-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Detecting support / extensible web? #171
Comments
Great to hear you're liking this! It is still behind an experimental flag/origin trial right now, but hopefully soon it will make it to unflagged-stable :). I'm a little unsure what you're asking, especially with the last paragraph. But I'll try to answer the question of how to set up a page that uses modules if modules + import maps are supported, or bundles if not. Here's what I've got off the top of my head: <script type="importmap">
{
"imports": {
"vue": "/vendor/vue.js"
}
}
</script>
<script nomodule src="./bundle.js"></script>
<script type="module" src="./index.js"></script>
<script>
import ("vue").catch(() => {
// We'll get here if we're in a browser that doesn't support import maps,
// because import "vue" will fail (with no evaluation performed). In that case
// the <script type=module> was also a no-op (mostly).
const s = document.createElement('script');
s.src = "./bundle.js";
document.body.append(s);
});
</script> This solution is a little sub-par, because in the case of browsers that support modules but not import maps, it will fetch (but not evaluate) your module graph up until it sees a bare specifier and fails. I see a couple ways to rejigger it, but they all move that kind of small delay around, instead of eliminating it. It's quite possible there's a solution if I think harder though... I'll think a bit harder about if there's something more elegant, and /cc @philipwalton and @hiroshige-g who might have better ideas for this particular case. If we were to add something for this case, one idea is to add the stub of an imperative API, e.g. an empty <script nomodule src="./bundle.js"></script>
<script type="module">
if (window.importMap) {
import("./index.js");
} else {
const s = document.createElement('script');
s.src = "./bundle.js";
document.body.append(s);
}
</script> |
One thing you can also do today is avoid using bare specifiers in your code, but instead use something like |
For some use cases, you can use Import Maps as their own feature detect. For example, you can build an app with two different entry points (e.g. <script type="importmap">
{
"imports": {
"./main-nomap.mjs": "./main-map.mjs"
}
}
</script> With this techinque, both But this only solves part of the problem. When loading modules (at least at the moment) you need to preload/modulepreload them in order to get good load performance, and there's not really a good way to conditionally preload modules based on whether you have Import Map support, so it's hard to see a strong adoption story until that's addressed (or I guess until most browsers support Import Maps). (Note: bundled exchanges would probably help address the modulepreload issue, but it'd also be nice to have something that works now. And of course then there'd be the issue of detecting bundled exchange support.) |
@philipwalton on that performance note, I've been pushing for some time for a generic web preload spec as discussed in systemjs/systemjs#1953. Exactly about dealing with this lazy / conditional graph preloading. |
Is it implied above that any browser that supports |
It is not; i believe only chrome has import maps support at this time. |
Did we add something for detecting import maps in the end? |
I'm also interested. How do we know if the browser supports import maps? |
Once I tried to write code to detect importmap support. <html>
<head></head>
<body>
<script>
//import-map feature detection
const supportsImportmap = async () => {
const specifier = jsToTextUrl(`export default false`)
const importMap = {
imports: {
[specifier]: jsToTextUrl(`export default true`),
},
}
const importmapScript = document.createElement("script")
importmapScript.type = "importmap"
importmapScript.textContent = JSON.stringify(importMap, null, " ")
document.body.appendChild(importmapScript)
const scriptModule = document.createElement("script")
scriptModule.type = "module"
scriptModule.src = jsToTextUrl(`import supported from "${specifier}"; window.__importmap_supported = supported`)
return new Promise((resolve, reject) => {
scriptModule.onload = () => {
const supported = window.__importmap_supported
delete window.__importmap_supported
resolve(supported)
}
scriptModule.onerror = () => {
reject()
}
document.body.appendChild(scriptModule)
})
}
const jsToTextUrl = (js) => {
return `data:text/javascript;base64,${window.btoa(js)}`
}
supportsImportmap().then((has) => {
console.log(has)
})
</script>
</body>
</html> Edit: Don't know in what scenario one could want to use this piece of code but there is maybe something to learn from it. |
Better than
So it doesn't work? |
I wanted to verify if remapping My test code const { parseFromString } = require("./parser.js");
const { resolve } = require("./resolver.js");
const from = `data:text/javascript,false`;
const to = `data:text/javascript,true`;
const importmapObject = {
imports: {
[from]: to,
},
};
const importmap = parseFromString(
JSON.stringify(importmapObject),
"file:///directory/"
);
console.log(resolve(from, importmap, "file:///directory/file.js").href); Link to reference implementation
Screenshot of the result So it should work. |
Running the code in #171 (comment) twice in Chromium Version 90.0.4421.0 logs the following error in the console: It means the code should be run before injecting any script type "module" in the page or it becomes non reliable (promise resolved to |
The script.supports() method will be introduced by whatwg/html#7008. script.supports('importmap') must return true when supported. Fixes WICG#171
The HTMLScriptElement.supports() method was introduced by whatwg/html#7008. HTMLScriptElement.supports('importmap') must return true when supported. Fixes WICG#171
The HTMLScriptElement.supports() method was introduced by whatwg/html#7008. HTMLScriptElement.supports('importmap') must return true when supported. Fixes WICG#171
The HTMLScriptElement.supports() method was introduced by whatwg/html#7008. This makes HTMLScriptElement.supports('importmap') return true. Fixes #171.
I've found that
importmap
has landed in Chrome stable (not sure exactly when or if it's an experimental flag that's turned on, but bear with me).This makes me very pleased that this code works seamlessly:
Where index.js is doing
import Vue from 'vue
and thenomodule
bundle is able to use webpack to bundle up Vue as required.Except as soon as I ran this in Firefox the code failed hard. Firefox has support for
type="module"
but knows nothing about import maps, so it failed to import Vue.I'm happy to target only browsers that have
type="module"
andtype="importmap"
as I have mynomodule
fallback support - but how?I can't see any way that I can state this code only works if
importmap
is supported. Is this included in the specification anywhere?The text was updated successfully, but these errors were encountered: