With a global virtual store, package directories live outside the project, so Node's upward node_modules walk from their real paths never reaches the project's hoisted node_modules — undeclared (phantom) dependencies stop resolving, and Node ignores NODE_PATH entirely for ESM imports (Related to pnpm/pnpm#9618). When enableGlobalVirtualStore is on (and extendNodePath is not disabled), every child process pnpm spawns — run, exec, lifecycle scripts, dlx — now receives NODE_PATH pointing at the private hoist dir and the root node_modules, plus a NODE_OPTIONS --import flag that registers a resolve hook restoring NODE_PATH lookups for ESM, replacing the plugin-esm-node-path config dependency. The flag is a self-contained constant: the registration module and the hook are nested data: URLs, so no loader file has to exist on disk and the flag stays valid regardless of which project or pnpm version spawned the child. It prefers module.registerHooks() (in-thread, no DEP0205 deprecation warning) and falls back to module.register() on Node >=18.19 <22.15. Everything outside the RFC 3986 unreserved set is percent-encoded: encodeURIComponent alone leaves single quotes bare, and the NODE_OPTIONS tokenizer treats those as quote delimiters. Both stacks embed identical hook sources and each asserts its derived flag against the shared golden file pnpm11/exec/esm-node-path-loader/test/import-flag.txt, so they cannot drift apart silently. Where the nodeOptions setting overwrites NODE_OPTIONS (run, exec, recursive run, install lifecycle), the flag is re-applied. pacquet's dlx and global installs force GVS off for their self-contained trees and now strip the injected env from the caller's cloned config, so a tool never resolves phantoms from the invoking project's tree; the TypeScript dlx (GVS on by default) adds the flag and lets the bin shim supply NODE_PATH. This deliberately does not address the TypeScript-compiler side of pnpm/pnpm#13210: tsc, tsserver, and bundlers implement their own resolution and honor neither NODE_PATH nor Node loader hooks. That class remains packageExtensions / compat-DB territory.
1 line
4.0 KiB
Plaintext
1 line
4.0 KiB
Plaintext
--import=data:text/javascript,if%20%28process.env.NODE_PATH%29%20%7B%0A%20%20const%20%7B%20register%2C%20registerHooks%20%7D%20%3D%20await%20import%28%27node%3Amodule%27%29%0A%20%20const%20%7B%20delimiter%20%7D%20%3D%20await%20import%28%27node%3Apath%27%29%0A%20%20const%20%7B%20pathToFileURL%20%7D%20%3D%20await%20import%28%27node%3Aurl%27%29%0A%20%20if%20%28registerHooks%29%20%7B%0A%20%20%20%20const%20nodePaths%20%3D%20%28process.env.NODE_PATH%20%3F%3F%20%27%27%29.split%28delimiter%29.filter%28Boolean%29%0A%20%20%20%20const%20isBareSpecifier%20%3D%20%28specifier%29%20%3D%3E%20%21specifier.startsWith%28%27.%27%29%20%26%26%20%21specifier.startsWith%28%27%2F%27%29%20%26%26%20%21specifier.startsWith%28%27%23%27%29%20%26%26%20%21specifier.includes%28%27%3A%27%29%0A%20%20%20%20registerHooks%28%7B%0A%20%20%20%20%20%20resolve%20%28specifier%2C%20context%2C%20nextResolve%29%20%7B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20return%20nextResolve%28specifier%2C%20context%29%0A%20%20%20%20%20%20%20%20%7D%20catch%20%28originalError%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20if%20%28originalError%3F.code%20%21%3D%3D%20%27ERR_MODULE_NOT_FOUND%27%20%7C%7C%20%21isBareSpecifier%28specifier%29%29%20throw%20originalError%0A%20%20%20%20%20%20%20%20%20%20for%20%28const%20nodePath%20of%20nodePaths%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20nextResolve%28specifier%2C%20%7B%20...context%2C%20parentURL%3A%20pathToFileURL%28nodePath%20%2B%20%27%2Fx%27%29.href%20%7D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20%28fallbackError%29%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20%28fallbackError%3F.code%20%21%3D%3D%20%27ERR_MODULE_NOT_FOUND%27%29%20throw%20fallbackError%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20throw%20originalError%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%7D%29%0A%20%20%7D%20else%20if%20%28register%29%20%7B%0A%20%20%20%20register%28%22data%3Atext%2Fjavascript%2Cimport%2520%257B%2520delimiter%2520%257D%2520from%2520%2527node%253Apath%2527%250Aimport%2520%257B%2520pathToFileURL%2520%257D%2520from%2520%2527node%253Aurl%2527%250Aconst%2520nodePaths%2520%253D%2520%2528process.env.NODE_PATH%2520%253F%253F%2520%2527%2527%2529.split%2528delimiter%2529.filter%2528Boolean%2529%250Aconst%2520isBareSpecifier%2520%253D%2520%2528specifier%2529%2520%253D%253E%2520%2521specifier.startsWith%2528%2527.%2527%2529%2520%2526%2526%2520%2521specifier.startsWith%2528%2527%252F%2527%2529%2520%2526%2526%2520%2521specifier.startsWith%2528%2527%2523%2527%2529%2520%2526%2526%2520%2521specifier.includes%2528%2527%253A%2527%2529%250A%250Aexport%2520async%2520function%2520resolve%2520%2528specifier%252C%2520context%252C%2520nextResolve%2529%2520%257B%250A%2520%2520try%2520%257B%250A%2520%2520%2520%2520return%2520await%2520nextResolve%2528specifier%252C%2520context%2529%250A%2520%2520%257D%2520catch%2520%2528originalError%2529%2520%257B%250A%2520%2520%2520%2520if%2520%2528originalError%253F.code%2520%2521%253D%253D%2520%2527ERR_MODULE_NOT_FOUND%2527%2520%257C%257C%2520%2521isBareSpecifier%2528specifier%2529%2529%2520throw%2520originalError%250A%2520%2520%2520%2520for%2520%2528const%2520nodePath%2520of%2520nodePaths%2529%2520%257B%250A%2520%2520%2520%2520%2520%2520try%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520return%2520await%2520nextResolve%2528specifier%252C%2520%257B%2520...context%252C%2520parentURL%253A%2520pathToFileURL%2528nodePath%2520%252B%2520%2527%252Fx%2527%2529.href%2520%257D%2529%250A%2520%2520%2520%2520%2520%2520%257D%2520catch%2520%2528fallbackError%2529%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520if%2520%2528fallbackError%253F.code%2520%2521%253D%253D%2520%2527ERR_MODULE_NOT_FOUND%2527%2529%2520throw%2520fallbackError%250A%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520throw%2520originalError%250A%2520%2520%257D%250A%257D%250A%22%29%0A%20%20%7D%0A%7D%0A |