From be1b4e94204703a1e48ccbebb7839fa5e5675eda Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Tue, 22 Oct 2024 17:36:11 +0200 Subject: [PATCH] Fix `module_resolution: "nodenext"` with `mjs` or `cjs` (#71635) A regression from https://github.com/vercel/turborepo/pull/8748 Closes PACK-3312 Previously, it treated imports to `something.mjs` as importing `something.mts` with a fallback to `something.js`. But it should obviously instead fallback to the original extension `mjs`, which is also what tsc does: ``` Found 'package.json' at 'input/package.json'. ======== Resolving module './src/foo.mjs' from 'input/index.js'. ======== Explicitly specified module resolution kind: 'NodeNext'. Resolving in CJS mode with conditions 'require', 'types', 'node'. Loading module as file / folder, candidate module location 'input/src/foo.mjs', target file types: TypeScript, JavaScript, Declaration. File name 'input/src/foo.mjs' has a '.mjs' extension - stripping it. File 'input/src/foo.mts' does not exist. File 'input/src/foo.d.mts' does not exist. File 'input/src/foo.mjs' does not exist. File 'input/src/foo.mjs.ts' does not exist. File 'input/src/foo.mjs.tsx' does not exist. File 'input/src/foo.mjs.d.ts' does not exist. File 'input/src/foo.mjs.js' does not exist. File 'input/src/foo.mjs.jsx' does not exist. Directory 'input/src/foo.mjs' does not exist, skipping all lookups in it. ======== Module name './src/foo.mjs' was not resolved. ======== ``` --- .../crates/turbopack-core/src/resolve/mod.rs | 40 +++++++++---------- .../tsconfig-nodenext/input/index.js | 24 +++++++---- .../input/node_modules/foo/package.json | 6 +++ .../input/node_modules/foo/source.mjs | 1 + .../tsconfig-nodenext/input/src/bar.tsx | 1 - .../tsconfig-nodenext/input/src/file-cjs.cjs | 1 + .../tsconfig-nodenext/input/src/file-cts.cts | 1 + .../tsconfig-nodenext/input/src/file-mjs.mjs | 1 + .../tsconfig-nodenext/input/src/file-mts.mts | 1 + .../tsconfig-nodenext/input/src/file-tsx.tsx | 1 + .../tsconfig-nodenext/input/src/foo-cjs.cts | 1 - .../tsconfig-nodenext/input/src/foo-esm.mts | 1 - .../tsconfig-nodenext/input/src/foo.ts | 2 +- .../tsconfig-nodenext/input/tsconfig.json | 7 +++- 14 files changed, 55 insertions(+), 33 deletions(-) create mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/node_modules/foo/package.json create mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/node_modules/foo/source.mjs delete mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/bar.tsx create mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-cjs.cjs create mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-cts.cts create mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-mjs.mjs create mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-mts.mts create mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-tsx.tsx delete mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo-cjs.cts delete mode 100644 turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo-esm.mts diff --git a/turbopack/crates/turbopack-core/src/resolve/mod.rs b/turbopack/crates/turbopack-core/src/resolve/mod.rs index cc8dc030c0398..b41cc191bf722 100644 --- a/turbopack/crates/turbopack-core/src/resolve/mod.rs +++ b/turbopack/crates/turbopack-core/src/resolve/mod.rs @@ -2006,41 +2006,41 @@ async fn resolve_relative_request( if options_value.enable_typescript_with_output_extension { new_path.replace_final_constants(&|c: &RcStr| -> Option { - let result = match c.rsplit_once(".") { - Some((base, "js")) => Some(( + let (base, replacement) = match c.rsplit_once(".") { + Some((base, "js")) => ( base, vec![ Pattern::Constant(".ts".into()), Pattern::Constant(".tsx".into()), Pattern::Constant(".js".into()), ], - )), - Some((base, "mjs")) => Some(( + ), + Some((base, "mjs")) => ( base, vec![ Pattern::Constant(".mts".into()), - Pattern::Constant(".js".into()), + Pattern::Constant(".mjs".into()), ], - )), - Some((base, "cjs")) => Some(( + ), + Some((base, "cjs")) => ( base, vec![ Pattern::Constant(".cts".into()), - Pattern::Constant(".js".into()), + Pattern::Constant(".cjs".into()), ], - )), - _ => None, - }; - result.map(|(base, replacement)| { - if base.is_empty() { - Pattern::Alternatives(replacement) - } else { - Pattern::Concatenation(vec![ - Pattern::Constant(base.into()), - Pattern::Alternatives(replacement), - ]) + ), + _ => { + return None; } - }) + }; + if base.is_empty() { + Some(Pattern::Alternatives(replacement)) + } else { + Some(Pattern::Concatenation(vec![ + Pattern::Constant(base.into()), + Pattern::Alternatives(replacement), + ])) + } }); new_path.normalize(); } diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/index.js b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/index.js index 3a0b2a12345ec..6636fcf6cbec4 100644 --- a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/index.js +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/index.js @@ -1,11 +1,21 @@ import foo from "./src/foo.js"; -import bar from "./src/bar.js"; -import fooEsm from "./src/foo-esm.mjs"; -import fooCjs from "./src/foo-cjs.cjs"; +import fileTsx from "./src/file-tsx.js"; +import fileMts from "./src/file-mts.mjs"; +import fileCts from "./src/file-cts.cjs"; +import fileMjs from "./src/file-mjs.mjs"; +import fileCjs from "./src/file-cjs.cjs"; it("should correctly resolve explicit extensions with nodenext", () => { - expect(foo).toBe("foo"); - expect(bar).toBe("bar"); - expect(fooEsm).toBe("fooEsm"); - expect(fooCjs).toBe("fooCjs"); + expect(foo).toBe("foo.ts"); + expect(fileTsx).toBe("file-tsx"); + expect(fileMts).toBe("file-mts"); + expect(fileCts).toBe("file-cts"); + expect(fileMjs).toBe("file-mjs"); + expect(fileCjs).toBe("file-cjs"); }); + +// import fooButton from "foo/button"; + +// it("should correctly resolve explicit extensions with nodenext", () => { +// expect(fooButton).toBe("button"); +// }); diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/node_modules/foo/package.json b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/node_modules/foo/package.json new file mode 100644 index 0000000000000..f609932f3b2d9 --- /dev/null +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/node_modules/foo/package.json @@ -0,0 +1,6 @@ +{ + "name": "foo", + "exports": { + "./button": "./source.mjs" + } +} diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/node_modules/foo/source.mjs b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/node_modules/foo/source.mjs new file mode 100644 index 0000000000000..612b01ed8e189 --- /dev/null +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/node_modules/foo/source.mjs @@ -0,0 +1 @@ +export default 'button' diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/bar.tsx b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/bar.tsx deleted file mode 100644 index 801821e109c18..0000000000000 --- a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/bar.tsx +++ /dev/null @@ -1 +0,0 @@ -export default "bar"; diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-cjs.cjs b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-cjs.cjs new file mode 100644 index 0000000000000..d241fadd1bee4 --- /dev/null +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-cjs.cjs @@ -0,0 +1 @@ +module.exports = 'file-cjs' diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-cts.cts b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-cts.cts new file mode 100644 index 0000000000000..45d3fbf3725fd --- /dev/null +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-cts.cts @@ -0,0 +1 @@ +module.exports = "file-cts"; diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-mjs.mjs b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-mjs.mjs new file mode 100644 index 0000000000000..8dfea16d1a17f --- /dev/null +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-mjs.mjs @@ -0,0 +1 @@ +export default 'file-mjs' diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-mts.mts b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-mts.mts new file mode 100644 index 0000000000000..6905d39890509 --- /dev/null +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-mts.mts @@ -0,0 +1 @@ +export default "file-mts"; diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-tsx.tsx b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-tsx.tsx new file mode 100644 index 0000000000000..c6db7ff46cd8f --- /dev/null +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/file-tsx.tsx @@ -0,0 +1 @@ +export default "file-tsx"; diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo-cjs.cts b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo-cjs.cts deleted file mode 100644 index 122dbfc3ec216..0000000000000 --- a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo-cjs.cts +++ /dev/null @@ -1 +0,0 @@ -module.exports = "fooCjs"; diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo-esm.mts b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo-esm.mts deleted file mode 100644 index 4c5f085924c15..0000000000000 --- a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo-esm.mts +++ /dev/null @@ -1 +0,0 @@ -export default "fooEsm"; diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo.ts b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo.ts index 60c6c8d8b04f9..c2b4cfd1e7e62 100644 --- a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo.ts +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/src/foo.ts @@ -1 +1 @@ -export default "foo"; +export default "foo.ts"; diff --git a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/tsconfig.json b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/tsconfig.json index cb7f695badd8e..c08883eb2077b 100644 --- a/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/tsconfig.json +++ b/turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-nodenext/input/tsconfig.json @@ -1,6 +1,9 @@ { "compilerOptions": { "module": "NodeNext", - "moduleResolution": "NodeNext" - } + "moduleResolution": "NodeNext", + "allowJs": true, + "outDir": "dist" + }, + "include": ["index.js"], }