Skip to content

Commit 17557bf

Browse files
authored
feat: preserve tla expr for EsmLibrary (#12942)
1 parent c938a59 commit 17557bf

File tree

24 files changed

+221
-284
lines changed

24 files changed

+221
-284
lines changed

crates/rspack_plugin_esm_library/src/chunk_link.rs

Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -375,44 +375,6 @@ impl ChunkLinkContext {
375375
}
376376
}
377377

378-
pub fn add_re_export_from_request(
379-
&mut self,
380-
request: String,
381-
imported_name: Atom,
382-
export_name: Atom,
383-
) {
384-
self.exported_symbols.insert(export_name.clone());
385-
386-
self
387-
.re_exports
388-
.entry(ReExportFrom::Request(request))
389-
.or_default()
390-
.entry(imported_name)
391-
.or_default()
392-
.insert(export_name);
393-
}
394-
395-
pub fn add_re_export(&mut self, chunk: ChunkUkey, local_name: Atom, export_name: Atom) -> &Atom {
396-
let export_name = if self.exported_symbols.insert(export_name.clone()) {
397-
export_name
398-
} else {
399-
let new_name = find_new_name(&local_name, &self.used_names, &vec![]);
400-
self.used_names.insert(new_name.clone());
401-
self.exported_symbols.insert(new_name.clone());
402-
new_name
403-
};
404-
405-
let set = self
406-
.re_exports
407-
.entry(ReExportFrom::Chunk(chunk))
408-
.or_default()
409-
.entry(local_name)
410-
.or_default();
411-
412-
set.insert(export_name.clone());
413-
set.get(&export_name).expect("should have inserted")
414-
}
415-
416378
pub fn exports(&self) -> &FxHashMap<Atom, FxIndexSet<Atom>> {
417379
&self.exports
418380
}
@@ -424,4 +386,10 @@ impl ChunkLinkContext {
424386
pub fn re_exports(&self) -> &FxIndexMap<ReExportFrom, FxHashMap<Atom, FxHashSet<Atom>>> {
425387
&self.re_exports
426388
}
389+
390+
pub fn re_exports_mut(
391+
&mut self,
392+
) -> &mut FxIndexMap<ReExportFrom, FxHashMap<Atom, FxHashSet<Atom>>> {
393+
&mut self.re_exports
394+
}
427395
}

crates/rspack_plugin_esm_library/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
mod chunk_link;
22
mod dependency;
3-
mod ensure_entry_exports;
43
mod esm_lib_parser_plugin;
54
mod link;
5+
mod optimize_chunks;
66
mod plugin;
77
mod preserve_modules;
88
mod render;

crates/rspack_plugin_esm_library/src/link.rs

Lines changed: 123 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use swc_core::{
4040

4141
use crate::{
4242
EsmLibraryPlugin,
43-
chunk_link::{ChunkLinkContext, ExternalInterop, Ref, SymbolRef},
43+
chunk_link::{ChunkLinkContext, ExternalInterop, ReExportFrom, Ref, SymbolRef},
4444
};
4545

4646
pub(crate) trait GetMut<K, V> {
@@ -66,9 +66,10 @@ impl<V> GetMut<ModuleIdentifier, V> for IdentifierIndexMap<V> {
6666
static START_EXPORTS: LazyLock<Atom> = LazyLock::new(|| "*".into());
6767

6868
#[derive(Default, Debug)]
69-
struct ExportsContext {
70-
pub exports: FxHashMap<Atom, FxIndexSet<Atom>>,
71-
pub exported_symbols: FxHashMap<Atom, Atom>,
69+
pub(crate) struct ExportsContext {
70+
exports: FxHashMap<Atom, FxIndexSet<Atom>>,
71+
exported_symbols: FxHashSet<Atom>,
72+
re_exports: FxIndexMap<ReExportFrom, FxHashMap<Atom, FxHashSet<Atom>>>,
7273
}
7374

7475
impl EsmLibraryPlugin {
@@ -94,33 +95,92 @@ impl EsmLibraryPlugin {
9495
}
9596

9697
// we've not exported this local symbol, check if we've already exported this symbol
97-
if ctx.exported_symbols.contains_key(&exported) {
98+
if ctx.exported_symbols.contains(&exported) {
9899
// the name is already exported and we know the exported_local is not the same
99100
if strict_exports {
100101
return None;
101102
}
102103

103-
let already_exported_names = ctx.exports.entry(local.clone()).or_default();
104+
let already_exported_names = ctx.exports.entry(local).or_default();
104105

105106
// we find another name to export this symbol
106107
let mut idx = 0;
107108
let mut new_export = Atom::new(format!("{exported}_{idx}"));
108-
while ctx.exported_symbols.contains_key(&new_export) {
109+
while ctx.exported_symbols.contains(&new_export) {
109110
idx += 1;
110111
new_export = format!("{exported}_{idx}").into();
111112
}
112113

113-
ctx.exported_symbols.insert(new_export.clone(), local);
114+
ctx.exported_symbols.insert(new_export.clone());
114115
already_exported_names.insert(new_export.clone());
115116
already_exported_names.get(&new_export).cloned()
116117
} else {
117-
let already_exported_names = ctx.exports.entry(local.clone()).or_default();
118-
ctx.exported_symbols.insert(exported.clone(), local);
118+
let already_exported_names = ctx.exports.entry(local).or_default();
119+
ctx.exported_symbols.insert(exported.clone());
119120
already_exported_names.insert(exported.clone());
120121
already_exported_names.get(&exported).cloned()
121122
}
122123
}
123124

125+
// // orig_chunk
126+
// export { local_name as export_name } from 'ref_chunk'
127+
fn add_chunk_re_export(
128+
orig_chunk: ChunkUkey,
129+
ref_chunk: ChunkUkey,
130+
local_name: Atom,
131+
export_name: Atom,
132+
chunk_exports: &mut UkeyMap<ChunkUkey, ExportsContext>,
133+
strict_exports: bool,
134+
) -> Option<&Atom> {
135+
let exports_context = chunk_exports.get_mut_unwrap(&orig_chunk);
136+
137+
let export_name = if !exports_context.exported_symbols.contains(&export_name) {
138+
export_name
139+
} else {
140+
if strict_exports {
141+
return None;
142+
}
143+
let mut idx = 0;
144+
let mut new_export = Atom::new(format!("{export_name}_{idx}"));
145+
while exports_context.exported_symbols.contains(&new_export) {
146+
idx += 1;
147+
new_export = format!("{export_name}_{idx}").into();
148+
}
149+
new_export
150+
};
151+
152+
exports_context.exported_symbols.insert(export_name.clone());
153+
154+
let set = exports_context
155+
.re_exports
156+
.entry(ReExportFrom::Chunk(ref_chunk))
157+
.or_default()
158+
.entry(local_name)
159+
.or_default();
160+
161+
set.insert(export_name.clone());
162+
Some(set.get(&export_name).expect("should have inserted"))
163+
}
164+
165+
fn add_re_export_from_request(
166+
chunk: ChunkUkey,
167+
request: String,
168+
imported_name: Atom,
169+
export_name: Atom,
170+
chunk_exports: &mut UkeyMap<ChunkUkey, ExportsContext>,
171+
) {
172+
let ctx = chunk_exports.get_mut_unwrap(&chunk);
173+
ctx.exported_symbols.insert(export_name.clone());
174+
175+
ctx
176+
.re_exports
177+
.entry(ReExportFrom::Request(request))
178+
.or_default()
179+
.entry(imported_name)
180+
.or_default()
181+
.insert(export_name);
182+
}
183+
124184
pub(crate) async fn link(
125185
&self,
126186
compilation: &Compilation,
@@ -1042,8 +1102,14 @@ var {} = {{}};
10421102
if entry_chunk != current_chunk
10431103
&& let Some(exported) = exported
10441104
{
1045-
let entry_chunk_link = link.get_mut_unwrap(&entry_chunk);
1046-
entry_chunk_link.add_re_export(current_chunk, exported, "default".to_string().into());
1105+
Self::add_chunk_re_export(
1106+
entry_chunk,
1107+
current_chunk,
1108+
exported,
1109+
"default".to_string().into(),
1110+
exports,
1111+
true,
1112+
);
10471113
}
10481114
}
10491115
ModuleInfo::External(info) => {
@@ -1237,8 +1303,14 @@ var {} = {{}};
12371303
if ref_chunk != entry_chunk
12381304
&& let Some(exported) = exported
12391305
{
1240-
let entry_chunk_link = link.get_mut_unwrap(&entry_chunk);
1241-
entry_chunk_link.add_re_export(ref_chunk, exported.clone(), name.clone());
1306+
Self::add_chunk_re_export(
1307+
entry_chunk,
1308+
ref_chunk,
1309+
exported.clone(),
1310+
name.clone(),
1311+
exports,
1312+
true,
1313+
);
12421314
}
12431315
}
12441316
}
@@ -1567,19 +1639,38 @@ var {} = {{}};
15671639

15681640
if let Ref::Symbol(symbol_binding) = &mut binding {
15691641
let module_id = symbol_binding.module;
1570-
let ref_chunk = Self::get_module_chunk(module_id, compilation);
1642+
let ref_module_chunk = Self::get_module_chunk(module_id, compilation);
15711643
let ref_external = concate_modules_map[ref_module].is_external();
15721644

15731645
if from_other_chunk && !ref_external {
15741646
let exported = Self::add_chunk_export(
1575-
ref_chunk,
1647+
ref_module_chunk,
15761648
symbol_binding.symbol.clone(),
15771649
symbol_binding.symbol.clone(),
15781650
&mut exports,
15791651
false,
15801652
);
15811653

1582-
symbol_binding.symbol = exported.expect("should have exported");
1654+
let mut exported = exported.expect("should have exported");
1655+
1656+
if ref_module_chunk != ref_chunk {
1657+
// special case
1658+
// const { foo, bar } = await import('./re-exports')
1659+
// there is a chance that foo is from another chunk, and bar is from re-exports chunk
1660+
// so should make sure foo is from another chunk
1661+
exported = Self::add_chunk_re_export(
1662+
ref_chunk,
1663+
ref_module_chunk,
1664+
exported.clone(),
1665+
exported.clone(),
1666+
&mut exports,
1667+
false,
1668+
)
1669+
.expect("should have name")
1670+
.clone();
1671+
}
1672+
1673+
symbol_binding.symbol = exported;
15831674
}
15841675
}
15851676

@@ -1788,34 +1879,39 @@ var {} = {{}};
17881879
}
17891880
}
17901881

1791-
let exports = exports
1792-
.get_mut(&chunk_link.chunk)
1793-
.expect("should have exports");
1794-
17951882
for (key, locals) in removed_import_stmts {
17961883
chunk_link.raw_import_stmts.swap_remove(&key);
17971884

17981885
// change it from normal export to re-export
17991886
for (local, imported) in locals {
1887+
let chunk_exports = exports
1888+
.get_mut(&chunk_link.chunk)
1889+
.expect("should have exports");
1890+
18001891
// remove local from exported names
1801-
let Some(export_names) = exports.exports.remove(&local) else {
1892+
let Some(export_names) = chunk_exports.exports.remove(&local) else {
18021893
continue;
18031894
};
18041895

18051896
// add local to re-export
18061897
for export_name in export_names {
1807-
chunk_link.add_re_export_from_request(key.0.clone(), imported.clone(), export_name);
1898+
Self::add_re_export_from_request(
1899+
chunk_link.chunk,
1900+
key.0.clone(),
1901+
imported.clone(),
1902+
export_name,
1903+
&mut exports,
1904+
);
18081905
}
18091906
}
18101907
}
18111908
}
18121909

18131910
// put result into chunk_link context
18141911
for (chunk, exports) in exports {
1815-
*link
1816-
.get_mut(&chunk)
1817-
.expect("should have chunk")
1818-
.exports_mut() = exports.exports;
1912+
let link = link.get_mut(&chunk).expect("should have chunk");
1913+
*link.exports_mut() = exports.exports;
1914+
*link.re_exports_mut() = exports.re_exports;
18191915
}
18201916
for (chunk, imports) in imports {
18211917
link.get_mut(&chunk).expect("should have chunk").imports = imports;

crates/rspack_plugin_esm_library/src/ensure_entry_exports.rs renamed to crates/rspack_plugin_esm_library/src/optimize_chunks.rs

File renamed without changes.

crates/rspack_plugin_esm_library/src/plugin.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rspack_core::{
1414
CompilationOptimizeChunks, CompilationParams, CompilationProcessAssets,
1515
CompilationRuntimeRequirementInTree, CompilerCompilation, ConcatenatedModuleInfo,
1616
ConcatenationScope, DependencyType, ExternalModuleInfo, GetTargetResult, Logger,
17-
ModuleFactoryCreateData, ModuleGraph, ModuleIdentifier, ModuleInfo, ModuleType,
17+
ModuleFactoryCreateData, ModuleIdentifier, ModuleInfo, ModuleType,
1818
NormalModuleFactoryAfterFactorize, NormalModuleFactoryParser, ParserAndGenerator, ParserOptions,
1919
Plugin, PrefetchExportsInfoMode, RuntimeGlobals, RuntimeModule, get_target, is_esm_dep_like,
2020
rspack_sources::{ReplaceSource, Source},
@@ -31,7 +31,7 @@ use tokio::sync::RwLock;
3131

3232
use crate::{
3333
chunk_link::ChunkLinkContext, dependency::dyn_import::DynamicImportDependencyTemplate,
34-
ensure_entry_exports::ensure_entry_exports, esm_lib_parser_plugin::EsmLibParserPlugin,
34+
esm_lib_parser_plugin::EsmLibParserPlugin, optimize_chunks::ensure_entry_exports,
3535
preserve_modules::preserve_modules, runtime::EsmRegisterModuleRuntimeModule,
3636
};
3737

@@ -98,7 +98,7 @@ async fn render_chunk_content(
9898
async fn finish_modules(
9999
&self,
100100
compilation: &mut Compilation,
101-
async_modules_artifact: &mut AsyncModulesArtifact,
101+
_async_modules_artifact: &mut AsyncModulesArtifact,
102102
) -> Result<()> {
103103
let module_graph = compilation.get_module_graph();
104104
let mut modules_map = IdentifierIndexMap::default();
@@ -119,9 +119,6 @@ async fn finish_modules(
119119
"module {module_identifier} has bailout reason: {reason}",
120120
));
121121
should_scope_hoisting = false;
122-
} else if ModuleGraph::is_async(async_modules_artifact, module_identifier) {
123-
logger.debug(format!("module {module_identifier} is an async module"));
124-
should_scope_hoisting = false;
125122
}
126123
// TODO: support config to disable scope hoisting for non strict module
127124
// else if !module.build_info().strict {

0 commit comments

Comments
 (0)