-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
loader: fix package resolution for edge case #41218
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
Changes from 2 commits
a149086
db7a12a
6f7d871
435dc9b
f9fe067
0bb04f2
a72ad73
05d7f87
16f422f
a4c3456
9a45c2b
8b741f0
01a3abc
fdf0d4d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -98,86 +98,172 @@ try { | |
| } | ||
| }; | ||
|
|
||
| // Create a dummy dual package | ||
| // | ||
| /** | ||
| * this creates following directory structure: | ||
| * | ||
| * ./node_modules: | ||
| * |-> my-dual-package | ||
| * |-> es | ||
| * |-> index.js | ||
| * |-> package.json [2] | ||
| * |-> lib | ||
| * |-> index.js | ||
| * |->package.json [1] | ||
| * | ||
| * [1] - main package.json of the package | ||
| * - it contains: | ||
| * - type: 'commonjs' | ||
| * - main: 'lib/mainfile.js' | ||
| * - conditional exports for 'require' (lib/index.js) and | ||
| * 'import' (es/index.js) | ||
| * [2] - package.json add-on for the import case | ||
| * - it only contains: | ||
| * - type: 'module' | ||
| * | ||
| * in case the package is consumed as an ESM by importing it: | ||
| * import * as my-package from 'my-dual-package' | ||
| * it will cause the resolve method to return: | ||
| * { | ||
| * url: '<base_path>/node_modules/my-dual-package/es/index.js', | ||
| * format: 'module' | ||
| * } | ||
| * | ||
| * following testcase ensures that resolve works correctly in this case | ||
| * returning the information as specified above. Source for 'url' value | ||
| * is [1], source for 'format' value is [2] | ||
| */ | ||
| function testDualPackageWithJsMainScriptAndModuleType() { | ||
| // Create a dummy dual package | ||
| // | ||
| /** | ||
| * this creates following directory structure: | ||
|
dygabo marked this conversation as resolved.
Outdated
|
||
| * | ||
| * ./node_modules: | ||
| * |-> my-dual-package | ||
| * |-> es | ||
| * |-> index.js | ||
| * |-> package.json [2] | ||
| * |-> lib | ||
| * |-> index.js | ||
| * |->package.json [1] | ||
| * | ||
| * [1] - main package.json of the package | ||
| * - it contains: | ||
| * - type: 'commonjs' | ||
| * - main: 'lib/mainfile.js' | ||
| * - conditional exports for 'require' (lib/index.js) and | ||
| * 'import' (es/index.js) | ||
| * [2] - package.json add-on for the import case | ||
| * - it only contains: | ||
| * - type: 'module' | ||
| * | ||
|
dygabo marked this conversation as resolved.
Outdated
|
||
| * in case the package is consumed as an ESM by importing it: | ||
|
dygabo marked this conversation as resolved.
Outdated
|
||
| * import * as my-package from 'my-dual-package' | ||
| * it will cause the resolve method to return: | ||
| * { | ||
| * url: '<base_path>/node_modules/my-dual-package/es/index.js', | ||
| * format: 'module' | ||
| * } | ||
| * | ||
| * following testcase ensures that resolve works correctly in this case | ||
| * returning the information as specified above. Source for 'url' value | ||
| * is [1], source for 'format' value is [2] | ||
| */ | ||
|
|
||
| const moduleName = 'my-dual-package'; | ||
|
|
||
| const mDir = rel(`node_modules/${moduleName}`); | ||
| const esSubDir = rel(`node_modules/${moduleName}/es`); | ||
| const cjsSubDir = rel(`node_modules/${moduleName}/lib`); | ||
| const pkg = rel(`node_modules/${moduleName}/package.json`); | ||
| const esmPkg = rel(`node_modules/${moduleName}/es/package.json`); | ||
| const esScript = rel(`node_modules/${moduleName}/es/index.js`); | ||
| const cjsScript = rel(`node_modules/${moduleName}/lib/index.js`); | ||
|
|
||
| createDir(nmDir); | ||
| createDir(mDir); | ||
| createDir(esSubDir); | ||
| createDir(cjsSubDir); | ||
|
|
||
| const mainPkgJsonContent = { | ||
| type: 'commonjs', | ||
| main: 'lib/index.js', | ||
| exports: { | ||
| '.': { | ||
| 'require': './lib/index.js', | ||
| 'import': './es/index.js' | ||
| }, | ||
| './package.json': './package.json', | ||
| } | ||
| }; | ||
| const esmPkgJsonContent = { | ||
| type: 'module' | ||
| }; | ||
| const moduleName = 'my-dual-package'; | ||
|
|
||
| fs.writeFileSync(pkg, JSON.stringify(mainPkgJsonContent)); | ||
| fs.writeFileSync(esmPkg, JSON.stringify(esmPkgJsonContent)); | ||
| fs.writeFileSync(esScript, | ||
| 'export function esm-resolve-tester() {return 42}'); | ||
| fs.writeFileSync(cjsScript, | ||
| `module.exports = { | ||
| esm-resolve-tester: () => {return 42}}` | ||
| ); | ||
| const mDir = rel(`node_modules/${moduleName}`); | ||
| const esSubDir = rel(`node_modules/${moduleName}/es`); | ||
| const cjsSubDir = rel(`node_modules/${moduleName}/lib`); | ||
| const pkg = rel(`node_modules/${moduleName}/package.json`); | ||
| const esmPkg = rel(`node_modules/${moduleName}/es/package.json`); | ||
| const esScript = rel(`node_modules/${moduleName}/es/index.js`); | ||
| const cjsScript = rel(`node_modules/${moduleName}/lib/index.js`); | ||
|
|
||
| createDir(nmDir); | ||
| createDir(mDir); | ||
| createDir(esSubDir); | ||
| createDir(cjsSubDir); | ||
|
|
||
| const mainPkgJsonContent = { | ||
| type: 'commonjs', | ||
| main: 'lib/index.js', | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I think node doesn't even consume
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the proposal would be to renounce at the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we remove
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, true. My comment was just a nit, so no change needed. If it were me, I would KISS and remove the unused bits, but maybe not worth the effort.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally, I would go with test scenarios as close to real world scenarios as possible (would mean having |
||
| exports: { | ||
| '.': { | ||
| 'require': './lib/index.js', | ||
| 'import': './es/index.js' | ||
| }, | ||
|
guybedford marked this conversation as resolved.
|
||
| './package.json': './package.json', | ||
| } | ||
| }; | ||
| const esmPkgJsonContent = { | ||
| type: 'module' | ||
| }; | ||
|
|
||
| fs.writeFileSync(pkg, JSON.stringify(mainPkgJsonContent)); | ||
| fs.writeFileSync(esmPkg, JSON.stringify(esmPkgJsonContent)); | ||
| fs.writeFileSync(esScript, | ||
| 'export function esm-resolve-tester() {return 42}'); | ||
| fs.writeFileSync(cjsScript, | ||
| `module.exports = { | ||
| esm-resolve-tester: () => {return 42}}` | ||
| ); | ||
|
dygabo marked this conversation as resolved.
|
||
|
|
||
| // test the resolve | ||
| const resolveResult = resolve(`${moduleName}`); | ||
| assert.strictEqual(resolveResult.format, 'module'); | ||
| assert.ok(resolveResult.url.includes('my-dual-package/es/index.js')); | ||
| } | ||
|
|
||
| function testDualPackageWithMjsMainScriptAndCJSType() { | ||
|
|
||
| // Additional test for following scenario | ||
| /** | ||
| * this creates following directory structure: | ||
| * | ||
| * ./node_modules: | ||
| * |-> dual-mjs-pjson | ||
| * |-> subdir | ||
| * |-> index.mjs [3] | ||
| * |-> package.json [2] | ||
| * |-> index.js | ||
| * |->package.json [1] | ||
| * | ||
| * [1] - main package.json of the package | ||
| * - it contains: | ||
| * - type: 'commonjs' | ||
| * - main: 'subdir/index.js' | ||
| * - conditional exports for 'require' (subdir/index.js) and | ||
| * 'import' (subdir/index.mjs) | ||
| * [2] - package.json add-on for the import case | ||
| * - it only contains: | ||
| * - type: 'commonjs' | ||
| * [3] - main script for the `import` case | ||
| * | ||
| * in case the package is consumed as an ESM by importing it: | ||
| * import * as my-package from 'dual-mjs-pjson' | ||
| * it will cause the resolve method to return: | ||
| * { | ||
| * url: '<base_path>/node_modules/dual-mjs-pjson/subdir/index.mjs', | ||
| * format: 'module' | ||
| * } | ||
| * | ||
| * following testcase ensures that resolve works correctly in this case | ||
| * returning the information as specified above. Source for 'url' value | ||
| * is [1], source for 'format' value is the file extension of [3] | ||
| */ | ||
| const moduleName = 'dual-mjs-pjson'; | ||
|
|
||
| const mDir = rel(`node_modules/${moduleName}`); | ||
| const subDir = rel(`node_modules/${moduleName}/subdir`); | ||
| const pkg = rel(`node_modules/${moduleName}/package.json`); | ||
| const subdirPkg = rel(`node_modules/${moduleName}/subdir/package.json`); | ||
| const esScript = rel(`node_modules/${moduleName}/subdir/index.mjs`); | ||
| const cjsScript = rel(`node_modules/${moduleName}/subdir/index.js`); | ||
|
|
||
| createDir(nmDir); | ||
| createDir(mDir); | ||
| createDir(subDir); | ||
|
|
||
| const mainPkgJsonContent = { | ||
| type: 'commonjs', | ||
| main: 'lib/index.js', | ||
| exports: { | ||
| '.': { | ||
| 'require': './subdir/index.js', | ||
| 'import': './subdir/index.mjs' | ||
| }, | ||
| './package.json': './package.json', | ||
| } | ||
| }; | ||
| const subdirPkgJsonContent = { | ||
| type: 'commonjs' | ||
| }; | ||
|
|
||
| fs.writeFileSync(pkg, JSON.stringify(mainPkgJsonContent)); | ||
| fs.writeFileSync(subdirPkg, JSON.stringify(subdirPkgJsonContent)); | ||
| fs.writeFileSync(esScript, | ||
| 'export function esm-resolve-tester() {return 42}'); | ||
| fs.writeFileSync(cjsScript, | ||
| `module.exports = { | ||
| esm-resolve-tester: () => {return 42}}` | ||
| ); | ||
|
dygabo marked this conversation as resolved.
|
||
|
|
||
| // test the resolve | ||
| const resolveResult = resolve(`${moduleName}`); | ||
| assert.strictEqual(resolveResult.format, 'module'); | ||
| assert.ok(resolveResult.url.includes(`${moduleName}/subdir/index.mjs`)); | ||
| } | ||
|
|
||
| testDualPackageWithJsMainScriptAndModuleType(); | ||
| testDualPackageWithMjsMainScriptAndCJSType(); | ||
|
|
||
| // test the resolve | ||
| const resolveResult = resolve(`${moduleName}`); | ||
| assert.strictEqual(resolveResult.format, 'module'); | ||
| assert.ok(resolveResult.url.includes('my-dual-package/es/index.js')); | ||
| } finally { | ||
| process.chdir(previousCwd); | ||
| fs.rmSync(nmDir, { recursive: true, force: true }); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.