Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cover multiple import maps #37739

Merged
merged 11 commits into from
Jan 28, 2025
126 changes: 121 additions & 5 deletions files/en-us/web/html/element/script/type/importmap/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,13 @@ For more information, see the [Importing modules using import maps](/en-US/docs/

The `src`, `async`, `nomodule`, `defer`, `crossorigin`, `integrity`, and `referrerpolicy` attributes must not be specified.

Only the first import map in the document with an inline definition is processed; any additional import maps and external import maps are ignored.

### Exceptions

- `TypeError`
- : The import map definition is not a JSON object, the `importmap` key is defined but its value is not a JSON object, or the `scopes` key is defined but its value is not a JSON object.

Browsers generate console warnings for other cases where the import map JSON does not conform to the [import map](#import_map_json_representation) schema.

An [`error` event](/en-US/docs/Web/API/HTMLElement/error_event) is fired at script elements with `type="importmap"` that are not processed.
This might occur, for example, if module loading has already started when an import map is processed, or if multiple import maps are defined in the page.

## Description

When importing a [JavaScript module](/en-US/docs/Web/JavaScript/Guide/Modules), both the [`import` statement](/en-US/docs/Web/JavaScript/Reference/Statements/import) and [`import()` operator](/en-US/docs/Web/JavaScript/Reference/Operators/import) have a "module specifier" that indicates the module to be imported.
Expand Down Expand Up @@ -169,6 +164,127 @@ For example, the map below defines integrity metadata for the `square.js` module
</script>
```

### Merging multiple import maps

Internally, browsers maintain a single global import map representation. When multiple import maps are included in a document, their contents are merged into the global import map when they are registered.

For example, consider the following two import maps:

```html
<script type="importmap">
{
"imports": {
"/app/": "./original-app/"
}
}
</script>
```

```html
<script type="importmap">
{
"imports": {
"/app/helper": "./helper/index.mjs"
},
"scopes": {
"/js": {
"/app/": "./js-app/"
}
}
}
</script>
```

These are equivalent to the following single import map:

```html
<script type="importmap">
{
"imports": {
"/app/": "./original-app/",
"/app/helper": "./helper/index.mjs"
},
"scopes": {
"/js": {
"/app/": "./js-app/"
}
}
}
</script>
```

Module specifiers in each registered map that were already resolved beforehand are dropped. Subsequent resolutions of these specifiers will provide the same results as their previous resolutions.

For example, if the module specifier `/app/helper.js` was already resolved, the following new import map:

```html
<script type="importmap">
{
"imports": {
"/app/helper.js": "./helper/index.mjs",
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>
```

Would be equivalent to:

```html
<script type="importmap">
{
"imports": {
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>
```

The `/app/helper.js` rule was ignored and not incorporated into the map.

Similarly, module specifiers in a registered map that were already mapped to URLs in the global map are dropped; their previous mapping prevails.

For example, the following two import maps:

```html
<script type="importmap">
{
"imports": {
"/app/helper": "./helper/index.mjs",
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>
```

```html
<script type="importmap">
{
"imports": {
"/app/helper": "./main/helper/index.mjs"
}
}
</script>
```

Are equivalent to the following single import map:

```html
<script type="importmap">
{
"imports": {
"/app/helper": "./helper/index.mjs",
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>
```

The `/app/helper/` rule was dropped from the second map.

> [!NOTE]
> In non-supporting browsers (check the [compatibility data](#browser_compatibility)), a [polyfill](https://github.com/guybedford/es-module-shims) can be used to avoid issues related to module resolution.

## Import map JSON representation

The following is a "formal" definition of the import map JSON representation.
Expand Down
3 changes: 1 addition & 2 deletions files/en-us/web/javascript/guide/modules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,7 @@ Relative URLs are resolved to absolute URL addresses using the [base URL](/en-US
```

The import map is defined using a [JSON object](/en-US/docs/Web/HTML/Element/script/type/importmap#import_map_json_representation) inside a `<script>` element with the `type` attribute set to [`importmap`](/en-US/docs/Web/HTML/Element/script/type/importmap).
There can only be one import map in the document, and because it is used to resolve which modules are loaded in both static and dynamic imports, it must be declared before any `<script>` elements that import modules.
Note that the import map only applies to the document — the specification does not cover how to apply an import map in a worker or worklet context. <!-- https://github.com/WICG/import-maps/issues/2 -->
Note that an import map only applies to the document — the specification does not cover how to apply an import map in a worker or worklet context. <!-- https://github.com/WICG/import-maps/issues/2 -->

With this map you can now use the property names above as module specifiers.
If there is no trailing forward slash on the module specifier key then the whole module specifier key is matched and substituted.
Expand Down