From 8505d307b8eabf5f20b0aecb2569c69bae3921be Mon Sep 17 00:00:00 2001 From: yuzheng14 <422450117@qq.com> Date: Mon, 18 May 2026 17:07:12 +0800 Subject: [PATCH] TURBOPACK: Fix subpath imports resolving to dependencies Allow package.json subpath imports targets to resolve as bare package specifiers instead of always forcing relative paths. Add a snapshot fixture that verifies an imports entry can point to a dependency in node_modules. --- .../crates/turbopack-core/src/resolve/mod.rs | 18 +++++++++++------- .../crates/turbopack-core/src/resolve/remap.rs | 2 +- .../imports/subpath-imports/input/index.js | 3 ++- .../input/node_modules/dep-in-nm/index.js | 1 + .../input/node_modules/dep-in-nm/package.json | 3 +++ .../imports/subpath-imports/input/package.json | 4 +++- ...subpath-imports_input_index_01i6qyk.js.map} | 0 ...rts_subpath-imports_input_index_01i6qyk.js} | 4 ++-- ...imports_subpath-imports_input_1p6gt_f._.js} | 17 ++++++++++++++--- ...rts_subpath-imports_input_1p6gt_f._.js.map} | 3 ++- 10 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/index.js create mode 100644 turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/package.json rename turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/{0_9x_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_1jr1_4n.js.map => 0_9x_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_01i6qyk.js.map} (100%) rename turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/{0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_1jr1_4n.js => 0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_01i6qyk.js} (78%) rename turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/{1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js => 1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js} (74%) rename turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/{1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js.map => 1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js.map} (69%) diff --git a/turbopack/crates/turbopack-core/src/resolve/mod.rs b/turbopack/crates/turbopack-core/src/resolve/mod.rs index 8ed91312cbfc..08dfc88fd179 100644 --- a/turbopack/crates/turbopack-core/src/resolve/mod.rs +++ b/turbopack/crates/turbopack-core/src/resolve/mod.rs @@ -47,7 +47,7 @@ use crate::{ parse::{Request, stringify_data_uri}, pattern::{Pattern, PatternMatch, read_matches}, plugin::{AfterResolvePlugin, AfterResolvePluginCondition, BeforeResolvePlugin}, - remap::{ExportsField, ImportsField, ReplacedSubpathValueResult}, + remap::{ExportImport, ExportsField, ImportsField, ReplacedSubpathValueResult}, }, source::{OptionSource, Source, Sources}, }; @@ -2950,6 +2950,7 @@ async fn resolve_into_package( conditions, unspecified_conditions, query, + ExportImport::Export, ) .await?, ); @@ -3229,6 +3230,7 @@ async fn handle_exports_imports_field( conditions: &BTreeMap, unspecified_conditions: &ConditionValue, query: RcStr, + kind: ExportImport, ) -> Result> { let mut results = Vec::new(); let mut conditions_state = FxHashMap::default(); @@ -3263,12 +3265,13 @@ async fn handle_exports_imports_field( } in results { if let Some(result_path) = result_path.with_normalized_path() { - let request = *Request::parse(Pattern::Concatenation(vec![ - Pattern::Constant(rcstr!("./")), - result_path.clone(), - ])) - .to_resolved() - .await?; + let request = + Pattern::Concatenation(vec![Pattern::Constant(rcstr!("./")), result_path.clone()]); + let request = match kind { + ExportImport::Export => request, + ExportImport::Import => Pattern::alternatives(vec![request, result_path.clone()]), + }; + let request = *Request::parse(request).to_resolved().await?; let resolve_result = Box::pin(resolve_internal_inline( package_path.clone(), @@ -3370,6 +3373,7 @@ async fn resolve_package_internal_with_imports_field( conditions, unspecified_conditions, RcStr::default(), + ExportImport::Import, ) .await } diff --git a/turbopack/crates/turbopack-core/src/resolve/remap.rs b/turbopack/crates/turbopack-core/src/resolve/remap.rs index 7d28032dd3fb..317f37199af6 100644 --- a/turbopack/crates/turbopack-core/src/resolve/remap.rs +++ b/turbopack/crates/turbopack-core/src/resolve/remap.rs @@ -16,7 +16,7 @@ use crate::resolve::{ /// A small helper type to differentiate parsing exports and imports fields. #[derive(Copy, Clone)] -enum ExportImport { +pub(crate) enum ExportImport { Export, Import, } diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/index.js b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/index.js index 6c71b6f4fc99..6605ceb49a2c 100644 --- a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/index.js +++ b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/index.js @@ -1,7 +1,8 @@ import foo from '#foo' import dep from '#dep' +import depInNm from '#dep-in-nm' import pattern from '#pattern/pat.js' import conditionalImport from '#conditional' const conditionalRequire = require('#conditional') -console.log(foo, dep, pattern, conditionalImport, conditionalRequire) +console.log(foo, dep, depInNm, pattern, conditionalImport, conditionalRequire) diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/index.js b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/index.js new file mode 100644 index 000000000000..504e794cf257 --- /dev/null +++ b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/index.js @@ -0,0 +1 @@ +export default 'dep-in-nm' diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/package.json b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/package.json new file mode 100644 index 000000000000..fc1409d0dc9f --- /dev/null +++ b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/package.json @@ -0,0 +1,3 @@ +{ + "name": "dep-in-nm" +} diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/package.json b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/package.json index 2790b239a509..926fa26ccb22 100644 --- a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/package.json +++ b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/package.json @@ -3,6 +3,7 @@ "imports": { "#foo": "./foo.js", "#dep": "dep", + "#dep-in-nm": "dep-in-nm", "#conditional": { "import": "./import.mjs", "require": "./require.cjs" @@ -10,6 +11,7 @@ "#pattern/*.js": "./*.js" }, "dependencies": { - "dep": "./dep" + "dep": "./dep", + "dep-in-nm": "dep-in-nm" } } diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0_9x_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_1jr1_4n.js.map b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0_9x_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_01i6qyk.js.map similarity index 100% rename from turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0_9x_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_1jr1_4n.js.map rename to turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0_9x_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_01i6qyk.js.map diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_1jr1_4n.js b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_01i6qyk.js similarity index 78% rename from turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_1jr1_4n.js rename to turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_01i6qyk.js index 7721b74569c3..1ce5833ba658 100644 --- a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_1jr1_4n.js +++ b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_01i6qyk.js @@ -1,5 +1,5 @@ (globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push([ - "output/0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_1jr1_4n.js", - {"otherChunks":["output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js"],"runtimeModuleIds":["[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/index.js [test] (ecmascript)"]} + "output/0rv8_turbopack-tests_tests_snapshot_imports_subpath-imports_input_index_01i6qyk.js", + {"otherChunks":["output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js"],"runtimeModuleIds":["[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/index.js [test] (ecmascript)"]} ]); // Dummy runtime \ No newline at end of file diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js similarity index 74% rename from turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js rename to turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js index efcac87838b3..eb8e044aec5b 100644 --- a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js +++ b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js @@ -1,4 +1,4 @@ -(globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push(["output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js", +(globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push(["output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js", "[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/foo.js [test] (ecmascript)", ((__turbopack_context__) => { "use strict"; @@ -45,15 +45,26 @@ module.exports = 'require'; __turbopack_context__.s([]); var __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$foo$2e$js__$5b$test$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/foo.js [test] (ecmascript)"); var __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$dep$2f$index$2e$js__$5b$test$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/dep/index.js [test] (ecmascript)"); +var __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$node_modules$2f$dep$2d$in$2d$nm$2f$index$2e$js__$5b$test$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/index.js [test] (ecmascript)"); var __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$pat$2e$js__$5b$test$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/pat.js [test] (ecmascript)"); var __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$import$2e$mjs__$5b$test$5d$__$28$ecmascript$29$__ = __turbopack_context__.i("[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/import.mjs [test] (ecmascript)"); ; ; ; ; +; const conditionalRequire = __turbopack_context__.r("[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/require.cjs [test] (ecmascript)"); -console.log(__TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$foo$2e$js__$5b$test$5d$__$28$ecmascript$29$__["default"], __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$dep$2f$index$2e$js__$5b$test$5d$__$28$ecmascript$29$__["default"], __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$pat$2e$js__$5b$test$5d$__$28$ecmascript$29$__["default"], __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$import$2e$mjs__$5b$test$5d$__$28$ecmascript$29$__["default"], conditionalRequire); +console.log(__TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$foo$2e$js__$5b$test$5d$__$28$ecmascript$29$__["default"], __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$dep$2f$index$2e$js__$5b$test$5d$__$28$ecmascript$29$__["default"], __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$node_modules$2f$dep$2d$in$2d$nm$2f$index$2e$js__$5b$test$5d$__$28$ecmascript$29$__["default"], __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$pat$2e$js__$5b$test$5d$__$28$ecmascript$29$__["default"], __TURBOPACK__imported__module__$5b$project$5d2f$turbopack$2f$crates$2f$turbopack$2d$tests$2f$tests$2f$snapshot$2f$imports$2f$subpath$2d$imports$2f$input$2f$import$2e$mjs__$5b$test$5d$__$28$ecmascript$29$__["default"], conditionalRequire); +}), +"[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/index.js [test] (ecmascript)", ((__turbopack_context__) => { +"use strict"; + +__turbopack_context__.s([ + "default", + ()=>__TURBOPACK__default__export__ +]); +const __TURBOPACK__default__export__ = 'dep-in-nm'; }), ]); -//# sourceMappingURL=1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js.map \ No newline at end of file +//# sourceMappingURL=1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js.map \ No newline at end of file diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js.map b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js.map similarity index 69% rename from turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js.map rename to turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js.map index b250641714f3..00e00445abd9 100644 --- a/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_14v1xaq._.js.map +++ b/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/output/1do3_crates_turbopack-tests_tests_snapshot_imports_subpath-imports_input_1p6gt_f._.js.map @@ -7,5 +7,6 @@ {"offset": {"line": 22, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/pat.js"],"sourcesContent":["export default 'pat'\n"],"names":[],"mappings":";;;;uCAAe"}}, {"offset": {"line": 31, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/import.mjs"],"sourcesContent":["export default 'import'\n"],"names":[],"mappings":";;;;uCAAe"}}, {"offset": {"line": 39, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/require.cjs"],"sourcesContent":["module.exports = 'require'\n"],"names":["module","exports"],"mappings":"AAAAA,OAAOC,OAAO,GAAG"}}, - {"offset": {"line": 44, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/index.js"],"sourcesContent":["import foo from '#foo'\nimport dep from '#dep'\nimport pattern from '#pattern/pat.js'\nimport conditionalImport from '#conditional'\nconst conditionalRequire = require('#conditional')\n\nconsole.log(foo, dep, pattern, conditionalImport, conditionalRequire)\n"],"names":["conditionalRequire","console","log"],"mappings":";AAAA;AACA;AACA;AACA;;;;;AACA,MAAMA;AAENC,QAAQC,GAAG,CAAC,oNAAG,EAAE,6NAAG,EAAE,oNAAO,EAAE,wNAAiB,EAAEF"}}] + {"offset": {"line": 44, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/index.js"],"sourcesContent":["import foo from '#foo'\nimport dep from '#dep'\nimport depInNm from '#dep-in-nm'\nimport pattern from '#pattern/pat.js'\nimport conditionalImport from '#conditional'\nconst conditionalRequire = require('#conditional')\n\nconsole.log(foo, dep, depInNm, pattern, conditionalImport, conditionalRequire)\n"],"names":["conditionalRequire","console","log"],"mappings":";AAAA;AACA;AACA;AACA;AACA;;;;;;AACA,MAAMA;AAENC,QAAQC,GAAG,CAAC,oNAAG,EAAE,6NAAG,EAAE,yPAAO,EAAE,oNAAO,EAAE,wNAAiB,EAAEF"}}, + {"offset": {"line": 61, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/turbopack/crates/turbopack-tests/tests/snapshot/imports/subpath-imports/input/node_modules/dep-in-nm/index.js"],"sourcesContent":["export default 'dep-in-nm'\n"],"names":[],"mappings":";;;;uCAAe","ignoreList":[0]}}] } \ No newline at end of file