Skip to content

Instantly share code, notes, and snippets.

@mk-pmb
Created November 9, 2025 08:21
Show Gist options
  • Select an option

  • Save mk-pmb/c3d4ef29c120687c984f7ced05ea0957 to your computer and use it in GitHub Desktop.

Select an option

Save mk-pmb/c3d4ef29c120687c984f7ced05ea0957 to your computer and use it in GitHub Desktop.
/* For browsers that don't understand import statements, the
`preferDynamicImport` transform replaces them with dynamic import.
The pseudo-code transpiler rule below explains the strategy.
It's unrealistic to aim for that level of correctness with regexps,
and in this project, simplicity wins over perfect accuracy. (If you
want correctness, use babel.)
Nonetheless, it' still useful to have a clear concept of what the
theoretically ideal goal would be, to ensure a clear understanding
of tbe trade-offs we make.
* Example use case: You can feed the pseudo-code to an AI and let it
explain why we can simply transplant the `ObjectBindingPattern`
(destructuring expression, stored as "unpack") verbatim. (Always
fact-check AI though! DO NOT report any AI counter-examples as bug
unless you have verified them in node.js or Firefox!)
Caveats inherent in the strategy, i.e. that would be unavoidable even
with all the complexity of the rule below:
* Only available for AMD output, because the module factory needs to
await the loader's promise.
* Mixed import statements are out of project scope. Just avoid them.
* If your imported module does not have the exports you want, the original
code would fail immediately, but the transpiled code may silently import
undefined instead. Use a linter to verify your imports.
* If an imported module uses its exported identifiers in strange ways
(e.g. export a getter, or reassign the exported identifiers at runtime),
the imported thing may become outdated, because an destructuring
assignment is not a real name binding. Just avoid such unstable modules.
* Don't use computed property names in your `ObjectBindingPattern`.
*/
export default {
name: 'preferDynamicImport',
supportedOutputFormats: ['amd_iife_define'],
applicable: a => (
(a.inputSourceType === 'esmodule')
&& (a.outputScope === 'asyncModuleFactory')
),
match: m => [
m.state('inputSourceScope')['===']('toplevel'),
m.literalToken('import'),
m.tokenBorder(),
m.or([
m.identifier().storeAs('name'),
m.opportunisticLookahead().greedy().failAt(
m.endOfStatement(), // abort early if there was no "from"
).storeAs('unpack'),
]),
m.tokenBorder(),
m.literalToken('from'),
m.tokenBorder(),
m.stringLiteral().storeAs('url'),
m.endOfStatement(),
],
replace: r => [
r.verbatim('const '),
() => (r.stored('name') || r.stored('unpack')),
r.verbatim(' = await import('),
r.resolveUrl(r.stored('url')),
r.verbatim(')'),
() => (r.stored('name') && r.verbatim('.default')),
r.verbatim(';\n'),
],
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment