single-spa / import-map-overrides Goto Github PK
View Code? Open in Web Editor NEWA browser and NodeJS javascript library for overriding import maps
License: MIT License
A browser and NodeJS javascript library for overriding import maps
License: MIT License
Take the following importmap.json
file, with relative URL paths:
{
"imports": {
"single-spa": "/shared/single-spa.min.js",
"react": "/shared/react.development.js",
"react-dom": "/shared/react-dom.development.js"
}
}
hosted on a remote server at the URL:
http://tk-import-map-test.s3-website-eu-west-1.amazonaws.com/importmap.json
If one accesses the importmap.json
file inside the index.html
of a root-config
app, like this:
<script
type="systemjs-importmap"
src="http://tk-import-map-test.s3-website-eu-west-1.amazonaws.com/importmap.json"
></script>
When running the root-config
on localhost:9000
, the relative paths in the importmap.json
file are resolved relative to the position of the importmap.json
file, not the host (locahost:9000
).
Therefore, react
bundle will be downloaded from http://tk-import-map-test.s3-website-eu-west-1.amazonaws.com/shared/react.development.js
and not localhost:9000
as shown in the import-map-overrides
UI:
I am keen on working on a fix. I would welcome suggestions on which part of the code is the one relevant to this issue.
Hi!
I`m working on a project with angular and I faced a problem when trying to import angular dependencies.
My project is using angular v13 and when I set angular at systemjs-importmap it replaces the import with the last version (14) automatically.
Is there a way to disable it?
The logImportMap function would print the current import map to the console
Not much more to add: If I add <import-map-overrides-full trigger-position="top-left"></import-map-overrides-full>
to my page, the button still appears in the bottom right corner.
If you need any more details or a repro, let me know.
Different color and different label
You say multiple times in the documentation that its risky to use import-map-overrides in production (and to use it only during development). I'm putting together a browser-based IDE, and it seems like import-map-overrides is the only way to let users of the IDE link to external dependencies.
I understand that doing this opens up arbitrary code execution and self-xss attacks. But those are par for the course for an IDE anyway. (Wouldn't be much of an IDE if you couldn't run code in it after all. ;) )
I'm curious if this is the security (and probably performance) implications are the only reasons you say to not do this, or are there other reasons too? (And if it really is a bad idea to use import-map-overrides, is there any other way to create a dynamic import-map type of thing (or a lexically scoped import-map)).
Thanks.
Right now after a refresh I have to click the button in the right bottom corner to view the UI. I was wondering if there was a way to keep this open even after a refresh?
Also, should we be using the import-map-overrides
ui or the single-spa-inspector
chrome extension or both?
how can i create E2E cypress tests?
New overrides are only applied when you refresh the page. I think we could change the color of overrides that haven't been applied yet.
For many organizations, disabling import-map-overrides in production is a good idea, as it would not be good for users to stumble across it. To do so currently, they can modify their HTML file so as to not include the script tag in production. However, that can be a bit of a hassle and is not currently very common.
A nice approach might be to be able to disable all of import-map-overrides functionality via a <meta>
element in the HTML file that specifies which domains to safelist / blocklist
<meta name="import-map-overrides-domains" content="allowlist:dev.example.com,stage.example.com">
<meta name="import-map-overrides-domains" content="denylist:prod.example.com">
In the new version 3 I'm getting the following console error
Uncaught DOMException: Failed to execute 'attachShadow' on 'Element': Shadow root cannot be created on a host which already hosts a shadow tree.
at a.value (https://cdn.jsdelivr.net/npm/[email protected]/dist/import-map-overrides.js:2:45424)
at a.value (https://cdn.jsdelivr.net/npm/[email protected]/dist/import-map-overrides.js:2:45188)
This shows up when I am using single-spa-react
to render one react microfrontend on the page.
Is there a way to avoid that? @ralphsaunders maybe you have an idea? It's most likely related to #65
I have tried to override app url but it does reflect change until you refresh the page. can we update it without refreshing a page?
Step: 1 : update the url
Step 2: navigate between app
it will load the old url only
Step 3; refresh the page
it will now load the update url
Purpose : want to update url runtime whenever new version of app deployed on server
@angular/core
@angular/platform-browser
@angular/router
@angular/common
This would likely reduce the library size pretty drastically, and is also the norm now for react projects. At the time I authored this, react had released hooks but preact had not.
importMapOverrides.removeOverride('name')
When building import-map-overrides-server.js
we get the following warning:
src/import-map-overrides-server.js → dist/import-map-overrides-server.js...
babelHelpers: 'bundled' option was used by default. It is recommended to configure this option explicitly, read more here: https://github.com/rollup/plugins/tree/master/packages/babel#babelhelpers
(!) Unresolved dependencies
https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
cookie (imported by src/server/server-api.js)
We should make it possible to turn off the import-map-overrides trigger unless a local storage flag is set
This refresh icon is kinda confusing. It shows up only after you’ve changed an import map, which is also the exact time you’d want to refresh the page, which is generally what this icon means, but not here 😁
It could be helpful to have an actual icon that reloads the page. But it would mainly be helpful to change this icon to something different (e.g. ⚙️) or just remove it entirely.
I'm hitting a bug which is very hard to debug, since it only appears when rollup-plugin-terser is enabled. When running the minified JS, I get
Uncaught TypeError: (intermediate value).next is not a function
n import-map-overrides.js:2
c import-map-overrides.js:2
value import-map-overrides.js:2
le import-map-overrides.js:2
Z import-map-overrides.js:2
le import-map-overrides.js:2
pe import-map-overrides.js:2
value import-map-overrides.js:2
value import-map-overrides.js:2
However when running the JS built with build:dev
(or deleting the terser()
part of the webpack config) the import-map-overrides load just fine.
We're running into this when attempting to upgrade to React 18, and changing to use WMF rather than SystemJS for loading modules (SystemJS is still used for the import map).
// server.js
// ExpressJS middleware - used on each route that requests a document w/ import-map-overrides
const importMapOverridesMiddleware = (req, res, next) => {
const overrides = importMapOverrides.getOverridesFromCookies(req);
if (Object.keys(overrides).length === 0) {
app.locals.importMap = app.locals.originalImportMap;
} else {
app.locals.importMap = new Map([...app.locals.originalImportMap, ...Object.entries(overrides)]);
}
next();
};
"elephant": "https://ci.assets.avalara.com/one-web-domain/elephant/0.0.0%2b8a086bcf"
import-map-override:elephant
import-map-override:elephant:"https://ci.assets.avalara.com/one-web-domain/elephant/0.0.0%2b8a086bcf"
import-map-override:elephant
has been deletedpath=/
, one on path=/elephant
/elephant
I believe this line: https://github.com/joeldenning/import-map-overrides/blob/5faf9e7a6226f5328252ca6f1645dc089d4d36d5/src/api/js-api.js#L114
is causing a cross-origin error when accessing our single-spa app when hosted inside of Microsoft Teams:
If y'all confirm that this is behaving as expected, and that this appears to be the cause of this exception, then I'm happy to spin up a PR + tests. Just need a sign that I haven't got this completely mixed.
addOverride()
would set a cookie import-map-override:name=/some-url.js
, removeOverride()
would remove it. Local storage remains source of truth.
<meta importmap-type="server-handles-cookies">
(or similar) would block dynamic insertion of import maps, requiring the server to choose whether to respect the overrides sent up in the cookies.
When parsing an element like:
<script type="importmap"></script>
the parser will throw an error here.
Is this the expected behaviour? I would expect the page not be broken by such an element, but I am not sure. I checked the importmap specs and couldn't find anything definitive on this.
I've got some initialization code that depends on import map overrides being loaded. Is there a way to have my code run as soon as import map overrides are loaded, but not before? A Promise I can then
? I tried listening on import-map-overrides:change
and that doesn't seem to get triggered with the initial load. See the following:
let didInitialCheck = false;
function checkForFile() {
setTimeout(() => {
if (!didInitialCheck && typeof System !== "undefined") {
try {
console.log("initial", System.resolve("config-file"));
} catch (e) {
console.log("initial: not resolved");
}
didInitialCheck = true;
} else {
checkForFile();
}
}, 5);
}
checkForFile();
window.addEventListener(
"import-map-overrides:change",
() => { console.log("import-map-overrides:change"); console.log("change", System.resolve("config-file")); }
);
setTimeout(() => { console.log("timeout", System.resolve("config-file"))}, 1000);
One cool feature could be the ability to point to a remote URL for an override import map and then have import map overrides insert that map dynamically. The url (or urls) for override import maps would be stored in local storage under a new key (perhaps import-map-overrides-external-maps
or something
Hey,
I recently switched to vite and I'm trying to get my override to work with the default dev mode in vite, which is using native imports.
I'm using SystemJS for all my other microservices and I don't understand if it is even possible to be able to run both at the same time.
When I try to override my main.js from vite I get the following error:
Uncaught SyntaxError: Cannot use import statement outside a module (at main.js:1:1)
Is it somehow possible to have both, native imports and SystemJS running at the same time?
getDisabledOverrides (and probably other functions that use localStorage) is throwing an error
"Uncaught DOMException: Failed to read the 'localStorage' property from 'Window': Access is denied for this document."
in an iframe when running in incognito mode on chrome.
Would be handy to be able to toggle an override on or off just to switch back and forth instead of only reset to default.
Handy when you are testing local and server and testing deployments.
Hi,
It seems Safari blocks import maps that are pointing to non https MFE's, running in localhost.
The error is page at was not allowed to run insecure content from
This happens we have an https loading sources from non http.
Is there a known solution for this?
Not sure if this library is promising support for IE11, but I saw in the README description that it does.
This commit 6e0f50e#r52817708
Seems to have broken import-map-overrides
in IE11.
import maps to be over ride
<script type="overridable-importmap">
{
"imports": {
"imlib2": "http://localhost:3001/imlib2.js",
}
}
</script>
<script src="./src-import-map-overrides/dist/import-map-overrides.js"></script>
<script src="https://cdn.jsdelivr.net/npm/systemjs/dist/system.js"></script>
<script type="module" src="/test.js"></script>
test.js
import lib2 from "imlib2";
console.log("lib2 ======== native dev runner==========", lib2);
Error in the browser
js-api.js:455 An import map is added after module script load was triggered.
Uncaught TypeError: Failed to resolve module specifier "imlib2". Relative references must start with either "/", "./", or "../".
Implementation
As expected new import map block is added ie:
<script type="importmap">
{
"imports": {
"imlib2": "http://localhost:3001/imlib2.js",
}
}
</script>
Issue:
I am using the dynamic import maps plugin for SystemJS because I need to slightly modify the content of my importmap.json
file after it was downloaded. So my code looks somehow like this:
document.addEventListener('DOMContentLoaded', function () {
fetch('/importmap.json')
.then(function(response) {
response.json().then(function(importMap) {
for (var module in importMap) {
if (importMap.hasOwnProperty(module)) {
importMap[module] = changeUrl(importMap[module])
}
}
var importmapElem = document.createElement('script');
importmapElem.type = 'systemjs-importmap';
importmapElem.innerHTML = JSON.stringify(importMap, null, 2);
document.head.appendChild(importmapElem);
})
})
});
})
I also inserted the webcomponent import-map-overrides-full
so that I can modify the import map via the UI. Now, the problem is that no overrides have any effect. If I use a static script
block for the import map, everythings works as expected. Is there anything I can do to be compatible with the dynamic import maps plugin?
Since only one import map per page is supported in the most recent import maps spec, we should provide a way for import map overrides to work with only one import map.
See more info at https://github.com/WICG/import-maps/#dynamic-import-map-example
<script>
window.importMap = {imports: {foo: './foo1.js'}};
<script>
<script src="https://cdn.jsdelivr.net/npm/import-map-overrides/dist/import-map-overrides.js"></script>
With this proposed API, import map overrides would look for a global variable named importMap
, modify it with the overrides, and then inject it as <script type="importmap">
into the DOM.
This library probably should not be used in production, however it's not uncommon to sacrifice security for convenience. There's a good guidance on practices to avoid security issues if devs opt-in to use it in non-dev environments, but I think that having a GET parameter that allows injection of 3rd party scripts is too permissive and easy to exploit. I believe this behavior should be disabled by default, or at least there's should be an option to disable it.
I'd appreciate any thoughts on this and will be happy to help with the PR if this proposal sounds sensible.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.