Giter VIP home page Giter VIP logo

pkg-import-map's Introduction

Module Resolution & Format Lookup

Motivating Examples

  • A package (react-dom) has a dedicated entrypoint `react-dom/server for code that isn't compatible with a browser environment.
  • A package (angular) exposes multiple independent APIs, modeled via import paths like angular/common/http.
  • A package (lodash) allows to import individual functions, e.g. lodash/map.
  • A package is exclusively exposing an ESM interface.
  • A package is exclusively exposing a CJS interface.
  • A package is exposing both an ESM and a CJS interface.
  • A package wishes to publish .js files containing ESM code.
  • A project wants to mix both ESM and CJS code, with CJS running as part of the ESM module graph.

High Level Considerations

  • The baseline behavior of relative imports should match a browser's with a simple file server. This implies that ./x will only ever import exactly the sibling file "x" without appending paths or extensions.
  • The primary compatibility boundary are bare specifiers. Relative and absolute imports can follow simpler rules.

package.json Interface

We propose a field in package.json to specify an ESM location when importing bare specifiers. The key is TBD, the examples use "esm-import-map" as a placeholder. Neither the name nor the fact that it exists top-level is final.

The package.json interface will only be respected for bare specifiers. The existence of a package.json file is ignored otherwise. This implies that importing a directory using relative paths is not possible.

Single Mapping

For packages that only want to support import 'pkg-name', the key can be set to a specifier. The specifier will be resolved relative to the URL of package.json. It may only be an absolute URL or a relative path ("./[...]", "../[...]"). Bare specifiers are not allowed as values for the mapping. The import: URL scheme is also explicitly disallowed in the mapping.

{
  "name": "@user/name",
  "esm-import-map": "./dist/index.mjs"
}

Multiple Mappings

"Deep imports" are explicit and expressed as an object. When importing the package name directly, the default key will be used. The semantics of the mapped value are the same as for the single mapping.

{
  "name": "@user/name",
  "esm-import-map": {
    "default": "./dist/index.mjs",
    "foo": "./some/filename-here.mjs"
  }
}

For a consumer, this will mean the following, assuming the package.json file is located at file:///path/to/pkg/package.json and @user/name is mapped to that package:

// Loads file:///path/to/pkg/dist/index.mjs
import x from '@user/name';
// Does the same as:
import x from 'file:///path/to/pkg/dist/index.mjs';

// Loads file:///path/to/pkg/some/filename-here.mjs
import x from '@user/name/foo';
// Does the same as:
import x from 'file:///path/to/pkg/some/filename-here.mjs';

// Fails - no such mapping (trailing slash not allowed).
import x from '@user/name/';

// Fails - directories cannot be imported, package.json only considered for bare imports
import x from 'file:///path/to/pkg';
// Fails - directories cannot be imported, package.json only considered for bare imports
import x from 'file:///path/to/pkg/';
// Fails - directories cannot be imported (there is no index.* magic)
import x from 'file:///path/to/pkg/dist/';

// Fails - no such mapping.
import x from '@user/name/dist/index.mjs';

Extension #1: Format Hint for .js

For packages that support both ESM and CJS, the import map can be preferred on import while require would hit the existing main entrypoint. The fact that we have a strong signal for the preference of the module author, we can use the same signal to interpret a .js file as ESM if it is used in the import mapping.

So the following would work:

{
  // dist/index.js never hits the ESM content type logic and is interpreted as CJS by require.extensions:
  "main": "dist/index.js",
  // src/index.js is mapped to the ESM content type because it is loaded via the import map:
  "esm-import-map": "src/index.js"
}

This raises the question how something might appear in an import map but be CJS, e.g. because a library hasn't fully migrated. Also how subsequent imports from src/index.js would be interpreted.

Extension #2: Content Type Override for CJS

One possible way of making a purely .js-based package easier to write, is to flip defaults. The content type lookup used when importing a .js file from disk would treat it as a module. A custom lookup can be used to allow importing .js files and interpret them as CJS.

Example (strawman):

// In package.json or via a node command line flag:
{
  "esm-content-types": {
    // node --esm-content-type=./old-src/**/*.js:application/vnd.node.js
    "./old-src/**/*.js": "application/vnd.node.js"
  }
}

No matter how a file is loaded, these overrides will be applied when loading the resource from a URL matching this filter. Code that does not want through this mapping can use createRequireFunction.

Open Questions

Should there be a way to allow deep imports?

Possible solutions include:

  • It's always allowed and tried if an explicit mapping isn't found.
  • It's configured via a special key in the import map (e.g. "/": "./lib/").
  • It's configured via a dedicated flag ("esm-allow-deep-import": true).

Should explict /default be allowed?

import x from 'some-pkg';
// Does this work and do the same thing?
import x from 'some-pkg/default';

pkg-import-map's People

Contributors

jkrems avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.