From 8eff1efe9267d74d39473bd5ac6e359e978b62ee Mon Sep 17 00:00:00 2001 From: Jan Martin Date: Wed, 26 Nov 2025 11:24:43 -0800 Subject: [PATCH 1/2] module: allow subpath imports that start with `#/` It's a common ecosystem pattern to map a source root directory to `@/` but it requires special tooling support. This turns `#/*` into a more realistic alternative for that pattern. --- doc/api/esm.md | 2 +- lib/internal/modules/esm/resolve.js | 3 +-- test/es-module/test-esm-imports.mjs | 6 ++++-- test/fixtures/es-modules/pkgimports/package.json | 1 + test/fixtures/es-modules/pkgimports/src/foo.js | 1 + 5 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 test/fixtures/es-modules/pkgimports/src/foo.js diff --git a/doc/api/esm.md b/doc/api/esm.md index 64e9c68289d01d..e019b3458c1759 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -1102,7 +1102,7 @@ Note: This function is directly invoked by the CommonJS resolution algorithm. Note: This function is directly invoked by the CommonJS resolution algorithm. > 1. Assert: _specifier_ begins with _"#"_. -> 2. If _specifier_ is exactly equal to _"#"_ or starts with _"#/"_, then +> 2. If _specifier_ is exactly equal to _"#"_, then > 1. Throw an _Invalid Module Specifier_ error. > 3. Let _packageURL_ be the result of **LOOKUP\_PACKAGE\_SCOPE**(_parentURL_). > 4. If _packageURL_ is not **null**, then diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js index c27ee4c6612c6a..a321744ab8263c 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -692,8 +692,7 @@ function patternKeyCompare(a, b) { * @returns {URL} The resolved import URL. */ function packageImportsResolve(name, base, conditions) { - if (name === '#' || StringPrototypeStartsWith(name, '#/') || - StringPrototypeEndsWith(name, '/')) { + if (name === '#' || StringPrototypeEndsWith(name, '/')) { const reason = 'is not a valid internal imports specifier name'; throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base)); } diff --git a/test/es-module/test-esm-imports.mjs b/test/es-module/test-esm-imports.mjs index 7d2f7a63773514..b9982e2d0a585b 100644 --- a/test/es-module/test-esm-imports.mjs +++ b/test/es-module/test-esm-imports.mjs @@ -15,6 +15,10 @@ const { requireImport, importImport } = importer; const internalImports = new Map([ // Base case ['#test', maybeWrapped({ default: 'test' })], + // Root wildcard import + ['#/foo', maybeWrapped({ default: 'foo' })], + // Explicit #/ mapping + ['#/initialslash', maybeWrapped({ default: 'test' })], // import / require conditions ['#branch', maybeWrapped({ default: isRequire ? 'requirebranch' : 'importbranch' })], // Subpath imports @@ -64,8 +68,6 @@ const { requireImport, importImport } = importer; ['#external/subpath/x%5Cy', 'must not include encoded "/" or "\\"'], // Target must have a name ['#', '#'], - // Initial slash target must have a leading name - ['#/initialslash', '#/initialslash'], // Percent-encoded target paths ['#encodedslash', 'must not include encoded "/" or "\\"'], ['#encodedbackslash', 'must not include encoded "/" or "\\"'], diff --git a/test/fixtures/es-modules/pkgimports/package.json b/test/fixtures/es-modules/pkgimports/package.json index dbbbcd1ab01ea1..82e57b11ce45cd 100644 --- a/test/fixtures/es-modules/pkgimports/package.json +++ b/test/fixtures/es-modules/pkgimports/package.json @@ -1,5 +1,6 @@ { "imports": { + "#/*": "./src/*.js", "#branch": { "import": "./importbranch.js", "require": "./requirebranch.js" diff --git a/test/fixtures/es-modules/pkgimports/src/foo.js b/test/fixtures/es-modules/pkgimports/src/foo.js new file mode 100644 index 00000000000000..2651774ae60543 --- /dev/null +++ b/test/fixtures/es-modules/pkgimports/src/foo.js @@ -0,0 +1 @@ +module.exports = 'foo'; From 9f4d8ecf18d10af1d1738173e02dd7c92f269a28 Mon Sep 17 00:00:00 2001 From: Jan Martin Date: Mon, 1 Dec 2025 13:23:43 -0800 Subject: [PATCH 2/2] fixup! module: allow subpath imports that start with `#/` --- doc/api/packages.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/api/packages.md b/doc/api/packages.md index a980d8d7aa3e59..6110d25be530a7 100644 --- a/doc/api/packages.md +++ b/doc/api/packages.md @@ -527,6 +527,10 @@ can be written: added: - v14.6.0 - v12.19.0 +changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/60864 + description: Allow subpath imports that start with `#/`. --> In addition to the [`"exports"`][] field, there is a package `"imports"` field