WICG / import-maps

How to control the behavior of JavaScript imports
https://html.spec.whatwg.org/multipage/webappapis.html#import-maps
Other
2.66k stars 69 forks source link

Bundled modules using hash from archives / external import-maps #214

Closed radnan closed 4 years ago

radnan commented 4 years ago

Problem

Currently there is no native way to bundle modules in JavaScript. You can only import from single files thus making it necessary to use bundlers like webpack.

We should have a way to bundle modules either using a single zip/wbn file or from a directory - in both cases by referencing an external import map.

I realize bundling is not the primary concern for this repo - but the main idea here is relying on external import maps rather than the concept of bundling itself.

What does it look like?

We can use the fragment identifier to refer to modules from external import maps.

<!-- index.html -->
<script type="module">
import 'bundle#main';
</script>

This will resolve the bundle specifier and will do either of 2 things:

  1. If the specifier points to an .importmap file then it will attempt to resolve the main module described inside of that import map.
  2. If the specifier points to a .zip file then it will fetch the zip file, extract the contents, make sure the root contains a .importmap file, and attempt to resolve the main module described inside of that import map.
// .importmap
{
  "imports": {
    "main": "./main.js"
  }
}

How it will work for directories

<!-- index.html -->
<script type="importmap">
{
  "imports": {
    "bundle": "/bundle.importmap"
  }
}
</script>
<script type="module">
import 'bundle#main';
</script>

Directly referencing an import map can be the way to work during development mode.

How it will work for zips

For production we'd create a zip file containing our JS modules along with a .importmap file at the root with the import maps of all contained modules.

<!-- index.html -->
<script type="importmap">
{
  "imports": {
    "bundle": "/bundle.zip"
  }
}
</script>
<script type="module">
import 'bundle#main';
</script>
# bundle.zip
.
|-- .importmap
`-- main.js

Module resolution

For relative imports it will be relative to base URL of the .importmap file or within the zip file.

Resolution of bare imports will first do a lookup of the external import map and then fallback to its parent level import map and keep working up the tree.

So, for the following external import maps and main.js file:

// bundle.importmap
{
  "imports": {
    "main": "./main.js"
  }
}
// vendor.importmap
{
  "imports": {
    "lodash": "./node_modules/lodash.js"
  }
}
// main.js
import 'vendor#lodash';

used inside of this HTML:

<!-- index.html -->
<script type="importmap">
{
  "imports": {
    "bundle": "/bundle.importmap",
    "vendor": "/vendor.importmap"
  }
}
</script>
<script type="module">
import 'bundle#main';
</script>

The attempt to import vendor#lodash within main.js should result in importing the ./node_modules/lodash.js file that is described in 'vendor.importmap'.

Dynamic imports

Since we're just using regular import syntax and import maps - dynamic imports should work the same way for bundled modules.

Scoping/Remapping

Not sure if we should allow remapping imports from within scope of bundles on account of deeply nested import maps.

domenic commented 4 years ago

Thanks for your interest. I'm not interested in tracking this problem on this repository. I suggest you check out web bundles.