A plugin to resolve ECMAScript module bare/url import specifiers at build-time for browsers which don't support import-maps, mostly based on WICG's import-maps reference implementation.
This plugin plays a role of polyfill for browsers but is used at build-time rather than at run-time. If some day (maybe in 2023) all major browsers support import-maps then this plugin can be retired.
Contents:
npm install --save-dev rollup-plugin-import-maps
edit rollup.config.js, import and use the plugin
import { importMapsPlugin } from 'rollup-plugin-import-maps';
// import { readFileSync } from 'fs';
export default {
input: './src/index.js',
plugins: [
importMapsPlugin({
srcPath: './index.importmap',
// srcText: readFileSync('./index.importmap', { encoding: 'utf8' }),
// srcObject: JSON.parse(readFileSync('./index.importmap', { encoding: 'utf8' })),
}),
],
output: [
{
file: './dist/index.js',
format: 'es'
}
]
};
-
srcPath
:string optionalfile path to importmap
-
srcText
:string optionalplain text of importmap
-
srcObject
:Object optionalparsed object of importmap
Note: One of
srcObject
,srcText
,srcPath
should be specified, if multiple of them specified, then precedence order is: srcObject, srcText, srcPath. -
baseDir
: string defaultprocess.cwd()
baseDir to calculate scope paths in order to match scopes defined in importmap
-
transformingReport
:string defaultundefined
set a file path to save transforming report as a JSON file, will output to Console if value set to
"-"
-
noTransforming
:boolean defaultfalse
if value set to
true
, then the plugin will mark specifiers defined in importmap as external, and won't transform those specifiers. useful if you want to build for browsers which already support import-maps and "set external list" with importmap. -
exclude
:string|RegExp|Function defaultundefined
skip bare/url specifiers from resolving / transforming according to importmap.
e.g.
.json,.wasm,.css
,/\.(json|wasm|css)$/
,(source, importer)=> /\.(json|wasm|css)$/.test(source)
-
This plugin doesn't yet support transforming module specifiers defined in data url. example data url:
import {foo, bar} from "data:application/javascript;charset=utf-8,import%20%7Bdefault%20as%20foo%7D%20from%20'foo'%3B%0Aexport%20%7Bfoo%7D%3B%0Aexport%20%7Bdefault%20as%20bar%7D%20from%20'bar'%3B";
which can be decoded as
import {default as foo} from 'foo'; export {foo}; export {default as bar} from 'bar';
-
When tansforming specifiers in dynamic imports, only string literal can be transformed. example specifiers:
import('foo/locales/en/messages.js') // Yes import("foo/locales/en/messages.js") // Yes let lang = 'en'; import('foo/locales/'+lang+'/messages.js') // No let modulePath = 'foo/locales/en/messages.js' import(modulePath) // No import(`foo/locales/en/messages.js`) // No
importmap
{
"imports": {
"three": "/node_modules/three/build/three.module.js",
"three/": "/node_modules/three/",
"underscore": "data:application/javascript;charset=utf-8,export%20default%20window._%3B",
"~/": "//mysite.com/packages/myapp/"
}
}
input code
import * as THREE from 'three';
import GLTFLoader from 'three/examples/jsm/loaders/GLTFLoader.js';
import _ from 'underscore';
import '~/polyfills/navigator.userAgentData.js';
console.log(THREE, GLTFLoader, _);
output code
import * as THREE from '/node_modules/three/build/three.module.js';
import GLTFLoader from '/node_modules/three/examples/jsm/loaders/GLTFLoader.js';
import _ from 'data:application/javascript;charset=utf-8,export%20default%20window._%3B';
import '//mysite.com/packages/myapp/polyfills/navigator.userAgentData.js';
console.log(THREE, GLTFLoader, _);
importmap
{
"imports": {
"https://unpkg.com/[email protected]/build/three.module.js": "/node_modules/three/build/three.module.js",
"node-modules:/": "/node_modules/",
"data:application/javascript;charset=utf-8,export%20default%20window._%3B": "/underscore/underscore-esm-min.js",
"app-home:/": "//mysite.com/packages/myapp/"
}
}
input code
import * as THREE from 'https://unpkg.com/[email protected]/build/three.module.js';
import GLTFLoader from 'node-modules:/three/examples/jsm/loaders/GLTFLoader.js';
import _ from 'data:application/javascript;charset=utf-8,export%20default%20window._%3B';
import 'app-home:/polyfills/navigator.userAgentData.js';
console.log(THREE, GLTFLoader, _);
output code
import * as THREE from '/node_modules/three/build/three.module.js';
import GLTFLoader from '/node_modules/three/examples/jsm/loaders/GLTFLoader.js';
import _ from '/underscore/underscore-esm-min.js';
import '//mysite.com/packages/myapp/polyfills/navigator.userAgentData.js';
console.log(THREE, GLTFLoader, _);
You may use rollup to build two distributions, for browsers with or without import-maps support, and load corresponding distribution conditionally. e.g.
// rollup.config.js
export default [
{
input: './src/index.js',
plugins: [
importMapsPlugin({
srcPath: './index.importmap',
transformingReport: '-',
}),
],
output: [
{
file: './dist/index.js',
format: 'es'
}
]
},
{
input: './src/index.js',
plugins: [
importMapsPlugin({
srcPath: './index.importmap',
noTransforming: true,
}),
],
output: [
{
file: './dist/index-experimental.js',
format: 'es'
}
]
}
];
<script type="importmap">
put content of ./index.importmap here
</script>
<script type="module">
if (HTMLScriptElement.supports && HTMLScriptElement.supports('importmap')) {
console.log('Your browser supports import maps.');
import('/dist/index-experimental.js');
}else{
console.log('Your browser doesn\'t support import maps.');
import('/dist/index.js');
}
</script>
- import-maps - Reference implementation playground for import maps proposal
Other licenses of dependencies
- import-maps: W3C Software and Document License and W3C CLA