Open owowed opened 3 months ago
Since dynamic import has to follow CORS rules, here is an implementation to workaround that using GM_fetch/GM_xhr:
async function importShim<ModuleType>(url: string): Promise<ModuleType> {
const script = await GM_fetch(url).then(res => res.text()); // recommend @trim21/gm-fetch
const scriptBlob = new Blob([script], { type: "text/javascript" });
const importUrl = URL.createObjectURL(scriptBlob);
return import(importUrl);
}
Of course, this will only work if CSP allows dynamic import from blob URLs. Don't forget there is also GM_import
API that can bypass this, but only available in FireMonkey (and unfortunately, no other userscript manager supports it).
you can use GM_getText
instead of fetch
to load module text
but it is not supported that target module text import
another remote relative module
you can use GM_getText instead of fetch to load module text
I've never seen GM_getText
API before, and its not in the Violentmonkey or Tampermonkey docs. Could you perhaps provide link to the documentation?
but it is not supported that target module text import another remote relative module
The importShim
function doesn't import the remote module directly, it first fetches the remote module via GM_fetch
, and then import that using Blob
and URL.createObjectURL
. Because of that, importShim
imports from a blob URL that's coming from the same origin, which should run on the website without violating CORS.
sorry, it should be GM_getResourceText
but it is not supported that target module text import another remote relative module
if your target module is the following code
// it import another remote relative module
export * from './'
your importShim
will not work
You're right. The importShim
function is designed to import from external module, like CDNs (jsdelivr, unpkg, cdnjs etc.) Users can still choose to use the normal import
for normal relative imports.
The naming for importShim
is kind of confusing since shims are meant for polyfills. Sorry, I'll refer to them as importExternal
from now on 😅
Actually, we can create importShim
that can handle both of these cases, and support GM_getResourceText
:
async function importShim(url) {
// for importing external modules outside of its own origin or using GM_getResourceText
if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("gm-resource:")) {
let scriptText = url.startsWith("gm-resource:")
? await (GM_getResourceText || GM.getResourceText)(url.split(":")[1])
: await GM_fetch(url).then(res => res.text());
const scriptBlob = new Blob([scriptText], { type: "text/javascript" });
const importUrl = URL.createObjectURL(scriptBlob);
return import(importUrl);
}
return import(url);
}
GM_fetch
is still useful in case the user doesn't want to manually add resource entries.
I'd like support for building with packages that only provide ESM dist, one example is jsx-dom, which doesn't provide UMD/IIFE dist, but only providing ESM.
We can already use ESM dist in the userscript via dynamic import in async IIFE:
Maybe we can add a new
build.externalDynamicImports
configuration that'll automatically resolve ESM-only external modules to dynamic import:(Edited for more clarity)