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.
45 lines
1.3 KiB
JSON
45 lines
1.3 KiB
JSON
{
|
|
"name": "@pnpm/exec.esm-node-path-loader",
|
|
"version": "1100.0.0",
|
|
"description": "Builds the NODE_OPTIONS flag that restores NODE_PATH resolution for ESM imports",
|
|
"keywords": [
|
|
"pnpm",
|
|
"pnpm11"
|
|
],
|
|
"license": "MIT",
|
|
"funding": "https://opencollective.com/pnpm",
|
|
"repository": "https://github.com/pnpm/pnpm/tree/main/pnpm11/exec/esm-node-path-loader",
|
|
"homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm11/exec/esm-node-path-loader#readme",
|
|
"bugs": {
|
|
"url": "https://github.com/pnpm/pnpm/issues"
|
|
},
|
|
"type": "module",
|
|
"main": "lib/index.js",
|
|
"types": "lib/index.d.ts",
|
|
"exports": {
|
|
".": "./lib/index.js"
|
|
},
|
|
"files": [
|
|
"lib",
|
|
"!*.map"
|
|
],
|
|
"scripts": {
|
|
"start": "tsgo --watch",
|
|
"test": "pn compile && pn .test",
|
|
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
"prepublishOnly": "tsgo --build",
|
|
"compile": "tsgo --build && pn lint --fix",
|
|
".test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest"
|
|
},
|
|
"devDependencies": {
|
|
"@jest/globals": "catalog:",
|
|
"@pnpm/exec.esm-node-path-loader": "workspace:*"
|
|
},
|
|
"engines": {
|
|
"node": ">=22.13"
|
|
},
|
|
"jest": {
|
|
"preset": "@pnpm/jest-config"
|
|
}
|
|
}
|