-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
--import
order is wrong when one of the modules imports a module
#50427
Comments
@nodejs/loaders |
It's probably because these imports are executed in order, but not in a forced sequence. |
The relevant code is here: node/lib/internal/process/esm_loader.js Lines 24 to 30 in 0a0b8df
So it’s essentially as if you had written a single import file with: import './a.mjs'
import './b.mjs' Instead of: await import('./a.mjs')
await import('./b.mjs') We could change the current behavior from the first option to the second, but I think it would be a breaking change. |
I did not find this by accident. I wrestled with figuring out why my loaders were loading in a different order than I specified with --import. This will people hard. Definitely goes against the principle of least surprise. I think this must be changed. |
It also differs from how |
In the static import case, b isn’t evaluated until all of a is finished, so it would be in serial i think? |
But we need it to emulate loader chaining without extra hacks & wrappers. @arcanis, what do you think about Yarn PnP and possible |
Definitely sounds to me like a bug, not a major change. It would be entirely reasonable for a user to expect that the imports happen in serial as they are serial to the app entrypoint, just not serial amongst each other. |
I didn't check yet but I'd also expect the |
Because // a.js
import { register } from 'node:module'
import typescript from 'typescript'
register('./hooks-a.js', import.meta.url)
typescript.doSomethingWithThis()
// b.js
import { register } from 'node:module'
register('./hooks-b.js', import.meta.url) When run via import './a.js'
import './b.js' The way ESM is specified, modules are evaluated from the leaves of the tree back up to the root. So the first code to get evaluated here is whatever is in Anyway I agree that this is surprising and that Node should evaluate |
Sure. Let's assume that yarn use
// ts-transpiler.mjs
import { register } from 'node:module';
register('cool-hooks'); // failed
// ts-transpiler.mjs
import { register } from 'node:module';
register('./local-hook.mjs');
// local-hook.mjs
const esbuild = await import('esbuild'); // random crashes
|
If it's made sequential, I'd expect the One thing to be careful about is that the resolution for |
I'm pretty sure it's not the case. I agree that we should consider this a bug and change it to evaluate in a sequence. |
There are three way of supporting several
It seems that only the latter would allow chaining of loaders, the tradeoff being that if one of the module has a long-running TLA task, work will start later on other |
Number 3 was what I was envisioning as well. It would also allow hooks registered in the first node --import ts-node/register --import my-script.ts app.ts @aduh95 are you already working on this? |
To clarify - (2) very much does permit chaining here since evaluation of each successive module will only happen after the previous has fully completed including with TLA support, with that benefit over (3) of continuing to parallelize the loading pipeline. |
It doesn't, because the modules will still get resolved in parallel, meaning that a loader registered in the first |
That is not what the reported bug is in this issue, the bug reported and replication provided only refer to the import ordering bug. I appreciate the loader chaining use case though in widening the fix to also support that case, in which case that seems a worthy justification for (3). |
Yes, I think the example I posted, where the second |
Can I take it? |
PR-URL: nodejs#50474 Fixes: nodejs#50427 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
PR-URL: nodejs#50474 Fixes: nodejs#50427 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Version
v20.9.0
Platform
Linux XXXXXXX 5.15.90.1-microsoft-standard-WSL2 #1 SMP Fri Jan 27 02:56:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Subsystem
module
What steps will reproduce the bug?
git clone https://github.com/giltayar/import-order-bug.git
The output here makes sense, as the order of execution of
a.js
andb.js
is firsta
thenb
a.js
and uncomment the first line (withimport './sub.mjs
). Note thatsub.mjs
is an empty file.Now run the same command again:
This doesn't make sense: the order of execution of the imports shouldn't change if one of the modules has an
import
and the other doesn't.How often does it reproduce? Is there a required condition?
Every time.
What is the expected behavior? Why is that the expected behavior?
The order of the execution of the modules in
--import
should not change based on whether they are importing another module or not.What do you see instead?
The order of the execution of the modules in
--import
changes based on whether they are importing another module or not.Additional information
This stumped me for 3 hours when modifying my ESM loaders talk for NodeConf EU and the new
register
didn't work with loader chaining. It took me 3 hours to figure out that the chaining didn't change, but the execution order in--import
does, and that it has nothing to do with loaders.The text was updated successfully, but these errors were encountered: