A browser javascript library for being able to override import maps. This works with native browser import maps or with the SystemJS polyfill for import maps.
Import maps are a way of controlling which url to download javascript modules from. The import-map-overrides library allows you to dynamically change the url for javascript modules by storing overrides in local storage. This allows developers to override individual modules to point to their localhost during development of a module, without having to boot up a local environment with all the other modules and a backend server.
You should not use import-map-overrides as the only import map on your page, since you cannot count on everyone's local storage having valid values for all of your modules. Instead, import-map-overrides should be viewed as a developer experience enhancement and dev tool -- developers can develop and debug on deployed environments instead of having to boot up a local environment.
Here are some tutorial videos that explain this in more depth:
The import-map-overrides library is used via a global variable window.importMapOverrides
. The global variable exists because import-map-overrides needs
to be usable regardless of build config and without dependence on ESM modules, since
once you use ESM modules you can no longer modify the import map.
It is preferred to install import-map-overrides with a <script>
tag in your html file.
<!--
Make sure to put this BEFORE any <script type="module"> elements or any System.import() calls, but
AFTER all other import maps
-->
<script
type="text/javascript"
src="https://cdn.jsdelivr.net/npm/import-map-overrides/dist/import-map-overrides.js"
></script>
<!-- optionally include the UI for import map overrides -->
<import-map-overrides-full></import-map-overrides-full>
Alternatively, you can use it as an npm package:
npm install --save import-map-overrides
# Or
yarn add import-map-overrides
/*
Make sure this js file gets executed BEFORE any <script type="module"> elements or any System.import() calls,
but AFTER any other import maps that are on the page.
*/
import "import-map-overrides"; // this only will work if you compile the `import` down to an iife via webpack, rollup, parcel, etc
If you are using import-map-overrides for native import maps, no configuration is required.
However, if you're using SystemJS as a polyfill for import maps, you'll need to tell import-map-overrides to make a
<script type="systemjs-importmap">
element instead of <script type="importmap">
. To do this, you must add a <meta>
element to your html file before the import-map-overrides library is loaded.
<meta name="importmap-type" content="systemjs-importmap" />
The import-map-overrides library can override a server-rendered inline import map, an import map that is loaded via src=""
, or
any other import map. The key to making this work is to ensure that the import-map-overrides library is loaded after all other
import maps that are on the page, but before the first <script type="module">
or System.import()
.
import-map-overrides provides the following functions. Note that these functions are always put onto window.importMapOverrides, even if you installed it as an npm package.
Returns the override import map as an object. The returned object represents the overrides that will take effect the next time you reload the page, including any additions or removals you've recently made after the current page's acquiringImportMaps boolean was set to false.
const overrideMap = window.importMapOverrides.getOverrideMap();
console.log(overrideMap);
/*
{
"imports": {
"module1": "https://mycdn.com/module1.js",
"lodash": "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.core.js"
}
}
*/
Accepts a string moduleName
and a string url
as arguments. This will set up an override which takes effect
the next time you reload the page. Returns the new override import map.
Note that if you provide a port instead of a full url, that import-map-overrides will provide a default url to your localhost.
window.importMapOverrides.addOverride("react", "https://unpkg.com/react");
// Alternatively, provide a port number. Default url will be //localhost:8085/module1.js
window.importMapOverrides.addOverride("module1", "8085");
Accepts a string moduleName
as an argument. This will remove an override which takes effect the next time you
reload the page. Returns a boolean that indicates whether the override existed.
const wasRemoved = window.importMapOverrides.removeOverride("vue");
console.log(wasRemoved); // Either true or false
Removes all overrides from local storage, so that the next time the page is reloaded an override import map won't be created. Accepts no arguments and returns the reset override import map.
window.importMapOverrides.resetOverrides();
This API is used internally by import-map-overrides to create a full url when calling addOverride()
with just a
port number:
const defaultOverrideUrl = window.importMapOverrides.getUrlFromPort(
"module1",
"8085"
);
console.log(defaultOverrideUrl); // "//localhost:8085/module1.js"
The getUrlFromPort
function is exposed as an API to allow you to customize the logic yourself:
window.importMapOverrides.getUrlFromPort = (moduleName, port) =>
`http://127.0.0.1:${port}/${moduleName}.js`;
// Now whenever you call `addOverride()` with a port number, your custom logic will be called
window.importMapOverrides.addOverride("module1", "8085");
console.log(window.importMapOverrides.getOverrideMap().imports.module1); // "http://127.0.0.1:8085/module1.js"
This will force the full import map overrides UI to be displayed (as long as the code for it is loaded on the page).
It will set local storage to match the show-when-local-storage
key and/or it will append a <import-map-overrides-full>
element to the DOM.
The import-map-overrides library fires an event called import-map-overrides:change
on the window whenever the
override import map changes. The event is a CustomEvent
that has no detail property.
Example usage:
window.addEventListener("import-map-overrides:change", logImportMap);
// Later on you can remove the event listener
window.removeEventListener("import-map-overrides:change", logImportMap);
function logImportMap(evt) {
console.log(window.importMapOverrides.getOverrideMap());
}
The UI for import-map-overrides gives visual indication when any module is overridden, so that you know whether to blame your override or not when things are broken. It also lets you view and modify urls for all the modules in your import map.
You use the import-map-overrides UI via web components. This means you just need to put some HTML into the DOM in order for it to work. You have three options for the UI, depending on how much you want to customize the UI:
<!--
The full UI, including the "trigger" button that pops up the UI.
If you omit the show-when-local-storage attribute, the yellow/orange rectangle always shows.
When you have the show-when-local-storage attribute, the yellow/orange rectangle will only show
when the user has set a local storage value of "true" for the key specified.
For example, in the below example you must run the follow command in order to see the full-ui.
localStorage.setItem('overrides-ui', true);
The dev-libs attribute indicates that you prefer using development versions of third party libraries
like react when the import-map-overrides ui is active. The presence of that attribute turns on this feature.
For example, if you have `react` in your import map pointing to https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js
the dev-libs attribute will automatically override it to https://cdn.jsdelivr.net/npm/react/umd/react.development.js.
-->
<import-map-overrides-full
show-when-local-storage="overrides-ui"
dev-libs
></import-map-overrides-full>
<!-- Alternatively, just the black popup itself -->
<import-map-overrides-popup></import-map-overrides-popup>
<!-- Or if you only want the actual import map list and UI for overriding -->
<import-map-overrides-list></import-map-overrides-list>
The UI is completely optional. If you don't want to use it, simply don't include the <import-map-overrides-full>
custom element in your page. Additionally, you can use the
/dist/import-map-overrides-api.js
file
instead of /dist/import-map-overrides.js
,
which avoids downloading the code for the UI and reduces the library size.