diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 907b8824fc7..59cf81a3898 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -982,6 +982,7 @@ export interface RawCacheGroupOptions { name?: string | false | Function reuseExistingChunk?: boolean enforce?: boolean + usedExports?: boolean } export interface RawCacheGroupTestCtx { @@ -1666,6 +1667,7 @@ export interface RawSplitChunksOptions { cacheGroups?: Array /** What kind of chunks should be selected. */ chunks?: RegExp | 'async' | 'initial' | 'all' | Function + usedExports?: boolean automaticNameDelimiter?: string maxAsyncRequests?: number maxInitialRequests?: number diff --git a/crates/rspack_binding_options/src/options/raw_split_chunks/mod.rs b/crates/rspack_binding_options/src/options/raw_split_chunks/mod.rs index 20ac1fc0b86..d836fac79c4 100644 --- a/crates/rspack_binding_options/src/options/raw_split_chunks/mod.rs +++ b/crates/rspack_binding_options/src/options/raw_split_chunks/mod.rs @@ -37,6 +37,7 @@ pub struct RawSplitChunksOptions { #[napi(ts_type = "RegExp | 'async' | 'initial' | 'all' | Function")] #[derivative(Debug = "ignore")] pub chunks: Option, + pub used_exports: Option, pub automatic_name_delimiter: Option, pub max_async_requests: Option, pub max_initial_requests: Option, @@ -95,6 +96,7 @@ pub struct RawCacheGroupOptions { // used_exports: bool, pub reuse_existing_chunk: Option, pub enforce: Option, + pub used_exports: Option, } impl From for rspack_plugin_split_chunks::PluginOptions { @@ -220,6 +222,9 @@ impl From for rspack_plugin_split_chunks::PluginOptions { max_initial_size, r#type, layer, + used_exports: v + .used_exports + .unwrap_or_else(|| raw_opts.used_exports.unwrap_or_default()), } }), ); diff --git a/crates/rspack_core/src/exports_info.rs b/crates/rspack_core/src/exports_info.rs index 3e241bae747..ba2d4e18e8e 100644 --- a/crates/rspack_core/src/exports_info.rs +++ b/crates/rspack_core/src/exports_info.rs @@ -7,6 +7,7 @@ use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; use std::sync::LazyLock; +use either::Either; use itertools::Itertools; use rspack_collections::impl_item_ukey; use rspack_collections::Ukey; @@ -672,6 +673,33 @@ impl ExportsInfo { } } + pub fn get_usage_key(&self, mg: &ModuleGraph, runtime: Option<&RuntimeSpec>) -> UsageKey { + let exports_info = self.as_exports_info(mg); + + // only expand capacity when this has redirect_to + let mut key = UsageKey(Vec::with_capacity(exports_info.exports.len() + 2)); + + if let Some(redirect_to) = &exports_info.redirect_to { + key.add(Either::Left(Box::new( + redirect_to.get_usage_key(mg, runtime), + ))); + } else { + key.add(Either::Right( + self.other_exports_info(mg).get_used(mg, runtime), + )); + }; + + key.add(Either::Right( + exports_info.side_effects_only_info.get_used(mg, runtime), + )); + + for export_info in self.ordered_exports(mg) { + key.add(Either::Right(export_info.get_used(mg, runtime))); + } + + key + } + pub fn is_used(&self, mg: &ModuleGraph, runtime: Option<&RuntimeSpec>) -> bool { let info = self.as_exports_info(mg); if let Some(redirect_to) = info.redirect_to { @@ -1607,6 +1635,15 @@ pub struct FindTargetRetValue { pub export: Option>, } +#[derive(Debug, Hash, PartialEq, Eq, Default)] +pub struct UsageKey(pub(crate) Vec, UsageState>>); + +impl UsageKey { + fn add(&mut self, value: Either, UsageState>) { + self.0.push(value); + } +} + #[derive(Debug, Clone)] struct UnResolvedExportInfoTarget { connection: Option, diff --git a/crates/rspack_plugin_split_chunks/src/options/cache_group.rs b/crates/rspack_plugin_split_chunks/src/options/cache_group.rs index 0a70b490bdd..104130ac26f 100644 --- a/crates/rspack_plugin_split_chunks/src/options/cache_group.rs +++ b/crates/rspack_plugin_split_chunks/src/options/cache_group.rs @@ -42,4 +42,5 @@ pub struct CacheGroup { pub max_initial_size: SplitChunkSizes, pub filename: Option, pub automatic_name_delimiter: String, + pub used_exports: bool, } diff --git a/crates/rspack_plugin_split_chunks/src/plugin/module_group.rs b/crates/rspack_plugin_split_chunks/src/plugin/module_group.rs index 63aa6fd5e5c..d7ba5b5bea3 100644 --- a/crates/rspack_plugin_split_chunks/src/plugin/module_group.rs +++ b/crates/rspack_plugin_split_chunks/src/plugin/module_group.rs @@ -1,11 +1,16 @@ use std::collections::{hash_map, HashMap}; use std::hash::{BuildHasherDefault, Hash, Hasher}; +use dashmap::mapref::entry::Entry; use dashmap::DashMap; use rayon::prelude::*; -use rspack_collections::UkeySet; -use rspack_core::{Chunk, ChunkGraph, ChunkUkey, Compilation, Module, ModuleGraph}; +use rspack_collections::{IdentifierMap, UkeyMap, UkeySet}; +use rspack_core::{ + Chunk, ChunkByUkey, ChunkGraph, ChunkUkey, Compilation, Module, ModuleGraph, ModuleIdentifier, + UsageKey, +}; use rspack_error::Result; +use rspack_util::fx_hash::FxDashMap; use rustc_hash::{FxHashMap, FxHasher}; use super::ModuleGroupMap; @@ -36,6 +41,216 @@ impl Hasher for IdentityHasher { type ChunksKeyHashBuilder = BuildHasherDefault; +fn get_key<'a, I: Iterator>(chunks: I) -> ChunksKey { + let mut sorted_chunk_ukeys = chunks + .map(|chunk| { + // Increment each usize by 1 to avoid hashing the value 0 with FxHasher, which would always return a hash of 0 + chunk.as_u32() + 1 + }) + .collect::>(); + sorted_chunk_ukeys.sort_unstable(); + let mut hasher = FxHasher::default(); + for chunk_ukey in sorted_chunk_ukeys { + chunk_ukey.hash(&mut hasher); + } + hasher.finish() +} + +type ChunkSetsInGraph<'a> = ( + &'a FxHashMap>, + &'a UkeyMap>>, +); + +#[derive(Default)] +struct Combinator { + combinations_cache: FxDashMap>>, + used_exports_combinations_cache: FxDashMap>>, + + chunk_sets_in_graph: FxHashMap>, + chunk_sets_by_count: UkeyMap>>, + + used_exports_chunk_sets_in_graph: FxHashMap>, + used_exports_chunk_sets_by_count: UkeyMap>>, + + grouped_by_exports: IdentifierMap>>, +} + +impl Combinator { + fn group_chunks_by_exports( + module_identifier: &ModuleIdentifier, + module_chunks: impl Iterator, + module_graph: &ModuleGraph, + chunk_by_ukey: &ChunkByUkey, + ) -> Vec> { + let exports_info = module_graph.get_exports_info(module_identifier); + let mut grouped_by_used_exports: FxHashMap> = Default::default(); + for chunk_ukey in module_chunks { + let chunk = chunk_by_ukey.expect_get(&chunk_ukey); + let usage_key = exports_info.get_usage_key(module_graph, Some(&chunk.runtime)); + + grouped_by_used_exports + .entry(usage_key) + .or_default() + .insert(chunk_ukey); + } + + grouped_by_used_exports.values().cloned().collect() + } + + fn get_combination( + &self, + chunks_key: ChunksKey, + combinations_cache: &FxDashMap>>, + chunk_sets_in_graph: &FxHashMap>, + chunk_sets_by_count: &UkeyMap>>, + ) -> Vec> { + match combinations_cache.entry(chunks_key) { + Entry::Occupied(entry) => entry.get().clone(), + Entry::Vacant(entry) => { + let chunks_set = chunk_sets_in_graph + .get(&chunks_key) + .expect("This should never happen, please file an issue"); + + let mut result = vec![chunks_set.clone()]; + + for (count, array_of_set) in chunk_sets_by_count.iter() { + if *count < chunks_set.len() as u32 { + for set in array_of_set { + if set.is_subset(chunks_set) { + result.push(set.clone()); + } + } + } + } + + entry.insert(result.clone()); + result + } + } + } + + fn get_combs( + &self, + module: ModuleIdentifier, + chunk_graph: &ChunkGraph, + used_exports: bool, + ) -> Vec> { + if used_exports { + let (chunk_sets_in_graph, chunk_sets_by_count) = self.group_by_used_exports(); + + let mut result = vec![]; + let chunks_by_module_used = self + .grouped_by_exports + .get(&module) + .expect("should have exports for module"); + + for chunks in chunks_by_module_used.iter() { + let chunks_key = get_key(chunks.iter()); + let combs = self.get_combination( + chunks_key, + &self.used_exports_combinations_cache, + chunk_sets_in_graph, + chunk_sets_by_count, + ); + result.extend(combs.into_iter()); + } + + result + } else { + let (chunk_sets_in_graph, chunk_sets_by_count) = self.group_by_chunks(); + let chunks = chunk_graph.get_module_chunks(module); + self.get_combination( + get_key(chunks.iter()), + &self.combinations_cache, + chunk_sets_in_graph, + chunk_sets_by_count, + ) + } + } + + fn prepare_group_by_chunks( + &mut self, + module_graph: &ModuleGraph, + chunk_graph: &ChunkGraph, + ) -> ChunkSetsInGraph { + let chunk_sets_in_graph = &mut self.chunk_sets_in_graph; + let chunk_sets_by_count = &mut self.chunk_sets_by_count; + + for module in module_graph.modules().keys() { + let chunks = chunk_graph.get_module_chunks(*module); + if chunks.is_empty() { + continue; + } + let chunk_key = get_key(chunks.iter()); + chunk_sets_in_graph.insert(chunk_key, chunks.clone()); + } + + for chunks in chunk_sets_in_graph.values() { + let count = chunks.len(); + + chunk_sets_by_count + .entry(count as u32) + .and_modify(|set| set.push(chunks.clone())) + .or_insert(vec![chunks.clone()]); + } + + (&self.chunk_sets_in_graph, &self.chunk_sets_by_count) + } + + fn group_by_chunks(&self) -> ChunkSetsInGraph { + (&self.chunk_sets_in_graph, &self.chunk_sets_by_count) + } + + fn prepare_group_by_used_exports( + &mut self, + module_graph: &ModuleGraph, + chunk_graph: &ChunkGraph, + chunk_by_ukey: &ChunkByUkey, + ) -> ChunkSetsInGraph { + let grouped_by_exports = &mut self.grouped_by_exports; + let used_exports_chunk_sets_in_graph = &mut self.used_exports_chunk_sets_in_graph; + let used_exports_chunk_sets_by_count = &mut self.used_exports_chunk_sets_by_count; + + for module in module_graph.modules().keys() { + let grouped_chunks = Self::group_chunks_by_exports( + module, + chunk_graph.get_module_chunks(*module).iter().cloned(), + module_graph, + chunk_by_ukey, + ); + for chunks in &grouped_chunks { + if chunks.is_empty() { + continue; + } + let chunk_key = get_key(chunks.iter()); + used_exports_chunk_sets_in_graph.insert(chunk_key, chunks.clone()); + } + + grouped_by_exports.insert(*module, grouped_chunks); + } + + for chunks in used_exports_chunk_sets_in_graph.values() { + let count = chunks.len(); + used_exports_chunk_sets_by_count + .entry(count as u32) + .and_modify(|set| set.push(chunks.clone())) + .or_insert(vec![chunks.clone()]); + } + + ( + used_exports_chunk_sets_in_graph, + used_exports_chunk_sets_by_count, + ) + } + + fn group_by_used_exports(&self) -> ChunkSetsInGraph { + ( + &self.used_exports_chunk_sets_in_graph, + &self.used_exports_chunk_sets_by_count, + ) + } +} + impl SplitChunksPlugin { #[tracing::instrument(skip_all)] pub(crate) fn find_best_module_group( @@ -83,37 +298,17 @@ impl SplitChunksPlugin { let module_group_map: DashMap = DashMap::default(); - // chunk_sets_in_graph: key: module, value: multiple chunks contains the module - // single_chunk_sets: chunkset of module that belongs to only one chunk - // chunk_sets_by_count: use chunkset len as key - let (chunk_sets_in_graph, chunk_sets_by_count) = - { Self::prepare_combination_maps(&module_graph, &compilation.chunk_graph) }; - - let combinations_cache = - DashMap::>, ChunksKeyHashBuilder>::default(); + let mut combinator = Combinator::default(); - let get_combination = |chunks_key: ChunksKey| match combinations_cache.entry(chunks_key) { - dashmap::mapref::entry::Entry::Occupied(entry) => entry.get().clone(), - dashmap::mapref::entry::Entry::Vacant(entry) => { - let chunks_set = chunk_sets_in_graph - .get(&chunks_key) - .expect("This should never happen, please file an issue"); - let mut result = vec![chunks_set.clone()]; - - for (count, array_of_set) in &chunk_sets_by_count { - if *count < chunks_set.len() { - for set in array_of_set { - if set.is_subset(chunks_set) { - result.push(set.clone()); - } - } - } - } + combinator.prepare_group_by_chunks(&module_graph, &compilation.chunk_graph); - entry.insert(result.clone()); - result - } - }; + if self + .cache_groups + .iter() + .any(|cache_group| cache_group.used_exports) + { + combinator.prepare_group_by_used_exports(&module_graph, &compilation.chunk_graph, chunk_db); + } module_graph.modules().values().par_bridge().map(|module| { let module = &***module; @@ -126,8 +321,6 @@ impl SplitChunksPlugin { return Ok(()); } - let chunks_key = Self::get_key(belong_to_chunks.iter()); - let mut temp = Vec::with_capacity(self.cache_groups.len()); for idx in 0..self.cache_groups.len() { @@ -171,7 +364,11 @@ impl SplitChunksPlugin { .filter(|(index, _)| temp[*index]); for (cache_group_index, (idx, cache_group)) in filtered.enumerate() { - let combs = get_combination(chunks_key); + let combs = combinator.get_combs( + module.identifier(), + &compilation.chunk_graph, + cache_group.used_exports + ); for chunk_combination in combs { if chunk_combination.is_empty() { @@ -221,7 +418,7 @@ impl SplitChunksPlugin { } let selected_chunks_key = - { Self::get_key(selected_chunks.iter().map(|chunk| &chunk.ukey)) }; + { get_key(selected_chunks.iter().map(|chunk| &chunk.ukey)) }; merge_matched_item_into_module_group_map( MatchedItem { @@ -389,48 +586,63 @@ impl SplitChunksPlugin { }); } - fn get_key<'a, I: Iterator>(chunks: I) -> ChunksKey { - let mut sorted_chunk_ukeys = chunks - .map(|chunk| { - // Increment each usize by 1 to avoid hashing the value 0 with FxHasher, which would always return a hash of 0 - chunk.as_u32() + 1 - }) - .collect::>(); - sorted_chunk_ukeys.sort_unstable(); - let mut hasher = FxHasher::default(); - for chunk_ukey in sorted_chunk_ukeys { - chunk_ukey.hash(&mut hasher); - } - hasher.finish() - } - - #[allow(clippy::type_complexity)] - fn prepare_combination_maps( - module_graph: &ModuleGraph, - chunk_graph: &ChunkGraph, - ) -> ( - HashMap, ChunksKeyHashBuilder>, - FxHashMap>>, - ) { - let mut chunk_sets_in_graph = - HashMap::, ChunksKeyHashBuilder>::default(); - - for module in module_graph.modules().keys() { - let chunks = chunk_graph.get_module_chunks(*module); - let chunk_key = Self::get_key(chunks.iter()); - chunk_sets_in_graph.insert(chunk_key, chunks.clone()); - } - - let mut chunk_sets_by_count = FxHashMap::>>::default(); - - for chunks in chunk_sets_in_graph.values() { - let count = chunks.len(); - chunk_sets_by_count - .entry(count) - .and_modify(|set| set.push(chunks.clone())) - .or_insert(vec![chunks.clone()]); - } - - (chunk_sets_in_graph, chunk_sets_by_count) - } + // #[allow(clippy::type_complexity)] + // fn prepare_combination_maps( + // module_graph: &ModuleGraph, + // chunk_graph: &ChunkGraph, + // used_exports: bool, + // chunk_by_ukey: &ChunkByUkey, + // ) -> ( + // HashMap, ChunksKeyHashBuilder>, + // FxHashMap>>, + // Option>>>, + // ) { + // let mut chunk_sets_in_graph = + // HashMap::, ChunksKeyHashBuilder>::default(); + // let mut chunk_sets_by_count = FxHashMap::>>::default(); + + // let mut grouped_by_exports_map: Option>>> = + // None; + + // if used_exports { + // let mut grouped_by_exports: FxHashMap>> = + // Default::default(); + // for module in module_graph.modules().keys() { + // let grouped_chunks = Self::group_chunks_by_exports( + // module, + // chunk_graph.get_module_chunks(*module).iter().cloned(), + // module_graph, + // chunk_by_ukey, + // ); + // for chunks in &grouped_chunks { + // let chunk_key = get_key(chunks.iter()); + // chunk_sets_in_graph.insert(chunk_key, chunks.clone()); + // } + + // grouped_by_exports.insert(*module, grouped_chunks); + // } + + // grouped_by_exports_map = Some(grouped_by_exports); + // } else { + // for module in module_graph.modules().keys() { + // let chunks = chunk_graph.get_module_chunks(*module); + // let chunk_key = get_key(chunks.iter()); + // chunk_sets_in_graph.insert(chunk_key, chunks.clone()); + // } + // } + + // for chunks in chunk_sets_in_graph.values() { + // let count = chunks.len(); + // chunk_sets_by_count + // .entry(count) + // .and_modify(|set| set.push(chunks.clone())) + // .or_insert(vec![chunks.clone()]); + // } + + // ( + // chunk_sets_in_graph, + // chunk_sets_by_count, + // grouped_by_exports_map, + // ) + // } } diff --git a/packages/rspack-test-tools/tests/__snapshots__/Defaults.test.js.snap b/packages/rspack-test-tools/tests/__snapshots__/Defaults.test.js.snap index 39fcbda58b8..bcce6d9dd1b 100644 --- a/packages/rspack-test-tools/tests/__snapshots__/Defaults.test.js.snap +++ b/packages/rspack-test-tools/tests/__snapshots__/Defaults.test.js.snap @@ -286,6 +286,7 @@ Object { "maxInitialRequests": Infinity, "minChunks": 1, "minSize": 10000, + "usedExports": false, }, "usedExports": false, }, diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/bar.js b/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/bar.js new file mode 100644 index 00000000000..f0fcc6a7aea --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/bar.js @@ -0,0 +1,9 @@ +import { bar } from './shared.js'; +import fs from 'fs' + +bar; +it('foo', () => { + const files = fs.readdirSync(__dirname); + const sharedChunks = files.filter(filename => filename.startsWith('shared-shared_js')).length + expect(sharedChunks).toBe(2); +}); diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/foo.js b/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/foo.js new file mode 100644 index 00000000000..d4feccc34dc --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/foo.js @@ -0,0 +1,2 @@ +import { foo } from './shared.js'; +foo; diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/rspack.config.js b/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/rspack.config.js new file mode 100644 index 00000000000..fb875bc4c73 --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/rspack.config.js @@ -0,0 +1,24 @@ +/** @type {import("@rspack/core").Configuration} */ +module.exports = { + entry: { + foo: "./foo", + bar: "./bar", + }, + output: { + filename: '[name].js' + }, + optimization: { + chunkIds: 'named', + usedExports: true, + splitChunks: { + chunks: "all", + minSize: 0, + cacheGroups: { + shared: { + test: /shared/, + minSize: 0, + } + } + } + } +}; diff --git a/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/shared.js b/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/shared.js new file mode 100644 index 00000000000..8ad8b2b285d --- /dev/null +++ b/packages/rspack-test-tools/tests/configCases/split-chunks/used-exports/shared.js @@ -0,0 +1,2 @@ +export const foo = 'bar' +export const bar = 'foo' diff --git a/packages/rspack-test-tools/tests/defaultsCases/mode/production.js b/packages/rspack-test-tools/tests/defaultsCases/mode/production.js index 0f917c52ebd..2315d3caa66 100644 --- a/packages/rspack-test-tools/tests/defaultsCases/mode/production.js +++ b/packages/rspack-test-tools/tests/defaultsCases/mode/production.js @@ -42,7 +42,9 @@ module.exports = { + "maxInitialRequests": 30, @@ ... @@ - "minSize": 10000, + - "usedExports": false, + "minSize": 20000, + + "usedExports": true, @@ ... @@ - "usedExports": false, + "usedExports": true, diff --git a/packages/rspack-test-tools/tests/defaultsCases/mode/undefined.js b/packages/rspack-test-tools/tests/defaultsCases/mode/undefined.js index 9b252e24eae..cb82a676fa9 100644 --- a/packages/rspack-test-tools/tests/defaultsCases/mode/undefined.js +++ b/packages/rspack-test-tools/tests/defaultsCases/mode/undefined.js @@ -42,7 +42,9 @@ module.exports = { + "maxInitialRequests": 30, @@ ... @@ - "minSize": 10000, + - "usedExports": false, + "minSize": 20000, + + "usedExports": true, @@ ... @@ - "usedExports": false, + "usedExports": true, diff --git a/packages/rspack/etc/api.md b/packages/rspack/etc/api.md index a021c5a1871..3e4bd69d394 100644 --- a/packages/rspack/etc/api.md +++ b/packages/rspack/etc/api.md @@ -7296,6 +7296,7 @@ const optimization: z.ZodObject<{ chunks: z.ZodOptional, z.ZodType]>, z.ZodFunction], z.ZodUnknown>, z.ZodBoolean>]>>; defaultSizeTypes: z.ZodOptional>; minChunks: z.ZodOptional; + usedExports: z.ZodOptional; name: z.ZodOptional]>, z.ZodFunction>], z.ZodUnknown>, z.ZodUnknown>]>>; minSize: z.ZodOptional]>>; maxSize: z.ZodOptional]>>; @@ -7306,6 +7307,7 @@ const optimization: z.ZodObject<{ chunks: z.ZodOptional, z.ZodType]>, z.ZodFunction], z.ZodUnknown>, z.ZodBoolean>]>>; defaultSizeTypes: z.ZodOptional>; minChunks: z.ZodOptional; + usedExports: z.ZodOptional; name: z.ZodOptional]>, z.ZodFunction>], z.ZodUnknown>, z.ZodUnknown>]>>; minSize: z.ZodOptional]>>; maxSize: z.ZodOptional]>>; @@ -7331,6 +7333,7 @@ const optimization: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7348,6 +7351,7 @@ const optimization: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7384,6 +7388,7 @@ const optimization: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7401,6 +7406,7 @@ const optimization: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7423,6 +7429,7 @@ const optimization: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7440,6 +7447,7 @@ const optimization: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7491,11 +7499,13 @@ const optimization: z.ZodObject<{ minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | WebpackPluginInstance | WebpackPluginFunction | null | undefined)[] | undefined; mergeDuplicateChunks?: boolean | undefined; + usedExports?: boolean | "global" | undefined; splitChunks?: false | { name?: string | false | ((args_0: Module | undefined, ...args_1: unknown[]) => unknown) | undefined; chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7513,6 +7523,7 @@ const optimization: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7543,7 +7554,6 @@ const optimization: z.ZodObject<{ providedExports?: boolean | undefined; concatenateModules?: boolean | undefined; innerGraph?: boolean | undefined; - usedExports?: boolean | "global" | undefined; mangleExports?: boolean | "deterministic" | "size" | undefined; nodeEnv?: string | false | undefined; }, { @@ -7552,11 +7562,13 @@ const optimization: z.ZodObject<{ minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | WebpackPluginInstance | WebpackPluginFunction | null | undefined)[] | undefined; mergeDuplicateChunks?: boolean | undefined; + usedExports?: boolean | "global" | undefined; splitChunks?: false | { name?: string | false | ((args_0: Module | undefined, ...args_1: unknown[]) => unknown) | undefined; chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7574,6 +7586,7 @@ const optimization: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7604,7 +7617,6 @@ const optimization: z.ZodObject<{ providedExports?: boolean | undefined; concatenateModules?: boolean | undefined; innerGraph?: boolean | undefined; - usedExports?: boolean | "global" | undefined; mangleExports?: boolean | "deterministic" | "size" | undefined; nodeEnv?: string | false | undefined; }>; @@ -7646,6 +7658,7 @@ const optimizationSplitChunksCacheGroup: z.ZodObject<{ chunks: z.ZodOptional, z.ZodType]>, z.ZodFunction], z.ZodUnknown>, z.ZodBoolean>]>>; defaultSizeTypes: z.ZodOptional>; minChunks: z.ZodOptional; + usedExports: z.ZodOptional; name: z.ZodOptional]>, z.ZodFunction>], z.ZodUnknown>, z.ZodUnknown>]>>; minSize: z.ZodOptional]>>; maxSize: z.ZodOptional]>>; @@ -7671,6 +7684,7 @@ const optimizationSplitChunksCacheGroup: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7688,6 +7702,7 @@ const optimizationSplitChunksCacheGroup: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7709,6 +7724,7 @@ const optimizationSplitChunksOptions: z.ZodObject<{ chunks: z.ZodOptional, z.ZodType]>, z.ZodFunction], z.ZodUnknown>, z.ZodBoolean>]>>; defaultSizeTypes: z.ZodOptional>; minChunks: z.ZodOptional; + usedExports: z.ZodOptional; name: z.ZodOptional]>, z.ZodFunction>], z.ZodUnknown>, z.ZodUnknown>]>>; minSize: z.ZodOptional]>>; maxSize: z.ZodOptional]>>; @@ -7719,6 +7735,7 @@ const optimizationSplitChunksOptions: z.ZodObject<{ chunks: z.ZodOptional, z.ZodType]>, z.ZodFunction], z.ZodUnknown>, z.ZodBoolean>]>>; defaultSizeTypes: z.ZodOptional>; minChunks: z.ZodOptional; + usedExports: z.ZodOptional; name: z.ZodOptional]>, z.ZodFunction>], z.ZodUnknown>, z.ZodUnknown>]>>; minSize: z.ZodOptional]>>; maxSize: z.ZodOptional]>>; @@ -7744,6 +7761,7 @@ const optimizationSplitChunksOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7761,6 +7779,7 @@ const optimizationSplitChunksOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7797,6 +7816,7 @@ const optimizationSplitChunksOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7814,6 +7834,7 @@ const optimizationSplitChunksOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7836,6 +7857,7 @@ const optimizationSplitChunksOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -7853,6 +7875,7 @@ const optimizationSplitChunksOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11191,8 +11214,8 @@ export const rspackOptions: z.ZodObject<{ hash?: boolean | undefined; all?: boolean | undefined; chunks?: boolean | undefined; - providedExports?: boolean | undefined; usedExports?: boolean | undefined; + providedExports?: boolean | undefined; preset?: boolean | "verbose" | "normal" | "none" | "errors-only" | "errors-warnings" | "minimal" | "detailed" | "summary" | undefined; assets?: boolean | undefined; modules?: boolean | undefined; @@ -11268,8 +11291,8 @@ export const rspackOptions: z.ZodObject<{ hash?: boolean | undefined; all?: boolean | undefined; chunks?: boolean | undefined; - providedExports?: boolean | undefined; usedExports?: boolean | undefined; + providedExports?: boolean | undefined; preset?: boolean | "verbose" | "normal" | "none" | "errors-only" | "errors-warnings" | "minimal" | "detailed" | "summary" | undefined; assets?: boolean | undefined; modules?: boolean | undefined; @@ -11352,6 +11375,7 @@ export const rspackOptions: z.ZodObject<{ chunks: z.ZodOptional, z.ZodType]>, z.ZodFunction], z.ZodUnknown>, z.ZodBoolean>]>>; defaultSizeTypes: z.ZodOptional>; minChunks: z.ZodOptional; + usedExports: z.ZodOptional; name: z.ZodOptional]>, z.ZodFunction>], z.ZodUnknown>, z.ZodUnknown>]>>; minSize: z.ZodOptional]>>; maxSize: z.ZodOptional]>>; @@ -11362,6 +11386,7 @@ export const rspackOptions: z.ZodObject<{ chunks: z.ZodOptional, z.ZodType]>, z.ZodFunction], z.ZodUnknown>, z.ZodBoolean>]>>; defaultSizeTypes: z.ZodOptional>; minChunks: z.ZodOptional; + usedExports: z.ZodOptional; name: z.ZodOptional]>, z.ZodFunction>], z.ZodUnknown>, z.ZodUnknown>]>>; minSize: z.ZodOptional]>>; maxSize: z.ZodOptional]>>; @@ -11387,6 +11412,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11404,6 +11430,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11440,6 +11467,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11457,6 +11485,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11479,6 +11508,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11496,6 +11526,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11547,11 +11578,13 @@ export const rspackOptions: z.ZodObject<{ minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | WebpackPluginInstance | WebpackPluginFunction | null | undefined)[] | undefined; mergeDuplicateChunks?: boolean | undefined; + usedExports?: boolean | "global" | undefined; splitChunks?: false | { name?: string | false | ((args_0: Module | undefined, ...args_1: unknown[]) => unknown) | undefined; chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11569,6 +11602,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11599,7 +11633,6 @@ export const rspackOptions: z.ZodObject<{ providedExports?: boolean | undefined; concatenateModules?: boolean | undefined; innerGraph?: boolean | undefined; - usedExports?: boolean | "global" | undefined; mangleExports?: boolean | "deterministic" | "size" | undefined; nodeEnv?: string | false | undefined; }, { @@ -11608,11 +11641,13 @@ export const rspackOptions: z.ZodObject<{ minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | WebpackPluginInstance | WebpackPluginFunction | null | undefined)[] | undefined; mergeDuplicateChunks?: boolean | undefined; + usedExports?: boolean | "global" | undefined; splitChunks?: false | { name?: string | false | ((args_0: Module | undefined, ...args_1: unknown[]) => unknown) | undefined; chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11630,6 +11665,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -11660,7 +11696,6 @@ export const rspackOptions: z.ZodObject<{ providedExports?: boolean | undefined; concatenateModules?: boolean | undefined; innerGraph?: boolean | undefined; - usedExports?: boolean | "global" | undefined; mangleExports?: boolean | "deterministic" | "size" | undefined; nodeEnv?: string | false | undefined; }>>; @@ -12984,8 +13019,8 @@ export const rspackOptions: z.ZodObject<{ hash?: boolean | undefined; all?: boolean | undefined; chunks?: boolean | undefined; - providedExports?: boolean | undefined; usedExports?: boolean | undefined; + providedExports?: boolean | undefined; preset?: boolean | "verbose" | "normal" | "none" | "errors-only" | "errors-warnings" | "minimal" | "detailed" | "summary" | undefined; assets?: boolean | undefined; modules?: boolean | undefined; @@ -13064,11 +13099,13 @@ export const rspackOptions: z.ZodObject<{ minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | WebpackPluginInstance | WebpackPluginFunction | null | undefined)[] | undefined; mergeDuplicateChunks?: boolean | undefined; + usedExports?: boolean | "global" | undefined; splitChunks?: false | { name?: string | false | ((args_0: Module | undefined, ...args_1: unknown[]) => unknown) | undefined; chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -13086,6 +13123,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -13116,7 +13154,6 @@ export const rspackOptions: z.ZodObject<{ providedExports?: boolean | undefined; concatenateModules?: boolean | undefined; innerGraph?: boolean | undefined; - usedExports?: boolean | "global" | undefined; mangleExports?: boolean | "deterministic" | "size" | undefined; nodeEnv?: string | false | undefined; } | undefined; @@ -13552,8 +13589,8 @@ export const rspackOptions: z.ZodObject<{ hash?: boolean | undefined; all?: boolean | undefined; chunks?: boolean | undefined; - providedExports?: boolean | undefined; usedExports?: boolean | undefined; + providedExports?: boolean | undefined; preset?: boolean | "verbose" | "normal" | "none" | "errors-only" | "errors-warnings" | "minimal" | "detailed" | "summary" | undefined; assets?: boolean | undefined; modules?: boolean | undefined; @@ -13632,11 +13669,13 @@ export const rspackOptions: z.ZodObject<{ minimize?: boolean | undefined; minimizer?: (false | "" | 0 | RspackPluginInstance | "..." | RspackPluginFunction | WebpackPluginInstance | WebpackPluginFunction | null | undefined)[] | undefined; mergeDuplicateChunks?: boolean | undefined; + usedExports?: boolean | "global" | undefined; splitChunks?: false | { name?: string | false | ((args_0: Module | undefined, ...args_1: unknown[]) => unknown) | undefined; chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -13654,6 +13693,7 @@ export const rspackOptions: z.ZodObject<{ chunks?: RegExp | "async" | "initial" | "all" | ((args_0: Chunk, ...args_1: unknown[]) => boolean) | undefined; defaultSizeTypes?: string[] | undefined; minChunks?: number | undefined; + usedExports?: boolean | undefined; minSize?: number | Record | undefined; maxSize?: number | Record | undefined; maxAsyncSize?: number | Record | undefined; @@ -13684,7 +13724,6 @@ export const rspackOptions: z.ZodObject<{ providedExports?: boolean | undefined; concatenateModules?: boolean | undefined; innerGraph?: boolean | undefined; - usedExports?: boolean | "global" | undefined; mangleExports?: boolean | "deterministic" | "size" | undefined; nodeEnv?: string | false | undefined; } | undefined; @@ -14341,8 +14380,8 @@ const statsOptions: z.ZodObject<{ hash?: boolean | undefined; all?: boolean | undefined; chunks?: boolean | undefined; - providedExports?: boolean | undefined; usedExports?: boolean | undefined; + providedExports?: boolean | undefined; preset?: boolean | "verbose" | "normal" | "none" | "errors-only" | "errors-warnings" | "minimal" | "detailed" | "summary" | undefined; assets?: boolean | undefined; modules?: boolean | undefined; @@ -14418,8 +14457,8 @@ const statsOptions: z.ZodObject<{ hash?: boolean | undefined; all?: boolean | undefined; chunks?: boolean | undefined; - providedExports?: boolean | undefined; usedExports?: boolean | undefined; + providedExports?: boolean | undefined; preset?: boolean | "verbose" | "normal" | "none" | "errors-only" | "errors-warnings" | "minimal" | "detailed" | "summary" | undefined; assets?: boolean | undefined; modules?: boolean | undefined; @@ -14605,8 +14644,8 @@ const statsValue: z.ZodUnion<[z.ZodUnion<[z.ZodBoolean, z.ZodEnum<["normal", "no hash?: boolean | undefined; all?: boolean | undefined; chunks?: boolean | undefined; - providedExports?: boolean | undefined; usedExports?: boolean | undefined; + providedExports?: boolean | undefined; preset?: boolean | "verbose" | "normal" | "none" | "errors-only" | "errors-warnings" | "minimal" | "detailed" | "summary" | undefined; assets?: boolean | undefined; modules?: boolean | undefined; @@ -14682,8 +14721,8 @@ const statsValue: z.ZodUnion<[z.ZodUnion<[z.ZodBoolean, z.ZodEnum<["normal", "no hash?: boolean | undefined; all?: boolean | undefined; chunks?: boolean | undefined; - providedExports?: boolean | undefined; usedExports?: boolean | undefined; + providedExports?: boolean | undefined; preset?: boolean | "verbose" | "normal" | "none" | "errors-only" | "errors-warnings" | "minimal" | "detailed" | "summary" | undefined; assets?: boolean | undefined; modules?: boolean | undefined; diff --git a/packages/rspack/src/config/defaults.ts b/packages/rspack/src/config/defaults.ts index f0767ac0ec9..3de849980a3 100644 --- a/packages/rspack/src/config/defaults.ts +++ b/packages/rspack/src/config/defaults.ts @@ -945,7 +945,7 @@ const applyOptimizationDefaults = ( ); D(splitChunks, "hidePathInfo", production); D(splitChunks, "chunks", "async"); - // D(splitChunks, "usedExports", optimization.usedExports === true); + D(splitChunks, "usedExports", optimization.usedExports === true); D(splitChunks, "minChunks", 1); F(splitChunks, "minSize", () => (production ? 20000 : 10000)); // F(splitChunks, "minRemainingSize", () => (development ? 0 : undefined)); diff --git a/packages/rspack/src/config/zod.ts b/packages/rspack/src/config/zod.ts index e78ed537fca..033d06e0781 100644 --- a/packages/rspack/src/config/zod.ts +++ b/packages/rspack/src/config/zod.ts @@ -1238,6 +1238,7 @@ const sharedOptimizationSplitChunksCacheGroup = { chunks: optimizationSplitChunksChunks.optional(), defaultSizeTypes: optimizationSplitChunksDefaultSizeTypes.optional(), minChunks: z.number().min(1).optional(), + usedExports: z.boolean().optional(), name: optimizationSplitChunksName.optional(), minSize: optimizationSplitChunksSizes.optional(), maxSize: optimizationSplitChunksSizes.optional(), diff --git a/tests/webpack-test/__snapshots__/StatsTestCases.basictest.js.snap b/tests/webpack-test/__snapshots__/StatsTestCases.basictest.js.snap index b1bdcdb7968..ad0369d1a48 100644 --- a/tests/webpack-test/__snapshots__/StatsTestCases.basictest.js.snap +++ b/tests/webpack-test/__snapshots__/StatsTestCases.basictest.js.snap @@ -175,25 +175,27 @@ multiple-vendors: multiple-vendors (Rspack x.x.x) compiled successfully all: - Entrypoint main 10.7 KiB = all/605.js 821 bytes all/main.js 9.88 KiB - Entrypoint a 11.2 KiB = all/272.js 1.33 KiB all/a.js 9.88 KiB - Entrypoint b 5.91 KiB = all/726.js 1.18 KiB all/b.js 4.73 KiB - Entrypoint c 5.91 KiB = all/29.js 1.18 KiB all/c.js 4.73 KiB - chunk (runtime: a, main) all/272.js (id hint: vendors) 165 bytes [initial] [rendered] split chunk (cache group: vendors) - > ./a ./index.js 1:0-47 + Entrypoint main 10.5 KiB = all/605.js 762 bytes all/main.js 9.8 KiB + Entrypoint a 10.3 KiB = all/272.js 501 bytes all/a.js 9.8 KiB + Entrypoint b 4.25 KiB = all/726.js 262 bytes all/b.js 3.99 KiB + Entrypoint c 4.24 KiB = all/29.js 261 bytes all/c.js 3.99 KiB + chunk (runtime: main) all/199.js (id hint: vendors) 116 bytes [rendered] split chunk (cache group: vendors) + > ./b ./index.js 2:0-47 + ./b.js 116 bytes [built] [code generated] + chunk (runtime: a) all/272.js (id hint: vendors) 165 bytes [initial] [rendered] split chunk (cache group: vendors) > ./a a ./a.js 165 bytes [built] [code generated] - chunk (runtime: c, main) all/29.js (id hint: vendors) 116 bytes [initial] [rendered] split chunk (cache group: vendors) - > ./c ./index.js 3:0-47 + chunk (runtime: c) all/29.js (id hint: vendors) 116 bytes [initial] [rendered] split chunk (cache group: vendors) > ./c c ./c.js 116 bytes [built] [code generated] chunk (runtime: main) all/310.js (id hint: vendors) 20 bytes [rendered] split chunk (cache group: vendors) > ./a ./index.js 1:0-47 > ./b ./index.js 2:0-47 ./node_modules/y.js 20 bytes [built] [code generated] - chunk (runtime: main) all/416.js (id hint: vendors) 20 bytes [rendered] split chunk (cache group: vendors) + chunk (runtime: main) all/364.js (id hint: vendors) 136 bytes [rendered] split chunk (cache group: vendors) > ./c ./index.js 3:0-47 - ./node_modules/z.js 20 bytes [built] [code generated] + dependent modules 20 bytes [dependent] 1 module + ./c.js 116 bytes [built] [code generated] chunk (runtime: main) all/457.js (id hint: vendors) 40 bytes [rendered] split chunk (cache group: vendors) > ./a ./index.js 1:0-47 > ./b ./index.js 2:0-47 @@ -208,24 +210,24 @@ all: chunk (runtime: main) all/605.js (id hint: vendors) 147 bytes [initial] [rendered] split chunk (cache group: vendors) > ./ main ./index.js 147 bytes [built] [code generated] - chunk (runtime: main) all/697.js (id hint: vendors) 20 bytes [rendered] split chunk (cache group: vendors) - > ./a ./index.js 1:0-47 - ./e.js 20 bytes [built] [code generated] - chunk (runtime: b, main) all/726.js (id hint: vendors) 116 bytes [initial] [rendered] split chunk (cache group: vendors) - > ./b ./index.js 2:0-47 + chunk (runtime: b) all/726.js (id hint: vendors) 116 bytes [initial] [rendered] split chunk (cache group: vendors) > ./b b ./b.js 116 bytes [built] [code generated] - chunk (runtime: a) all/a.js (a) 8.06 KiB [entry] [rendered] + chunk (runtime: a) all/a.js (a) 8.03 KiB [entry] [rendered] > ./a a - chunk (runtime: b) all/b.js (b) 3.16 KiB [entry] [rendered] + chunk (runtime: b) all/b.js (b) 2.58 KiB [entry] [rendered] > ./b b - chunk (runtime: c) all/c.js (c) 3.16 KiB [entry] [rendered] + chunk (runtime: c) all/c.js (c) 2.58 KiB [entry] [rendered] > ./c c chunk (runtime: a, main) all/889.js (id hint: vendors) 45 bytes [rendered] split chunk (cache group: vendors) > ./g ./a.js 6:0-47 ./g.js 45 bytes [built] [code generated] - chunk (runtime: main) all/main.js (main) 8.06 KiB [entry] [rendered] + chunk (runtime: main) all/main.js (main) 8.03 KiB [entry] [rendered] > ./ main + chunk (runtime: main) all/910.js (id hint: vendors) 185 bytes [rendered] split chunk (cache group: vendors) + > ./a ./index.js 1:0-47 + dependent modules 20 bytes [dependent] 1 module + ./a.js 165 bytes [built] [code generated] all (Rspack x.x.x) compiled successfully" `; @@ -546,11 +548,11 @@ runtime modules 2.59 KiB 3 modules ./a.js 18 bytes [built] [code generated] Rspack x.x.x compiled successfully in X.23 -asset b-runtime~main-fe10e0b865c55df180b8.js 4.39 KiB [emitted] [immutable] (name: runtime~main) +asset b-runtime~main-48886b0bb08b3987a553.js 4.39 KiB [emitted] [immutable] (name: runtime~main) asset b-all-b_js-242da217bb553f79303f.js 461 bytes [emitted] [immutable] (id hint: all) -asset b-main-236b715ba81f9430f0c7.js 420 bytes [emitted] [immutable] (name: main) +asset b-main-72ac2a7c5326395bcc89.js 420 bytes [emitted] [immutable] (name: main) asset b-vendors-node_modules_vendor_js-97d43f84c65cc0e25938.js 173 bytes [emitted] [immutable] (id hint: vendors) -Entrypoint main 5.42 KiB = b-runtime~main-fe10e0b865c55df180b8.js 4.39 KiB b-vendors-node_modules_vendor_js-97d43f84c65cc0e25938.js 173 bytes b-all-b_js-242da217bb553f79303f.js 461 bytes b-main-236b715ba81f9430f0c7.js 420 bytes +Entrypoint main 5.42 KiB = b-runtime~main-48886b0bb08b3987a553.js 4.39 KiB b-vendors-node_modules_vendor_js-97d43f84c65cc0e25938.js 173 bytes b-all-b_js-242da217bb553f79303f.js 461 bytes b-main-72ac2a7c5326395bcc89.js 420 bytes runtime modules 3.17 KiB 5 modules cacheable modules 40 bytes ./b.js 17 bytes [built] [code generated] @@ -1731,57 +1733,55 @@ exports[`StatsTestCases should print correct stats for split-chunks 1`] = ` default (Rspack x.x.x) compiled successfully all-chunks: - Entrypoint main 9.26 KiB = all-chunks/main.js - Entrypoint a 11.2 KiB = all-chunks/272.js 1.33 KiB all-chunks/a.js 9.92 KiB - Entrypoint b 5.91 KiB = all-chunks/async-b.js 1.18 KiB all-chunks/b.js 4.73 KiB - Entrypoint c 5.91 KiB = all-chunks/async-c.js 1.18 KiB all-chunks/c.js 4.73 KiB - chunk (runtime: c, main) all-chunks/async-c.js (async-c) (id hint: ) 116 bytes <{909}> ={416}= ={418}= ={581}= ={753}= ={76}= [initial] [rendered] + Entrypoint main 9.16 KiB = all-chunks/main.js + Entrypoint a 8.72 KiB = all-chunks/a.js + Entrypoint b 196 bytes = all-chunks/b.js + Entrypoint c 196 bytes = all-chunks/c.js + chunk (runtime: main) all-chunks/async-c.js (async-c) 116 bytes <{909}> ={416}= ={418}= ={581}= ={753}= [rendered] > ./c ./index.js 3:0-47 - > ./c c ./c.js 116 bytes [built] [code generated] - chunk (runtime: main) all-chunks/async-a.js (async-a) 20 bytes <{909}> ={272}= ={310}= ={418}= ={753}= >{581}< >{912}< [rendered] + chunk (runtime: main) all-chunks/async-a.js (async-a) 185 bytes <{909}> ={310}= ={418}= ={753}= >{581}< >{912}< [rendered] > ./a ./index.js 1:0-47 - ./e.js 20 bytes [built] [code generated] - chunk (runtime: b, main) all-chunks/async-b.js (async-b) (id hint: ) 116 bytes <{909}> ={310}= ={418}= ={581}= ={751}= ={753}= [initial] [rendered] + dependent modules 20 bytes [dependent] 1 module + ./a.js 165 bytes [built] [code generated] + chunk (runtime: main) all-chunks/async-b.js (async-b) 116 bytes <{909}> ={310}= ={418}= ={581}= ={753}= [rendered] > ./b ./index.js 2:0-47 - > ./b b ./b.js 116 bytes [built] [code generated] - chunk (runtime: a, main) all-chunks/272.js (id hint: ) 165 bytes <{909}> ={250}= ={310}= ={418}= ={74}= ={753}= >{581}< >{912}< [initial] [rendered] split chunk (cache group: default) - > ./a ./index.js 1:0-47 - > ./a a - ./a.js 165 bytes [built] [code generated] - chunk (runtime: main) all-chunks/310.js (id hint: vendors) 20 bytes <{909}> ={250}= ={262}= ={272}= ={418}= ={581}= ={753}= >{581}< >{912}< [rendered] split chunk (cache group: defaultVendors) + chunk (runtime: main) all-chunks/310.js (id hint: vendors) 20 bytes <{909}> ={250}= ={262}= ={418}= ={581}= ={753}= >{581}< >{912}< [rendered] split chunk (cache group: defaultVendors) > ./a ./index.js 1:0-47 > ./b ./index.js 2:0-47 ./node_modules/y.js 20 bytes [built] [code generated] chunk (runtime: main) all-chunks/416.js (id hint: vendors) 20 bytes <{909}> ={172}= ={418}= ={581}= ={753}= [rendered] split chunk (cache group: defaultVendors) > ./c ./index.js 3:0-47 ./node_modules/z.js 20 bytes [built] [code generated] - chunk (runtime: main) all-chunks/418.js (id hint: vendors) 20 bytes <{909}> ={172}= ={250}= ={262}= ={272}= ={310}= ={416}= ={581}= ={753}= >{581}< >{912}< [rendered] split chunk (cache group: defaultVendors) + chunk (runtime: main) all-chunks/418.js (id hint: vendors) 20 bytes <{909}> ={172}= ={250}= ={262}= ={310}= ={416}= ={581}= ={753}= >{581}< >{912}< [rendered] split chunk (cache group: defaultVendors) > ./a ./index.js 1:0-47 > ./b ./index.js 2:0-47 > ./c ./index.js 3:0-47 ./node_modules/x.js 20 bytes [built] [code generated] - chunk (runtime: a, main) all-chunks/581.js (id hint: ) 20 bytes <{250}> <{272}> <{310}> <{418}> <{74}> <{753}> <{909}> ={172}= ={262}= ={310}= ={416}= ={418}= ={753}= ={912}= [rendered] split chunk (cache group: default) + chunk (runtime: a, main) all-chunks/581.js (id hint: ) 20 bytes <{250}> <{310}> <{418}> <{74}> <{753}> <{909}> ={172}= ={262}= ={310}= ={416}= ={418}= ={753}= ={912}= [rendered] split chunk (cache group: default) > ./b ./index.js 2:0-47 > ./c ./index.js 3:0-47 > ./g ./a.js 6:0-47 ./f.js 20 bytes [built] [code generated] - chunk (runtime: a) all-chunks/a.js (a) 8.1 KiB ={272}= >{581}< >{912}< [entry] [rendered] + chunk (runtime: a) all-chunks/a.js (a) 165 bytes (javascript) 6.99 KiB (runtime) >{581}< >{912}< [entry] [rendered] > ./a a - chunk (runtime: b) all-chunks/b.js (b) 3.16 KiB ={262}= [entry] [rendered] + ./a.js 165 bytes [built] [code generated] + chunk (runtime: b) all-chunks/b.js (b) 116 bytes [entry] [rendered] > ./b b - chunk (runtime: main) all-chunks/753.js (id hint: ) 20 bytes <{909}> ={172}= ={250}= ={262}= ={272}= ={310}= ={416}= ={418}= ={581}= >{581}< >{912}< [rendered] split chunk (cache group: default) + ./b.js 116 bytes [built] [code generated] + chunk (runtime: main) all-chunks/753.js (id hint: ) 20 bytes <{909}> ={172}= ={250}= ={262}= ={310}= ={416}= ={418}= ={581}= >{581}< >{912}< [rendered] split chunk (cache group: default) > ./a ./index.js 1:0-47 > ./b ./index.js 2:0-47 > ./c ./index.js 3:0-47 ./d.js 20 bytes [built] [code generated] - chunk (runtime: c) all-chunks/c.js (c) 3.16 KiB ={172}= [entry] [rendered] + chunk (runtime: c) all-chunks/c.js (c) 116 bytes [entry] [rendered] > ./c c - chunk (runtime: main) all-chunks/main.js (main) 147 bytes (javascript) 7.07 KiB (runtime) >{172}< >{250}< >{262}< >{272}< >{310}< >{416}< >{418}< >{581}< >{753}< [entry] [rendered] + ./c.js 116 bytes [built] [code generated] + chunk (runtime: main) all-chunks/main.js (main) 147 bytes (javascript) 7.04 KiB (runtime) >{172}< >{250}< >{262}< >{310}< >{416}< >{418}< >{581}< >{753}< [entry] [rendered] > ./ main ./index.js 147 bytes [built] [code generated] - chunk (runtime: a, main) all-chunks/async-g.js (async-g) 45 bytes <{250}> <{272}> <{310}> <{418}> <{74}> <{753}> ={581}= [rendered] + chunk (runtime: a, main) all-chunks/async-g.js (async-g) 45 bytes <{250}> <{310}> <{418}> <{74}> <{753}> ={581}= [rendered] > ./g ./a.js 6:0-47 ./g.js 45 bytes [built] [code generated] all-chunks (Rspack x.x.x) compiled successfully @@ -1850,77 +1850,73 @@ manual: manual (Rspack x.x.x) compiled successfully name-too-long: - Entrypoint main 9.26 KiB = name-too-long/main.js - Entrypoint aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 11.3 KiB = name-too-long/272.js 1.33 KiB name-too-long/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.js 9.92 KiB - Entrypoint bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 5.91 KiB = name-too-long/async-b.js 1.18 KiB name-too-long/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.js 4.73 KiB - Entrypoint cccccccccccccccccccccccccccccc 5.91 KiB = name-too-long/async-c.js 1.18 KiB name-too-long/cccccccccccccccccccccccccccccc.js 4.73 KiB - chunk (runtime: cccccccccccccccccccccccccccccc, main) name-too-long/async-c.js (async-c) (id hint: ) 116 bytes <{909}> ={325}= ={416}= ={418}= ={581}= ={753}= [initial] [rendered] + Entrypoint main 9.16 KiB = name-too-long/main.js + Entrypoint aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 8.73 KiB = name-too-long/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.js + Entrypoint bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 196 bytes = name-too-long/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.js + Entrypoint cccccccccccccccccccccccccccccc 196 bytes = name-too-long/cccccccccccccccccccccccccccccc.js + chunk (runtime: main) name-too-long/async-c.js (async-c) 116 bytes <{909}> ={416}= ={418}= ={581}= ={753}= [rendered] > ./c ./index.js 3:0-47 - > ./c cccccccccccccccccccccccccccccc ./c.js 116 bytes [built] [code generated] - chunk (runtime: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) name-too-long/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.js (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) 3.16 KiB ={262}= [entry] [rendered] - > ./b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb - chunk (runtime: main) name-too-long/async-a.js (async-a) 20 bytes <{909}> ={272}= ={310}= ={418}= ={753}= >{581}< >{912}< [rendered] - > ./a ./index.js 1:0-47 - ./e.js 20 bytes [built] [code generated] - chunk (runtime: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, main) name-too-long/async-b.js (async-b) (id hint: ) 116 bytes <{909}> ={225}= ={310}= ={418}= ={581}= ={753}= [initial] [rendered] - > ./b ./index.js 2:0-47 + chunk (runtime: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) name-too-long/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.js (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) 116 bytes [entry] [rendered] > ./b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ./b.js 116 bytes [built] [code generated] - chunk (runtime: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, main) name-too-long/272.js (id hint: ) 165 bytes <{909}> ={250}= ={310}= ={418}= ={753}= ={959}= >{581}< >{912}< [initial] [rendered] split chunk (cache group: default) + chunk (runtime: main) name-too-long/async-a.js (async-a) 185 bytes <{909}> ={310}= ={418}= ={753}= >{581}< >{912}< [rendered] > ./a ./index.js 1:0-47 - > ./a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + dependent modules 20 bytes [dependent] 1 module ./a.js 165 bytes [built] [code generated] - chunk (runtime: main) name-too-long/310.js (id hint: vendors) 20 bytes <{909}> ={250}= ={262}= ={272}= ={418}= ={581}= ={753}= >{581}< >{912}< [rendered] split chunk (cache group: defaultVendors) + chunk (runtime: main) name-too-long/async-b.js (async-b) 116 bytes <{909}> ={310}= ={418}= ={581}= ={753}= [rendered] + > ./b ./index.js 2:0-47 + ./b.js 116 bytes [built] [code generated] + chunk (runtime: main) name-too-long/310.js (id hint: vendors) 20 bytes <{909}> ={250}= ={262}= ={418}= ={581}= ={753}= >{581}< >{912}< [rendered] split chunk (cache group: defaultVendors) > ./a ./index.js 1:0-47 > ./b ./index.js 2:0-47 ./node_modules/y.js 20 bytes [built] [code generated] - chunk (runtime: cccccccccccccccccccccccccccccc) name-too-long/cccccccccccccccccccccccccccccc.js (cccccccccccccccccccccccccccccc) 3.16 KiB ={172}= [entry] [rendered] + chunk (runtime: cccccccccccccccccccccccccccccc) name-too-long/cccccccccccccccccccccccccccccc.js (cccccccccccccccccccccccccccccc) 116 bytes [entry] [rendered] > ./c cccccccccccccccccccccccccccccc + ./c.js 116 bytes [built] [code generated] chunk (runtime: main) name-too-long/416.js (id hint: vendors) 20 bytes <{909}> ={172}= ={418}= ={581}= ={753}= [rendered] split chunk (cache group: defaultVendors) > ./c ./index.js 3:0-47 ./node_modules/z.js 20 bytes [built] [code generated] - chunk (runtime: main) name-too-long/418.js (id hint: vendors) 20 bytes <{909}> ={172}= ={250}= ={262}= ={272}= ={310}= ={416}= ={581}= ={753}= >{581}< >{912}< [rendered] split chunk (cache group: defaultVendors) + chunk (runtime: main) name-too-long/418.js (id hint: vendors) 20 bytes <{909}> ={172}= ={250}= ={262}= ={310}= ={416}= ={581}= ={753}= >{581}< >{912}< [rendered] split chunk (cache group: defaultVendors) > ./a ./index.js 1:0-47 > ./b ./index.js 2:0-47 > ./c ./index.js 3:0-47 ./node_modules/x.js 20 bytes [built] [code generated] - chunk (runtime: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, main) name-too-long/581.js (id hint: ) 20 bytes <{250}> <{272}> <{310}> <{418}> <{753}> <{909}> <{959}> ={172}= ={262}= ={310}= ={416}= ={418}= ={753}= ={912}= [rendered] split chunk (cache group: default) + chunk (runtime: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, main) name-too-long/581.js (id hint: ) 20 bytes <{250}> <{310}> <{418}> <{753}> <{909}> <{959}> ={172}= ={262}= ={310}= ={416}= ={418}= ={753}= ={912}= [rendered] split chunk (cache group: default) > ./b ./index.js 2:0-47 > ./c ./index.js 3:0-47 > ./g ./a.js 6:0-47 ./f.js 20 bytes [built] [code generated] - chunk (runtime: main) name-too-long/753.js (id hint: ) 20 bytes <{909}> ={172}= ={250}= ={262}= ={272}= ={310}= ={416}= ={418}= ={581}= >{581}< >{912}< [rendered] split chunk (cache group: default) + chunk (runtime: main) name-too-long/753.js (id hint: ) 20 bytes <{909}> ={172}= ={250}= ={262}= ={310}= ={416}= ={418}= ={581}= >{581}< >{912}< [rendered] split chunk (cache group: default) > ./a ./index.js 1:0-47 > ./b ./index.js 2:0-47 > ./c ./index.js 3:0-47 ./d.js 20 bytes [built] [code generated] - chunk (runtime: main) name-too-long/main.js (main) 147 bytes (javascript) 7.07 KiB (runtime) >{172}< >{250}< >{262}< >{272}< >{310}< >{416}< >{418}< >{581}< >{753}< [entry] [rendered] + chunk (runtime: main) name-too-long/main.js (main) 147 bytes (javascript) 7.04 KiB (runtime) >{172}< >{250}< >{262}< >{310}< >{416}< >{418}< >{581}< >{753}< [entry] [rendered] > ./ main ./index.js 147 bytes [built] [code generated] - chunk (runtime: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, main) name-too-long/async-g.js (async-g) 45 bytes <{250}> <{272}> <{310}> <{418}> <{753}> <{959}> ={581}= [rendered] + chunk (runtime: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, main) name-too-long/async-g.js (async-g) 45 bytes <{250}> <{310}> <{418}> <{753}> <{959}> ={581}= [rendered] > ./g ./a.js 6:0-47 ./g.js 45 bytes [built] [code generated] - chunk (runtime: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) name-too-long/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.js (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) 8.1 KiB ={272}= >{581}< >{912}< [entry] [rendered] + chunk (runtime: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) name-too-long/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.js (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) 165 bytes (javascript) 6.99 KiB (runtime) >{581}< >{912}< [entry] [rendered] > ./a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ./a.js 165 bytes [built] [code generated] name-too-long (Rspack x.x.x) compiled successfully custom-chunks-filter: - Entrypoint main 9.24 KiB = custom-chunks-filter/main.js + Entrypoint main 9.17 KiB = custom-chunks-filter/main.js Entrypoint a 8.73 KiB = custom-chunks-filter/a.js - Entrypoint b 5.91 KiB = custom-chunks-filter/async-b.js 1.18 KiB custom-chunks-filter/b.js 4.73 KiB - Entrypoint c 5.91 KiB = custom-chunks-filter/async-c.js 1.18 KiB custom-chunks-filter/c.js 4.73 KiB - chunk (runtime: c, main) custom-chunks-filter/async-c.js (async-c) (id hint: ) 116 bytes <{909}> ={416}= ={418}= ={581}= ={753}= ={76}= [initial] [rendered] + Entrypoint b 196 bytes = custom-chunks-filter/b.js + Entrypoint c 196 bytes = custom-chunks-filter/c.js + chunk (runtime: main) custom-chunks-filter/async-c.js (async-c) 116 bytes <{909}> ={416}= ={418}= ={581}= ={753}= [rendered] > ./c ./index.js 3:0-47 - > ./c c ./c.js 116 bytes [built] [code generated] chunk (runtime: main) custom-chunks-filter/async-a.js (async-a) 185 bytes <{909}> ={310}= ={418}= ={753}= >{581}< >{912}< [rendered] > ./a ./index.js 1:0-47 dependent modules 20 bytes [dependent] 1 module ./a.js 165 bytes [built] [code generated] - chunk (runtime: b, main) custom-chunks-filter/async-b.js (async-b) (id hint: ) 116 bytes <{909}> ={310}= ={418}= ={581}= ={751}= ={753}= [initial] [rendered] + chunk (runtime: main) custom-chunks-filter/async-b.js (async-b) 116 bytes <{909}> ={310}= ={418}= ={581}= ={753}= [rendered] > ./b ./index.js 2:0-47 - > ./b b ./b.js 116 bytes [built] [code generated] chunk (runtime: main) custom-chunks-filter/310.js (id hint: vendors) 20 bytes <{909}> ={250}= ={262}= ={418}= ={581}= ={753}= >{581}< >{912}< [rendered] split chunk (cache group: defaultVendors) > ./a ./index.js 1:0-47 @@ -1942,16 +1938,18 @@ custom-chunks-filter: chunk (runtime: a) custom-chunks-filter/a.js (a) 165 bytes (javascript) 7 KiB (runtime) >{581}< >{912}< [entry] [rendered] > ./a a ./a.js 165 bytes [built] [code generated] - chunk (runtime: b) custom-chunks-filter/b.js (b) 3.16 KiB ={262}= [entry] [rendered] + chunk (runtime: b) custom-chunks-filter/b.js (b) 116 bytes [entry] [rendered] > ./b b + ./b.js 116 bytes [built] [code generated] chunk (runtime: main) custom-chunks-filter/753.js (id hint: ) 20 bytes <{909}> ={172}= ={250}= ={262}= ={310}= ={416}= ={418}= ={581}= >{581}< >{912}< [rendered] split chunk (cache group: default) > ./a ./index.js 1:0-47 > ./b ./index.js 2:0-47 > ./c ./index.js 3:0-47 ./d.js 20 bytes [built] [code generated] - chunk (runtime: c) custom-chunks-filter/c.js (c) 3.16 KiB ={172}= [entry] [rendered] + chunk (runtime: c) custom-chunks-filter/c.js (c) 116 bytes [entry] [rendered] > ./c c - chunk (runtime: main) custom-chunks-filter/main.js (main) 147 bytes (javascript) 7.08 KiB (runtime) >{172}< >{250}< >{262}< >{310}< >{416}< >{418}< >{581}< >{753}< [entry] [rendered] + ./c.js 116 bytes [built] [code generated] + chunk (runtime: main) custom-chunks-filter/main.js (main) 147 bytes (javascript) 7.05 KiB (runtime) >{172}< >{250}< >{262}< >{310}< >{416}< >{418}< >{581}< >{753}< [entry] [rendered] > ./ main ./index.js 147 bytes [built] [code generated] chunk (runtime: a, main) custom-chunks-filter/async-g.js (async-g) 45 bytes <{250}> <{310}> <{418}> <{74}> <{753}> ={581}= [rendered] @@ -1961,7 +1959,7 @@ custom-chunks-filter: custom-chunks-filter-in-cache-groups: Entrypoint main 8.95 KiB = custom-chunks-filter-in-cache-groups/main.js - Entrypoint a 9.37 KiB = custom-chunks-filter-in-cache-groups/a.js + Entrypoint a 10.9 KiB = custom-chunks-filter-in-cache-groups/598.js 400 bytes custom-chunks-filter-in-cache-groups/a.js 10.5 KiB Entrypoint b 5.65 KiB = custom-chunks-filter-in-cache-groups/vendors.js 892 bytes custom-chunks-filter-in-cache-groups/b.js 4.78 KiB Entrypoint c 5.65 KiB = custom-chunks-filter-in-cache-groups/vendors.js 892 bytes custom-chunks-filter-in-cache-groups/c.js 4.77 KiB chunk (runtime: main) custom-chunks-filter-in-cache-groups/async-c.js (async-c) 156 bytes <{909}> ={192}= [rendered] @@ -1991,15 +1989,20 @@ custom-chunks-filter-in-cache-groups: > ./b ./index.js 2:0-47 dependent modules 40 bytes [dependent] 2 modules ./b.js 116 bytes [built] [code generated] - chunk (runtime: a) custom-chunks-filter-in-cache-groups/a.js (a) 225 bytes (javascript) 6.98 KiB (runtime) >{912}< [entry] [rendered] + chunk (runtime: a) custom-chunks-filter-in-cache-groups/598.js (id hint: vendors) 60 bytes ={74}= >{912}< [initial] [rendered] split chunk (cache group: defaultVendors) > ./a a > x a > y a > z a - dependent modules 40 bytes [dependent] 2 modules - cacheable modules 185 bytes - ./a.js 165 bytes [built] [code generated] - ./node_modules/z.js 20 bytes [built] [code generated] + ./node_modules/x.js 20 bytes [built] [code generated] + ./node_modules/y.js 20 bytes [built] [code generated] + ./node_modules/z.js 20 bytes [built] [code generated] + chunk (runtime: a) custom-chunks-filter-in-cache-groups/a.js (a) 165 bytes (javascript) 8.06 KiB (runtime) ={598}= >{912}< [entry] [rendered] + > ./a a + > x a + > y a + > z a + ./a.js 165 bytes [built] [code generated] chunk (runtime: b) custom-chunks-filter-in-cache-groups/b.js (b) 116 bytes (javascript) 2.86 KiB (runtime) ={192}= [entry] [rendered] > ./b b > x b @@ -2015,7 +2018,7 @@ custom-chunks-filter-in-cache-groups: chunk (runtime: main) custom-chunks-filter-in-cache-groups/main.js (main) 147 bytes (javascript) 7.07 KiB (runtime) >{172}< >{192}< >{250}< >{262}< [entry] [rendered] > ./ main ./index.js 147 bytes [built] [code generated] - chunk (runtime: a, main) custom-chunks-filter-in-cache-groups/async-g.js (async-g) 65 bytes <{192}> <{250}> <{74}> [rendered] + chunk (runtime: a, main) custom-chunks-filter-in-cache-groups/async-g.js (async-g) 65 bytes <{192}> <{250}> <{598}> <{74}> [rendered] > ./g ./a.js 6:0-47 dependent modules 20 bytes [dependent] 1 module ./g.js 45 bytes [built] [code generated] @@ -2272,20 +2275,20 @@ Rspack x.x.x compiled successfully" exports[`StatsTestCases should print correct stats for split-chunks-runtime-specific 1`] = ` "used-exports: - asset used-exports-c.js 4.67 KiB [emitted] (name: c) - asset used-exports-b.js 4.67 KiB [emitted] (name: b) - asset used-exports-a.js 4.67 KiB [emitted] (name: a) - asset used-exports-572.js 533 bytes [emitted] - Entrypoint a 5.19 KiB = used-exports-572.js 533 bytes used-exports-a.js 4.67 KiB - Entrypoint b 5.19 KiB = used-exports-572.js 533 bytes used-exports-b.js 4.67 KiB - Entrypoint c 5.2 KiB = used-exports-572.js 533 bytes used-exports-c.js 4.67 KiB - chunk (runtime: a, b, c) used-exports-572.js (id hint: ) 72 bytes [initial] [rendered] split chunk (cache group: default) + asset used-exports-c.js 4.6 KiB [emitted] (name: c) + asset used-exports-b.js 4.6 KiB [emitted] (name: b) + asset used-exports-572.js 370 bytes [emitted] + asset used-exports-a.js 249 bytes [emitted] (name: a) + Entrypoint a 249 bytes = used-exports-a.js + Entrypoint b 4.96 KiB = used-exports-572.js 370 bytes used-exports-b.js 4.6 KiB + Entrypoint c 4.96 KiB = used-exports-572.js 370 bytes used-exports-c.js 4.6 KiB + chunk (runtime: b, c) used-exports-572.js (id hint: ) 72 bytes [initial] [rendered] split chunk (cache group: default) ./objects.js 72 bytes [built] [code generated] - chunk (runtime: a) used-exports-a.js (a) 54 bytes (javascript) 2.89 KiB (runtime) [entry] [rendered] - ./a.js 54 bytes [built] [code generated] - chunk (runtime: b) used-exports-b.js (b) 54 bytes (javascript) 2.89 KiB (runtime) [entry] [rendered] + chunk (runtime: a) used-exports-a.js (a) 126 bytes [entry] [rendered] + ./a.js + 1 modules 126 bytes [code generated] + chunk (runtime: b) used-exports-b.js (b) 54 bytes (javascript) 2.86 KiB (runtime) [entry] [rendered] ./b.js 54 bytes [built] [code generated] - chunk (runtime: c) used-exports-c.js (c) 59 bytes (javascript) 2.89 KiB (runtime) [entry] [rendered] + chunk (runtime: c) used-exports-c.js (c) 59 bytes (javascript) 2.86 KiB (runtime) [entry] [rendered] ./c.js 59 bytes [built] [code generated] used-exports (Rspack x.x.x) compiled successfully in X.23 diff --git a/website/docs/en/plugins/webpack/split-chunks-plugin.mdx b/website/docs/en/plugins/webpack/split-chunks-plugin.mdx index b6022069687..ada966bdfc2 100644 --- a/website/docs/en/plugins/webpack/split-chunks-plugin.mdx +++ b/website/docs/en/plugins/webpack/split-chunks-plugin.mdx @@ -227,6 +227,56 @@ If the `splitChunks.name` matches an [entry point](/config/entry) name, the entr ::: +### splitChunks.usedExports + + + +- **Type:** `boolean` +- **Default:** Value of [optimization.usedExports](/config/optimization#optimizationusedexports) + +Enabling this configuration, the splitting of chunks will be grouped based on the usage of modules exports in different runtimes, ensuring the optimal loading size in each runtime. + +For example, if there are three entry points named `foo`, `bar`, and `baz`, they all depend on the same module called `shared`. However, `foo` and `bar` depend on the export `value1` from `shared`, while `baz` depends on the export `value2` from `shared`. + +```js title=foo.js +import { value1 } from 'shared'; +value1; +``` + +```js title=bar.js +import { value1 } from 'shared'; +value1; +``` + +```js title=baz.js +import { value2 } from 'shared'; +value2; +``` + +In the default strategy, the `shared` module appears in 3 chunks. If it meets the [minSize for splitting](plugins/webpack/split-chunks-plugin#splitchunksminsize), then the `shared` module should be extracted into a separate chunk. + +``` +chunk foo, chunk bar + \ + chunk shared (exports value1 and value2) + / +chunk baz +``` + +However, this would result in none of the three entry points having the optimal loaded size. Loading the `shared` module from the `foo` and `bar` entries would unnecessarily load the export `value2`, while loading from the `baz` entry would unnecessarily load the export `value1`. + +When the `splitChunks.usedExports` optimization is enabled, it analyzes which exports of the `shared` module are used in different entries. It finds that the exports used in `foo` and `bar` are different from those in `baz`, resulting in the creation of two distinct chunks, one corresponding to the entries `foo` and `bar`, and the other corresponding to the entry `baz`. + +``` +chunk foo, chunk bar + \ + chunk shared-1 (exports only value1) + +chunk baz + \ + chunk shared-2 (exports only value2) +``` + ### splitChunks.cacheGroups Cache groups can inherit and/or override any options from `splitChunks.*`; but `test`, `priority` and `reuseExistingChunk` can only be configured on cache group level. To disable any of the default cache groups, set them to `false`. diff --git a/website/docs/zh/plugins/webpack/split-chunks-plugin.mdx b/website/docs/zh/plugins/webpack/split-chunks-plugin.mdx index 0af97bbd109..464687ec701 100644 --- a/website/docs/zh/plugins/webpack/split-chunks-plugin.mdx +++ b/website/docs/zh/plugins/webpack/split-chunks-plugin.mdx @@ -217,6 +217,56 @@ module.exports = { ::: +### splitChunks.usedExports + + + +- **类型:** `boolean` +- **默认值:** 默认值为 [optimization.usedExports](/config/optimization#optimizationusedexports) + +开启该配置后,在拆分 chunk 将根据 module 在不同 runtime 中导出的使用情况进行分组,保持在不同 runtime 中都是最优的加载体积。 + +举个例子,如果一次构建中有 3 个入口分别名为 foo, bar 和 baz,他们都依赖了一个相同的模块 shared,但 foo 和 bar 依赖 shared 中的导出 value1,而 baz 依赖了 shared 中的导出 value2。 + +```js title=foo.js +import { value1 } from 'shared'; +value1; +``` + +```js title=bar.js +import { value1 } from 'shared'; +value1; +``` + +```js title=baz.js +import { value2 } from 'shared'; +value2; +``` + +默认的策略中 shared 模块由于同时出现在 3 个 chunk 中,如果它满足了[最小拆分体积](plugins/webpack/split-chunks-plugin#splitchunksminsize),那么 shared 本该被抽离到一个单独 chunk 中。 + +``` +chunk foo, chunk bar + \ + chunk shared (exports value1 and value2) + / +chunk baz +``` + +但这样会导致 3 个入口都不满足最佳的加载体积,从 foo 和 bar 入口加载 shared 会多加载并不需要的导出 value2,而从 baz 入口加载 shared 会多加载并不需要的导出 value1。 + +当开启 `splitChunks.usedExports` 优化后,会分析 shared 模块分别在不同入口中用到的导出,发现在 foo 和 bar 中用到的导出和 baz 中不一样,会产生 2 个不同的 chunk,其中一个对应入口 foo 和 bar,另一个对应入口 baz。 + +``` +chunk foo, chunk bar + \ + chunk shared-1 (exports only value1) + +chunk baz + \ + chunk shared-2 (exports only value2) +``` + ### splitChunks.cacheGroups 缓存组可以继承和/或覆盖来自 `splitChunks.*` 的任何选项。但是 `test`、`priority` 和 `reuseExistingChunk` 只能在缓存组级别上进行配置。将它们设置为 `false` 以禁用任何默认缓存组。