Skip to content

Commit 5da6c87

Browse files
committed
fix: should re-export real exportInfo when export dynamic js
1 parent 274a1bd commit 5da6c87

File tree

7 files changed

+178
-34
lines changed

7 files changed

+178
-34
lines changed

crates/rspack_plugin_esm_library/src/chunk_link.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub struct ExternalInterop {
7070
pub from_module: IdentifierSet,
7171
pub required_symbol: Option<Atom>,
7272
pub default_access: Option<Atom>,
73+
pub default_exported: Option<Atom>,
7374
pub namespace_object: Option<Atom>,
7475
pub namespace_object2: Option<Atom>,
7576
pub property_access: FxIndexMap<Atom, Atom>,
@@ -152,6 +153,24 @@ impl ExternalInterop {
152153
}
153154
}
154155

156+
pub fn default_exported(&mut self, used_names: &mut FxHashSet<Atom>) -> Atom {
157+
if self.required_symbol.is_none() {
158+
let new_name = find_new_name("", used_names, &vec![]);
159+
used_names.insert(new_name.clone());
160+
self.required_symbol = Some(new_name);
161+
}
162+
163+
if let Some(default_exported) = &self.default_exported {
164+
return default_exported.clone();
165+
}
166+
167+
let default_access_symbol = self.default_access(used_names);
168+
let default_exported_symbol = find_new_name(&default_access_symbol, used_names, &vec![]);
169+
used_names.insert(default_exported_symbol.clone());
170+
self.default_exported = Some(default_exported_symbol.clone());
171+
default_exported_symbol
172+
}
173+
155174
pub fn property_access(&mut self, atom: &Atom, used_names: &mut FxHashSet<Atom>) -> Atom {
156175
self.property_access.get(atom).cloned().unwrap_or_else(|| {
157176
let local_name = find_new_name(atom, used_names, &vec![]);
@@ -207,6 +226,13 @@ impl ExternalInterop {
207226
RuntimeGlobals::COMPAT_GET_DEFAULT_EXPORT,
208227
name
209228
)));
229+
230+
if let Some(default_exported_symbol) = &self.default_exported {
231+
source.add(RawStringSource::from(format!(
232+
"var {} = {}();\n",
233+
default_exported_symbol, default_access
234+
)));
235+
}
210236
}
211237

212238
for (s, local) in &self.property_access {

crates/rspack_plugin_esm_library/src/link.rs

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,7 @@ impl EsmLibraryPlugin {
871871
from_module: Default::default(),
872872
required_symbol: None,
873873
default_access: None,
874+
default_exported: None,
874875
namespace_object: None,
875876
namespace_object2: None,
876877
property_access: Default::default(),
@@ -905,7 +906,7 @@ impl EsmLibraryPlugin {
905906
current: ModuleIdentifier,
906907
current_chunk: ChunkUkey,
907908
compilation: &Compilation,
908-
concate_modules_map: &IdentifierIndexMap<ModuleInfo>,
909+
concate_modules_map: &mut IdentifierIndexMap<ModuleInfo>,
909910
required: &mut IdentifierIndexMap<ExternalInterop>,
910911
link: &mut UkeyMap<ChunkUkey, ChunkLinkContext>,
911912
module_graph: &ModuleGraph,
@@ -1002,14 +1003,17 @@ impl EsmLibraryPlugin {
10021003
required,
10031004
);
10041005
let ref_chunk = Self::get_module_chunk(ref_module, compilation);
1005-
1006-
let default_access_symbol = interop_info.default_access(&mut chunk_link.used_names);
1006+
let info = concate_modules_map
1007+
.get_mut(&ref_module)
1008+
.expect("should have info");
1009+
info.set_interop_default_access_used(true);
1010+
let default_exported = interop_info.default_exported(&mut chunk_link.used_names);
10071011
// ensure we import this chunk
10081012
entry_imports.entry(ref_module).or_default();
10091013

10101014
let exported = Self::add_chunk_export(
10111015
ref_chunk,
1012-
default_access_symbol,
1016+
default_exported.clone(),
10131017
mode.name.clone(),
10141018
exports,
10151019
ref_chunk == current_chunk,
@@ -1029,10 +1033,11 @@ impl EsmLibraryPlugin {
10291033
rspack_core::ExportMode::ReexportNamedDefault(mode) => {
10301034
// export { default as n } from './foo.cjs'
10311035
let ref_info = concate_modules_map
1032-
.get(&ref_module)
1036+
.get_mut(&ref_module)
10331037
.expect("should have info");
10341038
match ref_info {
10351039
ModuleInfo::External(ref_info) => {
1040+
ref_info.interop_default_access_used = true;
10361041
// var foo_default = /*#__PURE__*/ __webpack_require__.n(m3);
10371042
let interop_info = Self::add_require(
10381043
ref_module,
@@ -1042,14 +1047,15 @@ impl EsmLibraryPlugin {
10421047
required,
10431048
);
10441049

1045-
let default_access_symbol = interop_info.default_access(&mut chunk_link.used_names);
1050+
let default_exported_symbol =
1051+
interop_info.default_exported(&mut chunk_link.used_names);
10461052

10471053
// ensure we import this chunk
10481054
entry_imports.entry(ref_module).or_default();
10491055

10501056
Self::add_chunk_export(
10511057
current_chunk,
1052-
default_access_symbol,
1058+
default_exported_symbol,
10531059
mode.name.clone(),
10541060
exports,
10551061
true,
@@ -1136,8 +1142,6 @@ impl EsmLibraryPlugin {
11361142
);
11371143
}
11381144
rspack_core::ExportMode::NormalReexport(mode) => {
1139-
let exports_info = module_graph.get_exports_info(&ref_module);
1140-
11411145
for item in &mode.items {
11421146
// reset ref_module for each dep
11431147
let mut ref_module = orig_ref_module;
@@ -1156,13 +1160,7 @@ impl EsmLibraryPlugin {
11561160
}
11571161

11581162
let chunk_link = link.get_mut(&current_chunk).expect("should have link");
1159-
1160-
let mut export_info = item
1161-
.ids
1162-
.first()
1163-
.and_then(|id| exports_info.as_data(module_graph).named_exports(id))
1164-
.unwrap_or(item.export_info.as_data(module_graph));
1165-
1163+
let export_info = item.export_info.as_data(module_graph);
11661164
if export_info.is_reexport() {
11671165
// should point to the real export
11681166
let targets = export_info.get_max_target();
@@ -1178,18 +1176,17 @@ impl EsmLibraryPlugin {
11781176
continue;
11791177
};
11801178
ref_module = *module;
1181-
1182-
let exports_info = module_graph.get_exports_info(module).as_data(module_graph);
1183-
if let Some(target) =
1184-
exports_info.named_exports(item.ids.first().unwrap_or(&item.name))
1185-
{
1186-
export_info = target;
1187-
}
11881179
}
11891180

1190-
let Some(used_name) = export_info.get_used_name(None, None) else {
1191-
continue;
1192-
};
1181+
let exports_info = module_graph
1182+
.get_prefetched_exports_info(&ref_module, PrefetchExportsInfoMode::Default);
1183+
let export_info =
1184+
exports_info.get_read_only_export_info(item.ids.first().unwrap_or(&item.name));
1185+
1186+
let used_name = export_info.get_used_name(None, None).unwrap_or_else(|| {
1187+
// dynamic export
1188+
UsedNameItem::Str(item.name.clone())
1189+
});
11931190

11941191
if let UsedNameItem::Inlined(inlined) = used_name {
11951192
let new_name = find_new_name(&item.name, &chunk_link.used_names, &vec![]);
@@ -1882,9 +1879,9 @@ impl EsmLibraryPlugin {
18821879
ExportsType::Dynamic => match export_name.first().map(|atom| atom.as_str()) {
18831880
Some("default") => {
18841881
// shadowing the previous immutable ref to avoid violating rustc borrow rules
1882+
info.set_interop_default_access_used(true);
18851883
let symbol = match info {
18861884
ModuleInfo::External(info) => {
1887-
info.interop_default_access_used = true;
18881885
let required_info = Self::add_require(
18891886
*info_id,
18901887
from,
@@ -1894,13 +1891,10 @@ impl EsmLibraryPlugin {
18941891
);
18951892
required_info.default_access(all_used_names)
18961893
}
1897-
ModuleInfo::Concatenated(info) => {
1898-
info.interop_default_access_used = true;
1899-
info
1900-
.interop_default_access_name
1901-
.clone()
1902-
.expect("should already set interop namespace")
1903-
}
1894+
ModuleInfo::Concatenated(info) => info
1895+
.interop_default_access_name
1896+
.clone()
1897+
.expect("should already set interop namespace"),
19041898
};
19051899

19061900
export_name = export_name[1..].to_vec();
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
```mjs title=main.mjs
2+
import { __webpack_require__ } from "./runtime.mjs";
3+
4+
__webpack_require__.add({
5+
"./cjs-unknown.cjs":
6+
/*!*************************!*\
7+
!*** ./cjs-unknown.cjs ***!
8+
\*************************/
9+
(function (__unused_webpack_module, exports) {
10+
const exportSymbol = () => 'bar'
11+
12+
exports[exportSymbol()] = () => 'bar'
13+
14+
}),
15+
"./cjs.cjs":
16+
/*!*****************!*\
17+
!*** ./cjs.cjs ***!
18+
\*****************/
19+
(function (__unused_webpack_module, exports) {
20+
exports.foo = () => 'foo'
21+
22+
23+
}),
24+
});
25+
// ./index.js
26+
const cjs = __webpack_require__("./cjs.cjs");
27+
var foo_1 = cjs.foo;
28+
const cjs_unknown = __webpack_require__("./cjs-unknown.cjs");
29+
var cjs_unknown_default = /*#__PURE__*/__webpack_require__.n(cjs_unknown);
30+
var cjs_unknown_default_0 = cjs_unknown_default();
31+
var bar_1 = cjs_unknown.bar;
32+
33+
34+
35+
36+
it('should have correct re-export', async () => {
37+
const { foo, bar, default: defaultV } = await import(/*webpackIgnore: true*/ './main.mjs')
38+
expect(foo()).toBe('foo')
39+
expect(bar()).toBe('bar')
40+
expect(defaultV.bar()).toBe('bar')
41+
})
42+
43+
export { bar_1 as bar, foo_1 as foo };
44+
export default cjs_unknown_default_0;
45+
46+
```
47+
48+
```mjs title=runtime.mjs
49+
50+
var __webpack_modules__ = {};
51+
// The module cache
52+
var __webpack_module_cache__ = {};
53+
// The require function
54+
function __webpack_require__(moduleId) {
55+
// Check if module is in cache
56+
var cachedModule = __webpack_module_cache__[moduleId];
57+
if (cachedModule !== undefined) {
58+
return cachedModule.exports;
59+
}
60+
// Create a new module (and put it into the cache)
61+
var module = (__webpack_module_cache__[moduleId] = {
62+
exports: {}
63+
});
64+
// Execute the module function
65+
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
66+
67+
// Return the exports of the module
68+
return module.exports;
69+
}
70+
// expose the modules object (__webpack_modules__)
71+
__webpack_require__.m = __webpack_modules__;
72+
73+
// esm library register module runtime
74+
(() => {
75+
__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) }
76+
77+
})();
78+
// webpack/runtime/compat_get_default_export
79+
(() => {
80+
// getDefaultExport function for compatibility with non-ESM modules
81+
__webpack_require__.n = (module) => {
82+
var getter = module && module.__esModule ?
83+
() => (module['default']) :
84+
() => (module);
85+
__webpack_require__.d(getter, { a: getter });
86+
return getter;
87+
};
88+
89+
})();
90+
// webpack/runtime/define_property_getters
91+
(() => {
92+
__webpack_require__.d = (exports, definition) => {
93+
for(var key in definition) {
94+
if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
95+
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
96+
}
97+
}
98+
};
99+
})();
100+
// webpack/runtime/has_own_property
101+
(() => {
102+
__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
103+
})();
104+
105+
export { __webpack_require__ };
106+
107+
```
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const exportSymbol = () => 'bar'
2+
3+
exports[exportSymbol()] = () => 'bar'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exports.foo = () => 'foo'
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export { foo } from './cjs.cjs'
2+
export { bar } from './cjs-unknown.cjs'
3+
export { default } from './cjs-unknown.cjs'
4+
5+
it('should have correct re-export', async () => {
6+
const { foo, bar, default: defaultV } = await import(/*webpackIgnore: true*/ './main.mjs')
7+
expect(foo()).toBe('foo')
8+
expect(bar()).toBe('bar')
9+
expect(defaultV.bar()).toBe('bar')
10+
})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}

0 commit comments

Comments
 (0)