How to load JS in the runtime, from a separate server? Browsers provide a native feature called HTML importmap. It is supported and works across all latest devices and browser versions.
importmap
HTML feature is useful because:
- it allows to load modules by our specified rules and create a declarative configuration in the HTML.
- This configuration cannot be overriden and serves as a source of truth to our modules resolution configuration defined in on place.
- allows different modules to be loaded from the different sources. It enables independent deployment. Because we can specify different modules to be loaded from the different urls.
- when all JavaScript modules are loaded to the same main thread, conflicts can appear. this means, that for some imports we need to have one library resolved, for example
react
andreact-dom
. - when we are referencing the same libraries from different modules, we may want to specify different urls to resolve these libraries. For example billing is using
lodash@13
and customer is usinglodash@14
. These versions are not compatible. To load each version for each module we can usescopes
feature in theimportmap
.
What is an "importmap"?
Importmap is a JSON declaration of imports and actual paths to be replaced in the JavaScript. We can declare an importmap as follows:
<script type=importmap> { "imports": { "circle": "https://example.com/modules/circle.js", } } </script>
With this declaration we can use import
expression in our javascript just referencing circle
as:
import circle from 'circle'
What are the rules using importmap?
<script type='importmap'>
must be defined before other scripts. This is the quote from a HTML spec
Import maps are currently disallowed once any module loading has started, or once a single import map is loaded. These restrictions might be lifted in future specification revisions.
- no other properties cannot be specified in this script tag.
src
property cannot be specified also. - importmap impact only
import
andimport()
expressions in the JavaScript - import map cannot be dinamically modified. Once it is loaded to the browser, it cannot be reloaded in the runtime.
Scopes
Scopes feature allows to resolve different modules depending on the current module, from which the import is resolved. The scoping is achieved by specifying the "scopes" object in the import map, where each key is a scope URL, and its value is an object of import mappings that apply to that scope.
Consider this configuration of imports and scopes:
{ "imports": { "a": "/a-1.mjs", "b": "/b-1.mjs", "c": "/c-1.mjs" }, "scopes": { "/scope2/": { "a": "/a-2.mjs" }, "/scope2/scope3/": { "b": "/b-3.mjs" } } }
results in the resolutions of modules:
"a" "b" "c" /scope1/r.mjs /a-1.mjs /b-1.mjs /c-1.mjs /scope2/r.mjs /a-2.mjs /b-1.mjs /c-1.mjs /scope2/scope3/r.mjs /a-2.mjs /b-3.mjs /c-1.mjs