Repository navigation
Possible loader chaining problem / possible yarn problem #48515
Description
Activity
I think that's a known limitation, static imports will use only the previous loaders, dynamic imports will use whatever loaders are available at the time of the import. Calling
import()inside a hook will create infinite recursion and should be avoided.- addedesmIssues and PRs related to the ECMAScript Modules implementation.Issues and PRs related to the ECMAScript Modules implementation.loadersIssues and PRs related to ES module loaders.Issues and PRs related to ES module loaders.
on Jun 22, 2023 Interesting 🤔 I'd love to learn a bit more. Would it be possible to point out the area in the code that is responsible for this behaviour? My mental model is currently something like this:
const loaderStack = []; const import = async (file) => { let resolved = null; for (loader of loaderStack) { // if this calls import() we have a loop // UNLESS `loaderStack` is somehow twiddled with each time resolved = await loader.resolve(); if (resolved.shortCircuit) { break; } } let result = {source: await fs.loadFile(resolved) }; for (loader of loaderStack) { // if this calls import() we have a loop // UNLESS `loaderStack` is somehow twiddled with each time result = await loader.load(result); if (resolved.shortCircuit) { break; } } return result; } const addLoader = (file) => { loaderStack.push(await import(file)); }
node/lib/internal/modules/esm/utils.js
Lines 152 to 163 in a40a6c8
for (let i = 0; i < customLoaderURLs.length; i++) { const customLoaderURL = customLoaderURLs[i]; // Importation must be handled by internal loader to avoid polluting user-land const keyedExports = await privateModuleLoader.import( customLoaderURL, parentURL, kEmptyObject, ); hooks.addCustomLoader(customLoaderURL, keyedExports); } The mental model you presented does not correspond to the loader API (the
nexthook is available as an argument, and the order is different), but I'd say it's good enough to understand what's happening: once the loader module is loaded, a dynamic import would be loaded by a loaderStack that has grown since the static imports have been loaded.Ah excellent thanks @aduh95 😄 I'll have a look in that file!
@aduh95 thanks for pointing me in the right direction 😄 I'm not sure if this approach is sensible or not but I have a working patch now that solves the problem: #48559 Running it against https://github.com/izaakschroeder/loader-chain-issue now produces correct output!
NODE=/PATH/TO/nodejs/node/out/Release/node "${NODE}" \ --require ../../.pnp.cjs \ --loader ../../.pnp.loader.mjs \ --loader banana-loader \ ./demo.bananaOutputs:
Hello world10 remaining items
- added 2 commits that reference this issue
on Aug 14, 2023 - added a commit that references this issue
on Aug 14, 2023 - added a commit that references this issue
on Aug 15, 2023 - added a commit that references this issue
on Nov 11, 2023 - added a commit that references this issue
on Nov 23, 2023 - added a commit that references this issue
on Feb 18, 2024 - added 2 commits that reference this issue
on Apr 25, 2024
Version
v20.3.1
Platform
Darwin Kernel Version 22.5.0: Mon Apr 24 20:52:24 PDT 2023; root:xnu-8796.121.2~5/RELEASE_ARM64_T6000 arm64
Subsystem
esm, loaders
What steps will reproduce the bug?
corepack enableyarn set version berryyarn set version 4loadhookawait import(someFile);someFileimport a package that requires another loader to resolveReproducible repo: https://github.com/izaakschroeder/loader-chain-issue
Run the following:
yarn cd packages/demo yarn demo/packages/banana-loader/loader.mjs:
/packages/demo/banana.config.mjs:
/packages/demo/test.banana:
/packages/banana-config/config.mjs:
How often does it reproduce? Is there a required condition?
No response
What is the expected behavior? Why is that the expected behavior?
Using
await import(...)should respect the existing loader chain.What do you see instead?
Module resolution fails inside an
import'd module.Additional information
No response