Skip to content

Commit 274a1bd

Browse files
authored
feat: add experimental EsmLibraryPlugin for better esm output (#10350)
* feat: better esm format feat: better esm format feat: add chunk link relation feat: split module separately chore: update feat: render chunk fix: separate runtime chunk feat: fix some issues feat: support dynamic import call feat: support namespace interop fix: correct runtime_requirements chore: rebase chore: fix clippy fix: should handle default export fix: should link exports right fix: should use local atom if module is in current scope feat: namespace support feat: support re-export from entry chore: fix clippy feat: correct namespace render feat: handle interop default chore: improve interop test feat: support dyn import feat: interop-tests fix: fix some issues feat: should use interop for dynamic imports fix: should use importer's strict_esm refactor: use plugin to enable new esm format chore: clippy dyn import with cjs fix: replace chunk name after content hash feat: support star re-exports fix: should only require once when there are multiple required call fix: fix tests fix: should use exported name as export specifier fix: entry exports fix: remove dup chunks feat: add all snapshot tests fix: should re-exports from other chunk fix: should import external module chunk * refactor: refactor esm tests
1 parent 1573264 commit 274a1bd

File tree

115 files changed

+6682
-168
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+6682
-168
lines changed

Cargo.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ rspack_plugin_dll = { version = "=0.5.7", path = "crates/rs
183183
rspack_plugin_dynamic_entry = { version = "=0.5.7", path = "crates/rspack_plugin_dynamic_entry", default-features = false }
184184
rspack_plugin_ensure_chunk_conditions = { version = "=0.5.7", path = "crates/rspack_plugin_ensure_chunk_conditions", default-features = false }
185185
rspack_plugin_entry = { version = "=0.5.7", path = "crates/rspack_plugin_entry", default-features = false }
186+
rspack_plugin_esm_library = { version = "=0.5.7", path = "crates/rspack_plugin_esm_library", default-features = false }
186187
rspack_plugin_externals = { version = "=0.5.7", path = "crates/rspack_plugin_externals", default-features = false }
187188
rspack_plugin_extract_css = { version = "=0.5.7", path = "crates/rspack_plugin_extract_css", default-features = false }
188189
rspack_plugin_hmr = { version = "=0.5.7", path = "crates/rspack_plugin_hmr", default-features = false }

crates/node_binding/napi-binding.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ export declare enum BuiltinPluginName {
526526
CommonJsChunkFormatPlugin = 'CommonJsChunkFormatPlugin',
527527
ArrayPushCallbackChunkFormatPlugin = 'ArrayPushCallbackChunkFormatPlugin',
528528
ModuleChunkFormatPlugin = 'ModuleChunkFormatPlugin',
529+
EsmLibraryPlugin = 'EsmLibraryPlugin',
529530
HotModuleReplacementPlugin = 'HotModuleReplacementPlugin',
530531
LimitChunkCountPlugin = 'LimitChunkCountPlugin',
531532
WorkerPlugin = 'WorkerPlugin',

crates/rspack_binding_api/Cargo.toml

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,28 @@ plugin = ["rspack_loader_swc/plugin", "rspack_util/plugin"]
1818
sftrace-setup = ["dep:sftrace-setup", "rspack_allocator/sftrace-setup"]
1919

2020
[dependencies]
21-
anyhow = { workspace = true }
22-
ropey = { workspace = true }
23-
rspack_allocator = { workspace = true }
24-
rspack_browserslist = { workspace = true }
25-
rspack_collections = { workspace = true }
26-
rspack_core = { workspace = true, features = ["napi"] }
27-
rspack_error = { workspace = true }
28-
rspack_fs = { workspace = true }
29-
rspack_hash = { workspace = true }
30-
rspack_hook = { workspace = true }
31-
rspack_napi = { workspace = true }
32-
rspack_paths = { workspace = true }
33-
rspack_plugin_html = { workspace = true }
34-
rspack_plugin_javascript = { workspace = true }
35-
rspack_plugin_rsdoctor = { workspace = true }
36-
rspack_plugin_rslib = { workspace = true }
37-
rspack_plugin_rstest = { workspace = true }
38-
rspack_plugin_runtime = { workspace = true }
39-
rspack_tasks = { workspace = true }
40-
rspack_util = { workspace = true }
41-
rspack_workspace = { workspace = true }
21+
anyhow = { workspace = true }
22+
ropey = { workspace = true }
23+
rspack_allocator = { workspace = true }
24+
rspack_browserslist = { workspace = true }
25+
rspack_collections = { workspace = true }
26+
rspack_core = { workspace = true, features = ["napi"] }
27+
rspack_error = { workspace = true }
28+
rspack_fs = { workspace = true }
29+
rspack_hash = { workspace = true }
30+
rspack_hook = { workspace = true }
31+
rspack_napi = { workspace = true }
32+
rspack_paths = { workspace = true }
33+
rspack_plugin_esm_library = { workspace = true }
34+
rspack_plugin_html = { workspace = true }
35+
rspack_plugin_javascript = { workspace = true }
36+
rspack_plugin_rsdoctor = { workspace = true }
37+
rspack_plugin_rslib = { workspace = true }
38+
rspack_plugin_rstest = { workspace = true }
39+
rspack_plugin_runtime = { workspace = true }
40+
rspack_tasks = { workspace = true }
41+
rspack_util = { workspace = true }
42+
rspack_workspace = { workspace = true }
4243

4344
rspack_tracing = { workspace = true }
4445

crates/rspack_binding_api/src/raw_options/raw_builtins/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ use rspack_plugin_dll::{
5555
use rspack_plugin_dynamic_entry::DynamicEntryPlugin;
5656
use rspack_plugin_ensure_chunk_conditions::EnsureChunkConditionsPlugin;
5757
use rspack_plugin_entry::EntryPlugin;
58+
use rspack_plugin_esm_library::EsmLibraryPlugin;
5859
use rspack_plugin_externals::{
5960
ExternalsPlugin, electron_target_plugin, http_externals_rspack_plugin, node_target_plugin,
6061
};
@@ -155,6 +156,7 @@ pub enum BuiltinPluginName {
155156
CommonJsChunkFormatPlugin,
156157
ArrayPushCallbackChunkFormatPlugin,
157158
ModuleChunkFormatPlugin,
159+
EsmLibraryPlugin,
158160
HotModuleReplacementPlugin,
159161
LimitChunkCountPlugin,
160162
WorkerPlugin,
@@ -407,6 +409,9 @@ impl<'a> BuiltinPlugin<'a> {
407409
BuiltinPluginName::CommonJsChunkFormatPlugin => {
408410
plugins.push(CommonJsChunkFormatPlugin::default().boxed());
409411
}
412+
BuiltinPluginName::EsmLibraryPlugin => {
413+
plugins.push(EsmLibraryPlugin::default().boxed());
414+
}
410415
BuiltinPluginName::ArrayPushCallbackChunkFormatPlugin => {
411416
plugins.push(ArrayPushCallbackChunkFormatPlugin::default().boxed());
412417
}

crates/rspack_core/src/artifacts/code_generation_results.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,74 @@ impl CodeGenerationResults {
298298
.unwrap_or_else(|| panic!("No code generation result for {module_identifier}"))
299299
}
300300

301+
/**
302+
* This API should be used carefully, it will return one of the code generation result,
303+
* make sure the module has the same code generation result for all runtimes.
304+
*/
305+
pub fn get_one_mut(
306+
&mut self,
307+
module_identifier: &ModuleIdentifier,
308+
) -> &mut BindingCell<CodeGenerationResult> {
309+
self
310+
.map
311+
.get(module_identifier)
312+
.and_then(|entry| {
313+
entry
314+
.values()
315+
.next()
316+
.and_then(|m| self.module_generation_result_map.get_mut(m))
317+
})
318+
.unwrap_or_else(|| panic!("No code generation result for {module_identifier}"))
319+
}
320+
321+
pub fn get_mut(
322+
&mut self,
323+
module_identifier: &ModuleIdentifier,
324+
runtime: Option<&RuntimeSpec>,
325+
) -> &mut BindingCell<CodeGenerationResult> {
326+
if let Some(entry) = self.map.get(module_identifier) {
327+
if let Some(runtime) = runtime {
328+
entry
329+
.get(runtime)
330+
.and_then(|m| {
331+
self.module_generation_result_map.get_mut(m)
332+
})
333+
.unwrap_or_else(|| {
334+
panic!(
335+
"Failed to code generation result for {module_identifier} with runtime {runtime:?} \n {entry:?}"
336+
)
337+
})
338+
} else {
339+
if entry.size() > 1 {
340+
let mut values = entry.values();
341+
let results: FxHashSet<_> = entry.values().collect();
342+
if results.len() > 1 {
343+
panic!(
344+
"No unique code generation entry for unspecified runtime for {module_identifier} ",
345+
);
346+
}
347+
348+
return values
349+
.next()
350+
.and_then(|m| self.module_generation_result_map.get_mut(m))
351+
.unwrap_or_else(|| panic!("Expected value exists"));
352+
}
353+
354+
entry
355+
.values()
356+
.next()
357+
.and_then(|m| self.module_generation_result_map.get_mut(m))
358+
.unwrap_or_else(|| panic!("Expected value exists"))
359+
}
360+
} else {
361+
panic!(
362+
"No code generation entry for {} (existing entries: {:?})",
363+
module_identifier,
364+
self.map.keys().collect::<Vec<_>>()
365+
)
366+
}
367+
}
368+
301369
pub fn add(
302370
&mut self,
303371
module_identifier: ModuleIdentifier,
@@ -350,4 +418,5 @@ pub struct CodeGenerationJob {
350418
pub hash: RspackHashDigest,
351419
pub runtime: RuntimeSpec,
352420
pub runtimes: Vec<RuntimeSpec>,
421+
pub scope: Option<ConcatenationScope>,
353422
}

crates/rspack_core/src/chunk_graph/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use core::fmt;
2-
use std::{borrow::Cow, collections::HashSet};
2+
use std::borrow::Cow;
33

44
use itertools::Itertools;
55
use rspack_collections::{IdentifierMap, UkeyMap};
66
use rspack_util::env::has_query;
7-
use rustc_hash::FxHashMap as HashMap;
7+
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
88

99
use crate::{
1010
AsyncDependenciesBlockIdentifier, ChunkGroupUkey, ChunkUkey, Compilation, ModuleIdentifier,
@@ -39,7 +39,8 @@ impl ChunkGraph {
3939
// 1. support chunk_group dump visualizer
4040
pub fn to_dot(&self, compilation: &Compilation) -> std::result::Result<String, fmt::Error> {
4141
let mut visited_group_nodes: HashMap<ChunkGroupUkey, String> = HashMap::default();
42-
let mut visited_group_edges: HashSet<(ChunkGroupUkey, ChunkGroupUkey, bool)> = HashSet::new();
42+
let mut visited_group_edges: HashSet<(ChunkGroupUkey, ChunkGroupUkey, bool)> =
43+
HashSet::default();
4344
let mut visiting_groups: Vec<ChunkGroupUkey> = Vec::new();
4445
let module_graph = compilation.get_module_graph();
4546
// generate following chunk_group_info as dto record info

crates/rspack_core/src/compiler/compilation.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,17 @@ use crate::{
3838
ChunkByUkey, ChunkContentHash, ChunkGraph, ChunkGroupByUkey, ChunkGroupUkey, ChunkHashesArtifact,
3939
ChunkIdsArtifact, ChunkKind, ChunkRenderArtifact, ChunkRenderCacheArtifact, ChunkRenderResult,
4040
ChunkUkey, CodeGenerationJob, CodeGenerationResult, CodeGenerationResults, CompilationLogger,
41-
CompilationLogging, CompilerOptions, DependenciesDiagnosticsArtifact, DependencyCodeGeneration,
42-
DependencyId, DependencyTemplate, DependencyTemplateType, DependencyType, Entry, EntryData,
43-
EntryOptions, EntryRuntime, Entrypoint, Filename, ImportVarMap, Logger, MemoryGCStorage,
44-
ModuleFactory, ModuleGraph, ModuleGraphCacheArtifact, ModuleGraphPartial, ModuleIdentifier,
45-
ModuleIdsArtifact, ModuleStaticCacheArtifact, PathData, ResolverFactory, RuntimeGlobals,
46-
RuntimeKeyMap, RuntimeMode, RuntimeModule, RuntimeSpec, RuntimeSpecMap, RuntimeTemplate,
47-
SharedPluginDriver, SideEffectsOptimizeArtifact, SourceType, Stats, ValueCacheVersions,
41+
CompilationLogging, CompilerOptions, ConcatenationScope, DependenciesDiagnosticsArtifact,
42+
DependencyCodeGeneration, DependencyId, DependencyTemplate, DependencyTemplateType,
43+
DependencyType, Entry, EntryData, EntryOptions, EntryRuntime, Entrypoint, ExecuteModuleId,
44+
Filename, ImportVarMap, Logger, MemoryGCStorage, ModuleFactory, ModuleGraph,
45+
ModuleGraphCacheArtifact, ModuleGraphPartial, ModuleIdentifier, ModuleIdsArtifact,
46+
ModuleStaticCacheArtifact, PathData, ResolverFactory, RuntimeGlobals, RuntimeKeyMap, RuntimeMode,
47+
RuntimeModule, RuntimeSpec, RuntimeSpecMap, RuntimeTemplate, SharedPluginDriver,
48+
SideEffectsOptimizeArtifact, SourceType, Stats, ValueCacheVersions,
4849
build_chunk_graph::{build_chunk_graph, build_chunk_graph_new},
4950
compilation::make::{
50-
ExecuteModuleId, MakeArtifact, ModuleExecutor, UpdateParam, finish_make, make,
51-
update_module_graph,
51+
MakeArtifact, ModuleExecutor, UpdateParam, finish_make, make, update_module_graph,
5252
},
5353
get_runtime_key,
5454
incremental::{self, Incremental, IncrementalPasses, Mutation},
@@ -66,6 +66,7 @@ define_hook!(CompilationExecuteModule:
6666
Series(module: &ModuleIdentifier, runtime_modules: &IdentifierSet, code_generation_results: &BindingCell<CodeGenerationResults>, execute_module_id: &ExecuteModuleId));
6767
define_hook!(CompilationFinishModules: Series(compilation: &mut Compilation));
6868
define_hook!(CompilationSeal: Series(compilation: &mut Compilation));
69+
define_hook!(CompilationConcatenationScope: SeriesBail(compilation: &Compilation, curr_module: ModuleIdentifier) -> ConcatenationScope);
6970
define_hook!(CompilationOptimizeDependencies: SeriesBail(compilation: &mut Compilation) -> bool);
7071
define_hook!(CompilationOptimizeModules: SeriesBail(compilation: &mut Compilation) -> bool);
7172
define_hook!(CompilationAfterOptimizeModules: Series(compilation: &mut Compilation));
@@ -97,6 +98,7 @@ pub struct CompilationHooks {
9798
pub add_entry: CompilationAddEntryHook,
9899
pub build_module: CompilationBuildModuleHook,
99100
pub revoked_modules: CompilationRevokedModulesHook,
101+
pub concatenation_scope: CompilationConcatenationScopeHook,
100102
pub still_valid_module: CompilationStillValidModuleHook,
101103
pub succeed_module: CompilationSucceedModuleHook,
102104
pub execute_module: CompilationExecuteModuleHook,
@@ -313,6 +315,7 @@ impl Compilation {
313315
pub const PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE: i32 = 700;
314316
pub const PROCESS_ASSETS_STAGE_SUMMARIZE: i32 = 1000;
315317
pub const PROCESS_ASSETS_STAGE_OPTIMIZE_HASH: i32 = 2500;
318+
pub const PROCESS_ASSETS_STAGE_AFTER_OPTIMIZE_HASH: i32 = 2600;
316319
pub const PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER: i32 = 3000;
317320
pub const PROCESS_ASSETS_STAGE_ANALYSE: i32 = 4000;
318321
pub const PROCESS_ASSETS_STAGE_REPORT: i32 = 5000;
@@ -1096,6 +1099,12 @@ impl Compilation {
10961099
for runtime in chunk_graph.get_module_runtimes_iter(module, &self.chunk_by_ukey) {
10971100
let hash = ChunkGraph::get_module_hash(self, module, runtime)
10981101
.expect("should have cgm.hash in code generation");
1102+
let scope = self
1103+
.plugin_driver
1104+
.compilation_hooks
1105+
.concatenation_scope
1106+
.call(self, module)
1107+
.await?;
10991108
if let Some(job) = map.get_mut(hash) {
11001109
job.runtimes.push(runtime.clone());
11011110
} else {
@@ -1106,6 +1115,7 @@ impl Compilation {
11061115
hash: hash.clone(),
11071116
runtime: runtime.clone(),
11081117
runtimes: vec![runtime.clone()],
1118+
scope,
11091119
},
11101120
);
11111121
}
@@ -1129,7 +1139,7 @@ impl Compilation {
11291139
.code_generate_occasion
11301140
.use_cache(&job, || async {
11311141
module
1132-
.code_generation(this, Some(&job.runtime), None)
1142+
.code_generation(this, Some(&job.runtime), job.scope.clone())
11331143
.await
11341144
.map(|mut codegen_res| {
11351145
codegen_res.set_hash(

0 commit comments

Comments
 (0)