diff --git a/Cargo.lock b/Cargo.lock index b392a147ddad..6cf815461bc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2476,7 +2476,6 @@ dependencies = [ "rspack_plugin_remove_empty_chunks", "rspack_plugin_runtime", "rspack_plugin_schemes", - "rspack_plugin_split_chunks", "rspack_plugin_split_chunks_new", "rspack_plugin_swc_css_minimizer", "rspack_plugin_swc_js_minimizer", @@ -2538,7 +2537,6 @@ dependencies = [ "rspack_plugin_remove_empty_chunks", "rspack_plugin_runtime", "rspack_plugin_schemes", - "rspack_plugin_split_chunks", "rspack_plugin_split_chunks_new", "rspack_plugin_swc_css_minimizer", "rspack_plugin_swc_js_minimizer", @@ -3174,19 +3172,6 @@ dependencies = [ "urlencoding", ] -[[package]] -name = "rspack_plugin_split_chunks" -version = "0.1.0" -dependencies = [ - "async-trait", - "derivative", - "rspack_core", - "rspack_identifier", - "rspack_util", - "rustc-hash", - "tracing", -] - [[package]] name = "rspack_plugin_split_chunks_new" version = "0.1.0" diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 21961f466f70..5f1a91bd2acc 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -160,7 +160,6 @@ export const enum BuiltinPluginName { WebWorkerTemplatePlugin = 'WebWorkerTemplatePlugin', MergeDuplicateChunksPlugin = 'MergeDuplicateChunksPlugin', SplitChunksPlugin = 'SplitChunksPlugin', - OldSplitChunksPlugin = 'OldSplitChunksPlugin', ShareRuntimePlugin = 'ShareRuntimePlugin', ContainerPlugin = 'ContainerPlugin', ContainerReferencePlugin = 'ContainerReferencePlugin', diff --git a/crates/rspack_binding_options/Cargo.toml b/crates/rspack_binding_options/Cargo.toml index 58ed9ad45dcf..b500a27f59db 100644 --- a/crates/rspack_binding_options/Cargo.toml +++ b/crates/rspack_binding_options/Cargo.toml @@ -39,7 +39,6 @@ rspack_plugin_real_content_hash = { path = "../rspack_plugin_real_conten rspack_plugin_remove_empty_chunks = { path = "../rspack_plugin_remove_empty_chunks" } rspack_plugin_runtime = { path = "../rspack_plugin_runtime" } rspack_plugin_schemes = { path = "../rspack_plugin_schemes" } -rspack_plugin_split_chunks = { path = "../rspack_plugin_split_chunks" } rspack_plugin_split_chunks_new = { path = "../rspack_plugin_split_chunks_new" } rspack_plugin_swc_css_minimizer = { path = "../rspack_plugin_swc_css_minimizer" } rspack_plugin_swc_js_minimizer = { path = "../rspack_plugin_swc_js_minimizer" } diff --git a/crates/rspack_binding_options/src/options/raw_builtins/mod.rs b/crates/rspack_binding_options/src/options/raw_builtins/mod.rs index c1fce92bf549..4f42fe099e32 100644 --- a/crates/rspack_binding_options/src/options/raw_builtins/mod.rs +++ b/crates/rspack_binding_options/src/options/raw_builtins/mod.rs @@ -96,7 +96,6 @@ pub enum BuiltinPluginName { WebWorkerTemplatePlugin, MergeDuplicateChunksPlugin, SplitChunksPlugin, - OldSplitChunksPlugin, ShareRuntimePlugin, ContainerPlugin, ContainerReferencePlugin, @@ -237,11 +236,6 @@ impl BuiltinPlugin { let options = downcast_into::(self.options)?.into(); plugins.push(SplitChunksPlugin::new(options).boxed()); } - BuiltinPluginName::OldSplitChunksPlugin => { - use rspack_plugin_split_chunks::SplitChunksPlugin; - let options = downcast_into::(self.options)?.into(); - plugins.push(SplitChunksPlugin::new(options).boxed()); - } BuiltinPluginName::ShareRuntimePlugin => { plugins.push(ShareRuntimePlugin::new(downcast_into::(self.options)?).boxed()) } 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 f395b9e568bd..de21833d9795 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 @@ -5,7 +5,6 @@ mod raw_split_chunk_name; use std::sync::Arc; use derivative::Derivative; -use napi::bindgen_prelude::Either3; use napi::{Either, JsString}; use napi_derive::napi; use raw_split_chunk_name::normalize_raw_chunk_name; @@ -55,69 +54,6 @@ pub struct RawSplitChunksOptions { pub max_initial_size: Option, } -impl From for rspack_plugin_split_chunks::SplitChunksOptions { - fn from(value: RawSplitChunksOptions) -> Self { - use rspack_plugin_split_chunks::{CacheGroupOptions, ChunkType, SplitChunksOptions, TestFn}; - - let mut defaults = SplitChunksOptions { - max_async_requests: value.max_async_requests, - max_initial_requests: value.max_initial_requests, - min_chunks: value.min_chunks, - min_size: value.min_size, - enforce_size_threshold: value.enforce_size_threshold, - min_remaining_size: value.min_remaining_size, - automatic_name_delimiter: Some(DEFAULT_DELIMITER.to_string()), - chunks: value.chunks.map(|chunks| { - let Either3::B(chunks) = chunks else { - panic!("expected string") - }; - let chunks = chunks.into_string(); - match chunks.as_str() { - "initial" => ChunkType::Initial, - "async" => ChunkType::Async, - "all" => ChunkType::All, - _ => panic!("Invalid chunk type: {chunks}"), - } - }), - ..Default::default() - }; - - defaults - .cache_groups - .extend(value.cache_groups.unwrap_or_default().into_iter().map(|v| { - ( - v.key, - CacheGroupOptions { - // FIXME: since old split chunk will not used so I use `None` here - automatic_name_delimiter: Some(DEFAULT_DELIMITER.to_string()), - name: None, - priority: v.priority, - reuse_existing_chunk: Some(false), - test: v.test.map(|_| { - let f: TestFn = Arc::new(move |_| false); - f // FIXME: since old split chunk will not used so I use `|| -> false` here - }), - chunks: v.chunks.map(|chunks| { - let Either3::B(chunks) = chunks else { - panic!("expected string") - }; - let chunks = chunks.into_string(); - match chunks.as_str() { - "initial" => ChunkType::Initial, - "async" => ChunkType::Async, - "all" => ChunkType::All, - _ => panic!("Invalid chunk type: {chunks}"), - } - }), - min_chunks: v.min_chunks, - ..Default::default() - }, - ) - })); - defaults - } -} - #[derive(Derivative, Deserialize)] #[serde(rename_all = "camelCase")] #[napi(object)] diff --git a/crates/rspack_binding_values/Cargo.toml b/crates/rspack_binding_values/Cargo.toml index 60a2e89b1283..103544d57fd4 100644 --- a/crates/rspack_binding_values/Cargo.toml +++ b/crates/rspack_binding_values/Cargo.toml @@ -35,7 +35,6 @@ rspack_plugin_real_content_hash = { path = "../rspack_plugin_real_conten rspack_plugin_remove_empty_chunks = { path = "../rspack_plugin_remove_empty_chunks" } rspack_plugin_runtime = { path = "../rspack_plugin_runtime" } rspack_plugin_schemes = { path = "../rspack_plugin_schemes" } -rspack_plugin_split_chunks = { path = "../rspack_plugin_split_chunks" } rspack_plugin_split_chunks_new = { path = "../rspack_plugin_split_chunks_new" } rspack_plugin_swc_css_minimizer = { path = "../rspack_plugin_swc_css_minimizer" } rspack_plugin_swc_js_minimizer = { path = "../rspack_plugin_swc_js_minimizer" } diff --git a/crates/rspack_plugin_split_chunks/Cargo.toml b/crates/rspack_plugin_split_chunks/Cargo.toml deleted file mode 100644 index f7c2542e49e4..000000000000 --- a/crates/rspack_plugin_split_chunks/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -edition = "2021" -license = "MIT" -name = "rspack_plugin_split_chunks" -repository = "https://github.com/web-infra-dev/rspack" -version = "0.1.0" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -async-trait = { workspace = true } -derivative = { workspace = true } -rspack_core = { path = "../rspack_core" } -rspack_identifier = { path = "../rspack_identifier" } -rspack_util = { path = "../rspack_util" } -rustc-hash = { workspace = true } -tracing = { workspace = true } diff --git a/crates/rspack_plugin_split_chunks/LICENSE b/crates/rspack_plugin_split_chunks/LICENSE deleted file mode 100644 index 46310101ad8a..000000000000 --- a/crates/rspack_plugin_split_chunks/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2022-present Bytedance, Inc. and its affiliates. - - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/crates/rspack_plugin_split_chunks/src/cache_group.rs b/crates/rspack_plugin_split_chunks/src/cache_group.rs deleted file mode 100644 index 63b14cb06ac4..000000000000 --- a/crates/rspack_plugin_split_chunks/src/cache_group.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Port of https://github.com/webpack/webpack/blob/4b4ca3bb53f36a5b8fc6bc1bd976ed7af161bd80/lib/optimize/SplitChunksPlugin.js#L78 - -use derivative::Derivative; - -use crate::{cache_group_source::SplitChunkSizes, ChunkFilterFn, SplitChunksNameFn}; - -#[derive(Derivative)] -#[derivative(Debug)] -pub struct CacheGroup { - pub key: String, - pub priority: i32, - #[derivative(Debug = "ignore")] - pub get_name: SplitChunksNameFn, - #[derivative(Debug = "ignore")] - pub chunks_filter: ChunkFilterFn, - pub min_chunks: u32, - pub max_async_requests: u32, - pub max_initial_requests: u32, - pub filename: Option, - pub id_hint: String, - pub automatic_name_delimiter: String, - pub reuse_existing_chunk: bool, - // TODO: supports used_exports - // pub used_exports: bool, - pub min_size: SplitChunkSizes, - pub min_size_reduction: SplitChunkSizes, - pub min_remaining_size: SplitChunkSizes, - pub enforce_size_threshold: SplitChunkSizes, - pub max_async_size: SplitChunkSizes, - pub max_initial_size: SplitChunkSizes, - pub(crate) validate_size: bool, - pub(crate) min_size_for_max_size: SplitChunkSizes, - pub(crate) validate_remaining_size: bool, -} diff --git a/crates/rspack_plugin_split_chunks/src/cache_group_source.rs b/crates/rspack_plugin_split_chunks/src/cache_group_source.rs deleted file mode 100644 index 6a0997407fdb..000000000000 --- a/crates/rspack_plugin_split_chunks/src/cache_group_source.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Port of https://github.com/webpack/webpack/blob/4b4ca3bb53f36a5b8fc6bc1bd976ed7af161bd80/lib/optimize/SplitChunksPlugin.js#L55 - -use derivative::Derivative; -use rspack_core::SourceType; -use rustc_hash::FxHashMap as HashMap; - -use crate::{ChunkFilterFn, SplitChunksNameFn}; - -pub(crate) type SplitChunkSizes = HashMap; -#[derive(Derivative)] -#[derivative(Debug)] -pub struct CacheGroupSource { - pub key: String, - pub priority: Option, - - #[derivative(Debug = "ignore")] - pub get_name: Option, - #[derivative(Debug = "ignore")] - pub chunks_filter: Option, - pub enforce: Option, - pub min_size: SplitChunkSizes, - pub min_size_reduction: SplitChunkSizes, - pub min_remaining_size: SplitChunkSizes, - pub enforce_size_threshold: SplitChunkSizes, - pub max_async_size: SplitChunkSizes, - pub max_initial_size: SplitChunkSizes, - pub min_chunks: Option, - pub max_async_requests: Option, - pub max_initial_requests: Option, - pub filename: Option, - pub id_hint: Option, - pub automatic_name_delimiter: String, - pub reuse_existing_chunk: Option, - // TODO: supports used_exports - // pub used_exports: bool, -} diff --git a/crates/rspack_plugin_split_chunks/src/chunks_info_item.rs b/crates/rspack_plugin_split_chunks/src/chunks_info_item.rs deleted file mode 100644 index 1b5f74d9a29d..000000000000 --- a/crates/rspack_plugin_split_chunks/src/chunks_info_item.rs +++ /dev/null @@ -1,33 +0,0 @@ -use derivative::Derivative; -use rspack_core::ChunkUkey; -use rspack_identifier::IdentifierSet; -use rustc_hash::FxHashSet; - -use crate::{cache_group::CacheGroup, cache_group_source::SplitChunkSizes, CacheGroupByKey}; - -#[derive(Derivative)] -#[derivative(Debug)] -pub(crate) struct ChunksInfoItem { - // Sortable Module Set - #[derivative(Debug = "ignore")] - pub modules: IdentifierSet, - pub cache_group: String, - pub cache_group_index: usize, - pub name: Option, - pub sizes: SplitChunkSizes, - pub chunks: FxHashSet, - pub _reusable_chunks: FxHashSet, - // bigint | Chunk - // pub chunks_keys: Hash -} - -impl ChunksInfoItem { - pub(crate) fn cache_group<'cache_group>( - &self, - map: &'cache_group CacheGroupByKey, - ) -> &'cache_group CacheGroup { - map - .get(&self.cache_group) - .unwrap_or_else(|| panic!("Cache group not found: {}", self.cache_group)) - } -} diff --git a/crates/rspack_plugin_split_chunks/src/lib.rs b/crates/rspack_plugin_split_chunks/src/lib.rs deleted file mode 100644 index 09d1c7f272aa..000000000000 --- a/crates/rspack_plugin_split_chunks/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![feature(option_get_or_insert_default)] -#![feature(map_many_mut)] - -mod plugin; -use std::sync::Arc; - -use rustc_hash::FxHashMap as HashMap; -mod options; -pub use options::*; -use rspack_core::{Chunk, ChunkGroupByUkey, Module}; - -pub type TestFn = Arc bool + Sync + Send>; -pub(crate) type SplitChunksNameFn = Arc Option + Sync + Send>; -pub(crate) type ChunkFilterFn = Arc bool + Send + Sync>; - -mod utils; -pub(crate) type CacheGroupByKey = HashMap; -pub(crate) type ChunksInfoMap = HashMap; - -mod cache_group; -pub(crate) use cache_group::*; -mod cache_group_source; -pub(crate) use cache_group_source::*; -mod split_chunks_plugin; -// pub(crate) use split_chunks_plugin::*; -mod chunks_info_item; -pub(crate) use chunks_info_item::*; -mod max_size_queue_item; -// pub(crate) use max_size_queue_item::*; -// public -pub use split_chunks_plugin::SplitChunksPlugin; - -// TODO: Webpack also supports a HashMap here, which is not supported yet. -pub(crate) type OptimizationSplitChunksSizes = f64; -pub(crate) type SplitChunksSizes = HashMap; diff --git a/crates/rspack_plugin_split_chunks/src/max_size_queue_item.rs b/crates/rspack_plugin_split_chunks/src/max_size_queue_item.rs deleted file mode 100644 index 979fad18f979..000000000000 --- a/crates/rspack_plugin_split_chunks/src/max_size_queue_item.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::cache_group_source::SplitChunkSizes; - -#[derive(Debug)] -pub struct MaxSizeQueueItem { - pub min_size: SplitChunkSizes, - pub max_async_size: SplitChunkSizes, - pub max_initial_size: SplitChunkSizes, - pub keys: Vec, -} diff --git a/crates/rspack_plugin_split_chunks/src/options/cache_group_options.rs b/crates/rspack_plugin_split_chunks/src/options/cache_group_options.rs deleted file mode 100644 index 67c33ce03f1e..000000000000 --- a/crates/rspack_plugin_split_chunks/src/options/cache_group_options.rs +++ /dev/null @@ -1,34 +0,0 @@ -use derivative::Derivative; -use rspack_core::ModuleType; - -use crate::{ChunkType, OptimizationSplitChunksSizes, TestFn}; - -#[derive(Derivative)] -#[derivative(Debug)] -#[derive(Clone, Default)] -pub struct CacheGroupOptions { - pub automatic_name_delimiter: Option, - /// What kind of chunks should be selected. - pub chunks: Option, - pub enforce: Option, - pub enforce_size_threshold: Option, - pub filename: Option, - pub id_hint: Option, - // TODO: supports pub fn layer: RegExp | string | Function; - pub max_async_requests: Option, - pub max_async_size: Option, - pub max_initial_requests: Option, - pub max_initial_size: Option, - pub max_size: Option, - pub min_chunks: Option, - pub min_remaining_size: Option, - pub min_size: Option, - pub min_size_reduction: Option, - pub name: Option, - pub priority: Option, - pub reuse_existing_chunk: Option, - #[derivative(Debug = "ignore")] - pub test: Option, - pub r#type: Option, - // TODO: supports: used_exports: Option, -} diff --git a/crates/rspack_plugin_split_chunks/src/options/mod.rs b/crates/rspack_plugin_split_chunks/src/options/mod.rs deleted file mode 100644 index 0c9a445e5508..000000000000 --- a/crates/rspack_plugin_split_chunks/src/options/mod.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::fmt::Debug; - -use derivative::Derivative; -use rspack_core::{Chunk, ChunkGroupByUkey, SourceType}; - -use crate::{cache_group_source::SplitChunkSizes, ChunkFilterFn, SplitChunksNameFn}; - -mod split_chunks_options; -pub use split_chunks_options::*; -mod cache_group_options; -pub use cache_group_options::*; - -#[derive(Clone, Copy)] -pub enum ChunkType { - Initial, - Async, - All, - // Custom(Box bool + Sync + Send>), -} - -impl TryFrom<&str> for ChunkType { - type Error = String; - - fn try_from(value: &str) -> Result { - match value { - "initial" => Ok(ChunkType::Initial), - "async" => Ok(ChunkType::Async), - "all" => Ok(ChunkType::All), - _ => Err(format!("Invalid chunk type: {value}")), - } - } -} - -impl ChunkType { - pub fn is_selected(&self, chunk: &Chunk, chunk_group_by_ukey: &ChunkGroupByUkey) -> bool { - match self { - ChunkType::Initial => chunk.can_be_initial(chunk_group_by_ukey), - ChunkType::Async => !chunk.can_be_initial(chunk_group_by_ukey), - ChunkType::All => true, - } - } -} - -impl Debug for ChunkType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Initial => write!(f, "Initial"), - Self::Async => write!(f, "Async"), - Self::All => write!(f, "All"), - // Self::Custom(_) => write!(f, "Custom"), - } - } -} - -pub type SizeType = SourceType; - -#[derive(Derivative)] -#[derivative(Debug)] -pub struct NormalizedOptions { - pub default_size_types: Vec, - pub min_size: SplitChunkSizes, - pub min_size_reduction: SplitChunkSizes, - pub min_remaining_size: SplitChunkSizes, - pub enforce_size_threshold: SplitChunkSizes, - pub max_async_size: SplitChunkSizes, - pub max_initial_size: SplitChunkSizes, - pub min_chunks: u32, - pub max_async_requests: u32, - pub max_initial_requests: u32, - pub filename: Option, - #[derivative(Debug = "ignore")] - pub get_name: SplitChunksNameFn, - #[derivative(Debug = "ignore")] - pub chunk_filter: ChunkFilterFn, - pub fallback_cache_group: NormalizedFallbackCacheGroup, -} - -#[derive(Derivative, Clone)] -#[derivative(Debug)] -pub struct NormalizedFallbackCacheGroup { - #[derivative(Debug = "ignore")] - pub chunks_filter: ChunkFilterFn, - pub min_size: SplitChunkSizes, - pub max_async_size: SplitChunkSizes, - pub max_initial_size: SplitChunkSizes, - pub automatic_name_delimiter: String, -} diff --git a/crates/rspack_plugin_split_chunks/src/options/split_chunks_options.rs b/crates/rspack_plugin_split_chunks/src/options/split_chunks_options.rs deleted file mode 100644 index 2b74c913b471..000000000000 --- a/crates/rspack_plugin_split_chunks/src/options/split_chunks_options.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::collections::HashMap; - -use derivative::Derivative; - -use crate::{ - CacheGroupOptions, ChunkType, OptimizationSplitChunksSizes, SizeType, SplitChunksNameFn, -}; - -/// Align with https://github.com/webpack/webpack/blob/4b4ca3bb53f36a5b8fc6bc1bd976ed7af161bd80/types.d.ts#L8265 -#[derive(Default, Derivative)] -#[derivative(Debug, Clone)] -pub struct SplitChunksOptions { - pub automatic_name_delimiter: Option, - pub cache_groups: HashMap, - /// What kind of chunks should be selected. - pub chunks: Option, - pub default_size_types: Option>, - pub enforce_size_threshold: Option, - pub fallback_cache_group: Option, - pub filename: Option, - pub max_async_requests: Option, - pub max_async_size: Option, - pub max_initial_requests: Option, - pub max_initial_size: Option, - pub max_size: Option, - pub min_chunks: Option, - pub min_remaining_size: Option, - pub min_size: Option, - pub min_size_reduction: Option, - #[derivative(Debug = "ignore")] - pub name: Option, - // TODO: Supports used_exports: bool, -} - -#[derive(Debug, Default, Clone)] -pub struct SplitChunksOptionsCacheGroup { - pub automatic_name_delimiter: Option, - pub chunks: Option, - pub max_async_size: Option, - pub max_initial_size: Option, - pub max_size: Option, - pub min_size: Option, - pub min_size_reduction: Option, -} diff --git a/crates/rspack_plugin_split_chunks/src/plugin.rs b/crates/rspack_plugin_split_chunks/src/plugin.rs deleted file mode 100644 index 1345edd2a681..000000000000 --- a/crates/rspack_plugin_split_chunks/src/plugin.rs +++ /dev/null @@ -1,213 +0,0 @@ -#![allow(clippy::obfuscated_if_else)] -#![allow(clippy::comparison_chain)] - -use std::sync::Arc; - -use rspack_core::{Module, ModuleGraph, SourceType, DEFAULT_DELIMITER}; -use rustc_hash::FxHashMap as HashMap; - -use crate::{ - chunks_info_item::ChunksInfoItem, - utils::{get_violating_min_sizes, merge_sizes2, normalize_sizes}, - CacheGroup, CacheGroupOptions, CacheGroupSource, ChunkFilterFn, ChunkType, NormalizedOptions, - SizeType, SplitChunksNameFn, -}; - -pub fn create_cache_group( - options: &NormalizedOptions, - group_source: &CacheGroupSource, -) -> CacheGroup { - let min_size = { - let mut cloned = group_source.min_size.clone(); - if !group_source.enforce.unwrap_or_default() { - cloned.extend(group_source.enforce_size_threshold.clone()); - } - cloned - }; - let min_size_reduction = { - let mut cloned = group_source.min_size_reduction.clone(); - if !group_source.enforce.unwrap_or_default() { - cloned.extend(group_source.enforce_size_threshold.clone()); - } - cloned - }; - let min_remaining_size = { - let mut cloned = group_source.min_remaining_size.clone(); - if !group_source.enforce.unwrap_or_default() { - cloned.extend(group_source.enforce_size_threshold.clone()); - } - cloned - }; - let enforce_size_threshold = { - let mut cloned = group_source.enforce_size_threshold.clone(); - if !group_source.enforce.unwrap_or_default() { - cloned.extend(group_source.enforce_size_threshold.clone()); - } - cloned - }; - let max_async_size = { - let mut cloned = group_source.max_async_size.clone(); - if !group_source.enforce.unwrap_or_default() { - cloned.extend(group_source.enforce_size_threshold.clone()); - } - cloned - }; - let max_initial_size = { - let mut cloned = group_source.max_initial_size.clone(); - if !group_source.enforce.unwrap_or_default() { - cloned.extend(group_source.enforce_size_threshold.clone()); - } - cloned - }; - let chunks_filter = group_source.chunks_filter.clone(); - CacheGroup { - key: group_source.key.clone(), - priority: group_source.priority.unwrap_or(0), - chunks_filter: chunks_filter - .clone() - .unwrap_or_else(|| options.chunk_filter.clone()), - min_size: min_size.clone(), - min_size_reduction, - min_remaining_size: min_remaining_size.clone(), - enforce_size_threshold, - max_async_size, - max_initial_size, - min_chunks: group_source.min_chunks.unwrap_or_else(|| { - group_source - .enforce - .unwrap_or_default() - .then_some(1) - .unwrap_or(options.min_chunks) - }), - max_async_requests: group_source.max_async_requests.unwrap_or_else(|| { - group_source - .enforce - .unwrap_or_default() - .then_some(1) - .unwrap_or(options.max_async_requests) - }), - max_initial_requests: group_source.max_initial_requests.unwrap_or_else(|| { - group_source - .enforce - .unwrap_or_default() - .then_some(1) - .unwrap_or(options.max_initial_requests) - }), - get_name: group_source - .get_name - .clone() - .unwrap_or_else(|| options.get_name.clone()), - // used_exports: group_source.used_exports, - automatic_name_delimiter: group_source.automatic_name_delimiter.clone(), - filename: group_source - .filename - .clone() - .map(Some) - .unwrap_or_else(|| options.filename.clone()), - id_hint: group_source - .id_hint - .clone() - .unwrap_or_else(|| group_source.key.clone()), - reuse_existing_chunk: group_source.reuse_existing_chunk.unwrap_or_default(), - validate_size: min_size.values().any(|size| size > &0f64), - min_size_for_max_size: merge_sizes2(group_source.min_size.clone(), options.min_size.clone()), - validate_remaining_size: min_remaining_size.values().any(|size| size > &0f64), - } -} - -pub fn create_cache_group_source( - options: CacheGroupOptions, - key: String, - default_size_types: &[SizeType], -) -> CacheGroupSource { - let min_size = normalize_sizes(options.min_size, default_size_types); - let min_size_reduction = normalize_sizes(options.min_size_reduction, default_size_types); - let max_size = normalize_sizes(options.max_size, default_size_types); - - let get_name = options - .name - .map(|name| Arc::new(move |_: &dyn Module| Some(name.clone())) as SplitChunksNameFn); - - CacheGroupSource { - key, - priority: options.priority, - get_name, - chunks_filter: options.chunks.map(|chunks| { - let f: ChunkFilterFn = Arc::new(move |chunk, chunk_group_by_ukey| match chunks { - ChunkType::Initial => chunk.can_be_initial(chunk_group_by_ukey), - ChunkType::Async => !chunk.can_be_initial(chunk_group_by_ukey), - ChunkType::All => true, - }); - f - }), - enforce: options.enforce, - min_size: min_size.clone(), - min_size_reduction, - min_remaining_size: merge_sizes2( - normalize_sizes(options.min_remaining_size, default_size_types), - min_size, - ), - enforce_size_threshold: normalize_sizes(options.enforce_size_threshold, default_size_types), - max_async_size: merge_sizes2( - normalize_sizes(options.max_async_size, default_size_types), - max_size.clone(), - ), - max_initial_size: merge_sizes2( - normalize_sizes(options.max_initial_size, default_size_types), - max_size, - ), - min_chunks: options.min_chunks, - max_async_requests: options.max_async_requests, - max_initial_requests: options.max_initial_requests, - filename: options.filename.clone(), - id_hint: options.id_hint.clone(), - automatic_name_delimiter: options - .automatic_name_delimiter - .clone() - .unwrap_or_else(|| DEFAULT_DELIMITER.to_string()), - reuse_existing_chunk: options.reuse_existing_chunk, - // used_exports: options.used_exports, - } -} - -pub(crate) fn remove_modules_with_source_type( - info: &mut ChunksInfoItem, - source_types: &[SourceType], - module_graph: &mut ModuleGraph, -) { - info.modules.retain(|module_identifier| { - let module = module_graph - .module_by_identifier(module_identifier) - .expect("module should exist"); - let types = module.source_types(); - if source_types.iter().any(|ty| types.contains(ty)) { - info - .sizes - .iter_mut() - .for_each(|(ty, size)| *size -= module.size(ty)); - true - } else { - false - } - }); -} - -pub(crate) fn remove_min_size_violating_modules( - info: &mut ChunksInfoItem, - cache_group_by_key: &HashMap, - module_graph: &mut ModuleGraph, -) -> bool { - let cache_group = cache_group_by_key - .get(&info.cache_group) - .expect("cache_group should exists"); - if !cache_group.validate_size { - return false; - }; - let violating_sizes = get_violating_min_sizes(&info.sizes, &cache_group.min_size); - if let Some(violating_sizes) = violating_sizes { - remove_modules_with_source_type(info, &violating_sizes, module_graph); - info.modules.is_empty() - } else { - false - } -} diff --git a/crates/rspack_plugin_split_chunks/src/split_chunks_plugin.rs b/crates/rspack_plugin_split_chunks/src/split_chunks_plugin.rs deleted file mode 100644 index 93d88d32db59..000000000000 --- a/crates/rspack_plugin_split_chunks/src/split_chunks_plugin.rs +++ /dev/null @@ -1,906 +0,0 @@ -#![allow(clippy::obfuscated_if_else)] -#![allow(clippy::comparison_chain)] - -use std::{fmt::Debug, sync::Arc}; - -use rspack_core::{ - get_chunk_from_ukey, get_chunk_group_from_ukey, Chunk, ChunkGroupByUkey, ChunkUkey, Compilation, - Module, Plugin, DEFAULT_DELIMITER, -}; -use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; - -use crate::{ - chunks_info_item::ChunksInfoItem, - max_size_queue_item::MaxSizeQueueItem, - plugin::{ - create_cache_group, create_cache_group_source, remove_min_size_violating_modules, - remove_modules_with_source_type, - }, - utils::{ - check_min_size, check_min_size_reduction, combine_sizes, compare_entries, get_requests, - get_violating_min_sizes, merge_sizes, merge_sizes2, normalize_chunks_filter, normalize_sizes, - }, - CacheGroup, CacheGroupSource, ChunkType, ChunksInfoMap, NormalizedFallbackCacheGroup, - NormalizedOptions, SizeType, SplitChunkSizes, SplitChunksOptions, -}; - -#[derive(Debug)] -pub struct SplitChunksPlugin { - raw_options: SplitChunksOptions, - _cache_group_source_by_key: HashMap, - cache_group_by_key: HashMap, -} - -impl SplitChunksPlugin { - pub fn new(options: SplitChunksOptions) -> Self { - let default_size_types = options - .default_size_types - .clone() - .unwrap_or_else(|| vec![SizeType::JavaScript, SizeType::Unknown]); - - let fallback_cache_group = options.fallback_cache_group.clone().unwrap_or_default(); - - let min_size = normalize_sizes(options.min_size, &default_size_types); - let min_size_reduction = normalize_sizes(options.min_size_reduction, &default_size_types); - let max_size = normalize_sizes(options.max_size, &default_size_types); - - let normalized_options = NormalizedOptions { - chunk_filter: { - let chunks = options.chunks; - Arc::new(move |chunk, chunk_group_by_ukey| { - let chunk_type = chunks.as_ref().unwrap_or(&ChunkType::Async); - chunk_type.is_selected(chunk, chunk_group_by_ukey) - }) - }, - default_size_types: default_size_types.clone(), - min_size: min_size.clone(), - min_size_reduction, - min_remaining_size: merge_sizes2( - normalize_sizes(options.min_remaining_size, &default_size_types), - min_size.clone(), - ), - enforce_size_threshold: normalize_sizes(options.enforce_size_threshold, &default_size_types), - max_async_size: merge_sizes2( - normalize_sizes(options.max_async_size, &default_size_types), - max_size.clone(), - ), - max_initial_size: merge_sizes2( - normalize_sizes(options.max_initial_size, &default_size_types), - max_size, - ), - min_chunks: options.min_chunks.unwrap_or(1), - max_async_requests: options.min_chunks.unwrap_or(1), - max_initial_requests: options.min_chunks.unwrap_or(1), - filename: options.filename.clone(), - get_name: options.name.clone().unwrap_or_else(|| Arc::new(|_| None)), - fallback_cache_group: NormalizedFallbackCacheGroup { - chunks_filter: normalize_chunks_filter( - fallback_cache_group - .chunks - .unwrap_or_else(|| options.chunks.unwrap_or(ChunkType::All)), - ), - min_size: merge_sizes2( - normalize_sizes(fallback_cache_group.min_size, &default_size_types), - min_size, - ), - max_async_size: merge_sizes(vec![ - normalize_sizes(fallback_cache_group.max_async_size, &default_size_types), - normalize_sizes(fallback_cache_group.max_size, &default_size_types), - normalize_sizes(options.max_async_size, &default_size_types), - normalize_sizes(options.max_size, &default_size_types), - ]), - max_initial_size: merge_sizes(vec![ - normalize_sizes(fallback_cache_group.max_initial_size, &default_size_types), - normalize_sizes(fallback_cache_group.max_size, &default_size_types), - normalize_sizes(options.max_initial_size, &default_size_types), - normalize_sizes(options.max_size, &default_size_types), - ]), - automatic_name_delimiter: fallback_cache_group - .automatic_name_delimiter - .unwrap_or_else(|| { - options - .automatic_name_delimiter - .clone() - .unwrap_or_else(|| DEFAULT_DELIMITER.to_string()) - }), - }, - }; - - let cache_group_source_by_key = { - options - .cache_groups - .clone() - .into_iter() - .map(|(name, group_option)| { - ( - name.clone(), - create_cache_group_source(group_option, name, &default_size_types), - ) - }) - } - .collect::>(); - - let cache_group_by_key = { - cache_group_source_by_key.values().map(|group_source| { - ( - group_source.key.clone(), - create_cache_group(&normalized_options, group_source), - ) - }) - } - .collect::>(); - - tracing::debug!( - "created cache groups: {:#?}", - cache_group_by_key.keys().collect::>() - ); - - Self { - _cache_group_source_by_key: cache_group_source_by_key, - raw_options: options, - cache_group_by_key, - } - } - - fn get_cache_groups(&self, module: &dyn Module) -> Vec { - self - .raw_options - .cache_groups - .iter() - .filter(|(_, group_option)| { - // Align with - group_option - .test - .as_ref() - .map_or(true, |test| (test)(module)) - && group_option - .r#type - .as_ref() - .map_or(true, |ty| ty == module.module_type()) - // TODO: check module layer - }) - // TODO: Supports filter with module type - .map(|(key, _group_option)| key.clone()) - .collect() - } - - #[allow(clippy::format_in_format_args)] - #[allow(clippy::too_many_arguments)] - fn add_module_to_chunks_info_map( - &self, - cache_group: &CacheGroup, - cache_group_index: usize, - selected_chunks: &[&Chunk], - // selectedChunksKey, - module: &dyn Module, - chunks_info_map: &mut HashMap, - named_chunk: &HashMap, - chunk_by_ukey: &rspack_core::ChunkByUkey, - chunk_group_by_ukey: &ChunkGroupByUkey, - // compilation: &mut Compilation, - ) { - let module_identifier = module.identifier(); - // Break if minimum number of chunks is not reached - if selected_chunks.len() < cache_group.min_chunks as usize { - tracing::debug!( - "[Bailout-Module]: {}, because selected_chunks.len({:?}) < cache_group.min_chunks({:?})", - module_identifier, - selected_chunks.len(), - cache_group.min_chunks - ); - return; - } - - // Determine name for split chunk - let name = (cache_group.get_name)(module); - - let existing_chunk = name.clone().and_then(|name| { - named_chunk - .get(&name) - .and_then(|chunk_ukey| get_chunk_from_ukey(chunk_ukey, chunk_by_ukey)) - }); - if let Some(existing_chunk) = existing_chunk { - // Module can only be moved into the existing chunk if the existing chunk - // is a parent of all selected chunks - let mut is_in_all_parents = true; - let queue = selected_chunks - .iter() - .flat_map(|c| { - let groups = c - .groups - .iter() - .filter_map(|ukey| get_chunk_group_from_ukey(ukey, chunk_group_by_ukey)) - .collect::>(); - let ancestors = groups - .iter() - .flat_map(|g| g.ancestors(chunk_group_by_ukey)) - .collect::>(); - groups.into_iter().map(|g| g.ukey).chain(ancestors) - }) - .collect::>(); - - for group in queue { - let group = chunk_group_by_ukey.expect_get(&group); - if existing_chunk.is_in_group(&group.ukey) { - continue; - } - is_in_all_parents = false; - break; - } - let valid = is_in_all_parents; - if !valid { - panic!("{}{}{}{}{}", - "SplitChunksPlugin\n", - format!("Cache group \"{}\" conflicts with existing chunk.\n", cache_group.key), - format!("Both have the same name \"{name:?}\" and existing chunk is not a parent of the selected modules.\n"), - "Use a different name for the cache group or make sure that the existing chunk is a parent (e. g. via dependOn).\n", - "HINT: You can omit \"name\" to automatically create a name.\n", - ) - } - } - - let key = format!( - "{} {}", - cache_group.key.clone(), - if let Some(name) = &name { - format!("name:{name}") - } else { - format!("chunk:{}", { - let mut keys = selected_chunks - .iter() - .map(|c| c.ukey.as_usize().to_string()) - .collect::>(); - keys.sort_unstable(); - keys.join("_") - }) - } - ); - - let info = chunks_info_map - .entry(key) - .or_insert_with(|| ChunksInfoItem { - modules: Default::default(), - cache_group: cache_group.key.clone(), - cache_group_index, - name, - sizes: Default::default(), - chunks: Default::default(), - _reusable_chunks: Default::default(), - }); - let old_size = info.modules.len(); - info.modules.insert(module.identifier()); - - if info.modules.len() != old_size { - module.source_types().iter().for_each(|ty| { - let sizes = info.sizes.entry(*ty).or_default(); - *sizes += module.size(ty); - }); - } - - info.chunks.extend( - selected_chunks - .iter() - .map(|chunk| chunk.ukey) - .collect::>(), - ); - } - - fn create_chunks_info_map( - &self, - compilation: &mut Compilation, - ) -> HashMap { - let mut chunks_info_map: HashMap = Default::default(); - - for module in compilation.module_graph.modules().values() { - let cache_group_source_keys = self.get_cache_groups(module.as_ref()); - if cache_group_source_keys.is_empty() { - tracing::debug!( - "[Bailout-No matched groups]: Module({})", - module.identifier(), - ); - continue; - } - tracing::debug!( - "Module({}) witch matched groups {:?}", - module.identifier(), - cache_group_source_keys - ); - - let mut cache_group_index = 0; - for cache_group_source in cache_group_source_keys { - let cache_group = self - .cache_group_by_key - .get(&cache_group_source) - .expect("TODO:"); - let combs = vec![compilation - .chunk_graph - .get_module_chunks(module.identifier())]; - - for combinations in combs { - if combinations.len() < cache_group.min_chunks as usize { - tracing::debug!( - "[Bailout]: CacheGroup({}), because of combinations({:?}) < cache_group.min_chunks({:?})", - cache_group.key, - combinations.len(), - cache_group.min_chunks - ); - continue; - } - - let selected_chunks = combinations - .iter() - .filter_map(|c| get_chunk_from_ukey(c, &compilation.chunk_by_ukey)) - .filter(|c| (cache_group.chunks_filter)(c, &compilation.chunk_group_by_ukey)) - .collect::>(); - - tracing::debug!( - "Split Module({}) with selected_chunks {:?} into group '{}'", - module.identifier(), - selected_chunks.iter().map(|c| c.ukey).collect::>(), - cache_group.key, - ); - self.add_module_to_chunks_info_map( - cache_group, - cache_group_index, - &selected_chunks, - module.as_ref(), - &mut chunks_info_map, - &compilation.named_chunks, - &compilation.chunk_by_ukey, // compilation, - &compilation.chunk_group_by_ukey, - ); - } - - cache_group_index += 1; - } - } - chunks_info_map - } - - fn find_best_entry(&self, chunks_info_map: &mut ChunksInfoMap) -> (String, ChunksInfoItem) { - let mut chunks_info_map_iter = chunks_info_map.iter(); - let (best_entry_key, mut best_entry) = chunks_info_map_iter.next().expect("item should exist"); - let mut best_entry_key = best_entry_key.clone(); - for (key, info) in chunks_info_map_iter { - if compare_entries(best_entry, info, &self.cache_group_by_key) < 0f64 { - best_entry_key = key.clone(); - best_entry = info; - } - } - - ( - best_entry_key.clone(), - chunks_info_map - .remove(&best_entry_key) - .expect("item should exist"), - ) - } - - #[allow(clippy::unwrap_in_result)] - #[allow(clippy::if_same_then_else)] - fn find_reusable_chunk( - &self, - compilation: &Compilation, - item: &ChunksInfoItem, - mut new_chunk: Option, - ) -> Option { - 'outer: for chunk in &item.chunks { - if compilation.chunk_graph.get_number_of_chunk_modules(chunk) != item.modules.len() { - continue; - } - - if item.chunks.len() > 1 && compilation.chunk_graph.get_number_of_entry_modules(chunk) > 0 { - continue; - } - - for module in &item.modules { - if !compilation.chunk_graph.is_module_in_chunk(module, *chunk) { - continue 'outer; - } - } - - let chunk = compilation.chunk_by_ukey.expect_get(chunk); - if new_chunk.is_none() - || new_chunk - .and_then(|ukey| get_chunk_from_ukey(&ukey, &compilation.chunk_by_ukey)) - .as_ref() - .map_or(false, |c| c.name.is_none()) - { - new_chunk = Some(chunk.ukey); - } else if chunk.name.as_ref().map_or(false, |chunk_name| { - new_chunk - .and_then(|new_ukey| get_chunk_from_ukey(&new_ukey, &compilation.chunk_by_ukey)) - .and_then(|c| c.name.as_ref()) - .map_or(false, |new_chunk_name| { - chunk_name.len() < new_chunk_name.len() - }) - }) { - new_chunk = Some(chunk.ukey); - } else if chunk.name.as_ref().map_or(false, |chunk_name| { - new_chunk - .and_then(|new_ukey| get_chunk_from_ukey(&new_ukey, &compilation.chunk_by_ukey)) - .and_then(|c| c.name.as_ref()) - .map_or(false, |new_chunk_name| { - chunk_name.len() == new_chunk_name.len() && chunk_name < new_chunk_name - }) - }) { - new_chunk = Some(chunk.ukey); - }; - } - new_chunk - } - - fn remove_unrelated_chunk( - &self, - compilation: &Compilation, - used_chunks: &mut HashSet, - item: &ChunksInfoItem, - ) { - 'outer: for chunk in &used_chunks.clone() { - for module in &item.modules { - if compilation.chunk_graph.is_module_in_chunk(module, *chunk) { - continue 'outer; - } else { - used_chunks.remove(chunk); - } - } - } - } - - fn filter_items_lesser_than_min_size( - &self, - chunks_info_map: &mut ChunksInfoMap, - compilation: &mut Compilation, - ) { - // Align with https://github.com/webpack/webpack/blob/8241da7f1e75c5581ba535d127fa66aeb9eb2ac8/lib/optimize/SplitChunksPlugin.js#L1280 - let mut to_be_removed: HashSet = HashSet::default(); - for (key, info) in chunks_info_map.iter_mut() { - if remove_min_size_violating_modules( - info, - &self.cache_group_by_key, - &mut compilation.module_graph, - ) || !check_min_size_reduction( - &info.sizes, - &self - .cache_group_by_key - .get(&info.cache_group) - .expect("TODO:") - .min_size_reduction, - info.chunks.len(), - ) { - to_be_removed.insert(key.clone()); - } - } - to_be_removed.into_iter().for_each(|cache_group_key| { - let info = chunks_info_map.remove(&cache_group_key); - tracing::debug!( - "Remove cache group '{:?}' because of minSize violation", - info - ); - }); - } - - fn remove_all_modules_from_other_entries_and_update_size( - &self, - item: &mut ChunksInfoItem, - chunks_info_map: &mut ChunksInfoMap, - used_chunks: &mut HashSet, - compilation: &mut Compilation, - ) { - let mut to_be_deleted = HashSet::default(); - // remove all modules from other entries and update size - for (key, info) in chunks_info_map.iter_mut() { - let is_overlap = info.chunks.union(used_chunks).next().is_some(); - if is_overlap { - // update modules and total size - // may remove it from the map when < minSize - let mut updated = false; - for module in &item.modules { - if info.modules.contains(module) { - info.modules.remove(module); - let module = compilation - .module_graph - .module_by_identifier(module) - .unwrap_or_else(|| panic!("Module({module}) not found")); - for ty in module.source_types() { - let sizes = info.sizes.get_mut(ty).unwrap_or_else(|| { - panic!( - "{:?} is not existed in sizes of {} for module({})", - ty, - info.cache_group, - module.identifier() - ) - }); - *sizes -= module.size(ty); - } - } - updated = true; - } - - if updated { - if info.modules.is_empty() { - to_be_deleted.insert(key.to_string()); - continue; - } - if remove_min_size_violating_modules( - info, - &self.cache_group_by_key, - &mut compilation.module_graph, - ) || !check_min_size_reduction( - &info.sizes, - &info - .cache_group(&self.cache_group_by_key) - .min_size_reduction, - info.chunks.len(), - ) { - to_be_deleted.insert(key.to_string()); - continue; - } - } - } - } - - to_be_deleted.into_iter().for_each(|key| { - chunks_info_map.remove(&key); - }); - } - - fn link_module_new_chunk_and_remove_in_old_chunks( - &self, - is_reused_with_all_modules: bool, - item: &ChunksInfoItem, - new_chunk: ChunkUkey, - used_chunks: &HashSet, - compilation: &mut Compilation, - ) { - if !is_reused_with_all_modules { - // Add all modules to the new chunk - for module_identifier in &item.modules { - // TODO: module.chunkCondition - // Add module to new chunk - compilation - .chunk_graph - .connect_chunk_and_module(new_chunk, *module_identifier); - // Remove module from used chunks - for used_chunk in used_chunks { - let used_chunk = compilation.chunk_by_ukey.expect_get(used_chunk); - compilation - .chunk_graph - .disconnect_chunk_and_module(&used_chunk.ukey, *module_identifier); - } - } - } else { - // Remove all modules from used chunks - for module_identifier in &item.modules { - for used_chunk in used_chunks { - let used_chunk = compilation.chunk_by_ukey.expect_get(used_chunk); - compilation - .chunk_graph - .disconnect_chunk_and_module(&used_chunk.ukey, *module_identifier); - } - } - } - } - - fn split_used_chunks( - &self, - used_chunks: &HashSet, - new_chunk: ChunkUkey, - compilation: &mut Compilation, - ) { - let new_chunk_ukey = new_chunk; - for used_chunk in used_chunks { - let [new_chunk, used_chunk] = compilation - .chunk_by_ukey - ._todo_should_remove_this_method_inner_mut() - .get_many_mut([&new_chunk_ukey, used_chunk]) - .expect("TODO:"); - used_chunk.split(new_chunk, &mut compilation.chunk_group_by_ukey); - } - } -} - -#[async_trait::async_trait] -impl Plugin for SplitChunksPlugin { - fn name(&self) -> &'static str { - "split_chunks" - } - - #[allow(clippy::unwrap_in_result)] - #[allow(clippy::if_same_then_else)] - #[allow(clippy::collapsible_else_if)] - #[allow(unused)] - async fn optimize_chunks( - &self, - _ctx: rspack_core::PluginContext, - args: rspack_core::OptimizeChunksArgs<'_>, - ) -> rspack_core::PluginOptimizeChunksOutput { - let compilation = args.compilation; - - let mut chunks_info_map: HashMap = - self.create_chunks_info_map(compilation); - - // Filter items were size < minSize - self.filter_items_lesser_than_min_size(&mut chunks_info_map, compilation); - - let split_chunks_span = tracing::trace_span!("split chunks with chunks_info_map"); - split_chunks_span.in_scope(|| { - while !chunks_info_map.is_empty() { - let (best_entry_key, mut item) = self.find_best_entry(&mut chunks_info_map); - let item_cache_group = item.cache_group(&self.cache_group_by_key); - - let mut chunk_name = item.name.clone(); - let mut new_chunk: Option = None; - let mut is_existing_chunk = false; - let mut is_reused_with_all_modules = false; - if let Some(chunk_name) = chunk_name.clone() { - let chunk_by_name = compilation.named_chunks.get(&chunk_name); - if let Some(chunk_by_name) = chunk_by_name { - let chunk = compilation.chunk_by_ukey.expect_get_mut(chunk_by_name); - let old_size = item.chunks.len(); - item.chunks.remove(&chunk.ukey); - is_existing_chunk = item.chunks.len() != old_size; - new_chunk = Some(chunk.ukey); - } - } else if item_cache_group.reuse_existing_chunk { - new_chunk = self.find_reusable_chunk(compilation, &item, new_chunk); - if let Some(new_chunk) = new_chunk { - item.chunks.remove(&new_chunk); - chunk_name = None; - is_existing_chunk = true; - is_reused_with_all_modules = true; - } - }; - - let enforced = check_min_size(&item.sizes, &item_cache_group.min_size); - - let mut used_chunks = item.chunks.clone(); - - // Check if maxRequests condition can be fulfilled - if !enforced - && (item - .cache_group(&self.cache_group_by_key) - .max_initial_requests - == u32::MAX - || item - .cache_group(&self.cache_group_by_key) - .max_async_requests - == u32::MAX) - { - for chunk in used_chunks.clone() { - let chunk = compilation.chunk_by_ukey.expect_get(&chunk); - let max_requests = if chunk.is_only_initial(&compilation.chunk_group_by_ukey) { - item_cache_group.max_initial_requests - } else { - if chunk.can_be_initial(&compilation.chunk_group_by_ukey) { - u32::min( - item - .cache_group(&self.cache_group_by_key) - .max_initial_requests, - item - .cache_group(&self.cache_group_by_key) - .max_async_requests, - ) - } else { - item - .cache_group(&self.cache_group_by_key) - .max_async_requests - } - }; - if u32::MAX == max_requests - && get_requests(chunk, &compilation.chunk_group_by_ukey) > max_requests - { - used_chunks.remove(&chunk.ukey); - } - } - } - - self.remove_unrelated_chunk(compilation, &mut used_chunks, &item); - - // Were some (invalid) chunks removed from usedChunks? - // => readd all modules to the queue, as things could have been changed - if used_chunks.len() < item.chunks.len() { - if is_existing_chunk { - used_chunks.insert(*new_chunk.as_ref().expect("New chunk not found")); - } - if used_chunks.len() >= item_cache_group.min_chunks as usize { - let chunk_arr = used_chunks - .iter() - .filter_map(|ukey| get_chunk_from_ukey(ukey, &compilation.chunk_by_ukey)) - .collect::>(); - for module in &item.modules { - self.add_module_to_chunks_info_map( - item_cache_group, - item.cache_group_index, - &chunk_arr, - &**compilation - .module_graph - .module_by_identifier(module) - .expect("Module not found"), - &mut chunks_info_map, - &compilation.named_chunks, - &compilation.chunk_by_ukey, // compilation, - &compilation.chunk_group_by_ukey, - ) - } - } - continue; - }; - - // Validate minRemainingSize constraint when a single chunk is left over - if !enforced && item_cache_group.validate_remaining_size && used_chunks.len() == 1 { - let chunk = used_chunks.iter().next().expect("Chunk should exist"); - let mut chunk_sizes = SplitChunkSizes::default(); - for module in compilation - .chunk_graph - .get_chunk_modules(chunk, &compilation.module_graph) - { - let module = compilation - .module_graph - .module_by_identifier(&module.identifier()) - .expect("Module should exist"); - if !item.modules.contains(&module.identifier()) { - for ty in module.source_types() { - let sizes = chunk_sizes.entry(*ty).or_default(); - *sizes += module.size(ty); - } - } - } - let violating_sizes = get_violating_min_sizes( - &chunk_sizes, - &item - .cache_group(&self.cache_group_by_key) - .min_remaining_size, - ); - if let Some(violating_sizes) = violating_sizes { - let old_modules_size = item.modules.len(); - remove_modules_with_source_type( - &mut item, - &violating_sizes, - &mut compilation.module_graph, - ); - if !item.modules.is_empty() && item.modules.len() != old_modules_size { - // queue this item again to be processed again - // without violating modules - chunks_info_map.insert(best_entry_key, item); - } - continue; - } - } - - // Create the new chunk if not reusing one - let new_chunk = if let Some(existed) = new_chunk { - existed - } else { - if let Some(chunk_name) = &chunk_name { - Compilation::add_named_chunk( - chunk_name.clone(), - &mut compilation.chunk_by_ukey, - &mut compilation.named_chunks, - ) - } else { - tracing::debug!( - "create a non-named chunk for cache group {}", - item_cache_group.key - ); - Compilation::add_chunk(&mut compilation.chunk_by_ukey) - } - }; - - compilation.chunk_graph.add_chunk(new_chunk); - - // Walk through all chunks - let new_chunk_ukey = new_chunk; - self.split_used_chunks(&used_chunks, new_chunk, compilation); - - let new_chunk = compilation.chunk_by_ukey.expect_get_mut(&new_chunk_ukey); - let new_chunk_ukey = new_chunk.ukey; - new_chunk.chunk_reasons.push(if is_reused_with_all_modules { - "reused as split chunk".to_string() - } else { - "split chunk".to_string() - }); - - new_chunk - .chunk_reasons - .push(format!("(cache group: {})", item_cache_group.key)); - - if let Some(chunk_name) = &chunk_name { - new_chunk - .chunk_reasons - .push(format!("(name: {chunk_name})")); - } - - // new_chunk.id_name_hints.insert(info) - - self.link_module_new_chunk_and_remove_in_old_chunks( - is_reused_with_all_modules, - &item, - new_chunk.ukey, - &used_chunks, - compilation, - ); - - let mut max_size_queue_map: HashMap = Default::default(); - - if !item - .cache_group(&self.cache_group_by_key) - .max_async_size - .is_empty() - || !item - .cache_group(&self.cache_group_by_key) - .max_initial_size - .is_empty() - { - let old_max_size_settings = max_size_queue_map.remove(&new_chunk_ukey); - max_size_queue_map.insert( - new_chunk_ukey, - MaxSizeQueueItem { - min_size: old_max_size_settings - .as_ref() - .map(|old| { - combine_sizes( - &old.min_size, - &item - .cache_group(&self.cache_group_by_key) - .min_size_for_max_size, - f64::max, - ) - }) - .unwrap_or_else(|| item_cache_group.min_size.clone()), - max_async_size: old_max_size_settings - .as_ref() - .map(|old| { - combine_sizes( - &old.max_async_size, - &item_cache_group.max_async_size, - f64::min, - ) - }) - .unwrap_or_else(|| { - item - .cache_group(&self.cache_group_by_key) - .max_async_size - .clone() - }), - max_initial_size: old_max_size_settings - .as_ref() - .map(|old| { - combine_sizes( - &old.max_initial_size, - &item_cache_group.max_initial_size, - f64::min, - ) - }) - .unwrap_or_else(|| { - item - .cache_group(&self.cache_group_by_key) - .max_initial_size - .clone() - }), - keys: old_max_size_settings - .map(|mut old| { - old.keys.push(item_cache_group.key.clone()); - old.keys - }) - .unwrap_or_else(|| vec![item_cache_group.key.clone()]), - }, - ); - } - - // remove all modules from other entries and update size - self.remove_all_modules_from_other_entries_and_update_size( - &mut item, - &mut chunks_info_map, - &mut used_chunks, - compilation, - ) - } - }); - - // Make sure that maxSize is fulfilled - // let fallbackCacheGroup = self.options.f - - Ok(()) - } -} diff --git a/crates/rspack_plugin_split_chunks/src/utils.rs b/crates/rspack_plugin_split_chunks/src/utils.rs deleted file mode 100644 index c54c1937b9f5..000000000000 --- a/crates/rspack_plugin_split_chunks/src/utils.rs +++ /dev/null @@ -1,202 +0,0 @@ -use std::{cmp::Ordering, sync::Arc}; - -use rspack_core::{Chunk, ChunkGroupByUkey, ModuleIdentifier, SourceType}; -use rspack_util::comparators::compare_ids; -use rustc_hash::FxHashMap as HashMap; - -use crate::{ - CacheGroupByKey, ChunkFilterFn, ChunkType, ChunksInfoItem, SizeType, SplitChunkSizes, - SplitChunksSizes, -}; - -pub(crate) fn compare_entries( - a: &ChunksInfoItem, - b: &ChunksInfoItem, - cache_group_by_key: &CacheGroupByKey, -) -> f64 { - // 1. by priority - let diff_priority = a.cache_group(cache_group_by_key).priority as f64 - - b.cache_group(cache_group_by_key).priority as f64; - if diff_priority != 0f64 { - return diff_priority; - } - // 2. by number of chunks - let diff_count = a.chunks.len() as f64 - b.chunks.len() as f64; - if diff_count != 0f64 { - return diff_count; - } - - // 3. by size reduction - let a_size_reduce = total_size(&a.sizes) * (a.chunks.len() - 1) as f64; - let b_size_reduce = total_size(&b.sizes) * (b.chunks.len() - 1) as f64; - let diff_size_reduce = a_size_reduce - b_size_reduce; - if diff_size_reduce != 0f64 { - return diff_size_reduce; - } - // 4. by cache group index - let index_diff = b.cache_group_index as f64 - a.cache_group_index as f64; - if index_diff != 0f64 { - return index_diff; - } - - // 5. by number of modules (to be able to compare by identifier) - let modules_a_len = a.modules.len(); - let modules_b_len = b.modules.len(); - let diff = modules_a_len as f64 - modules_b_len as f64; - if diff != 0f64 { - return diff; - } - - let mut modules_a = a.modules.iter().collect::>(); - let mut modules_b = b.modules.iter().collect::>(); - modules_a.sort_unstable(); - modules_b.sort_unstable(); - compare_modules(&modules_a, &modules_b) as usize as f64 -} - -fn total_size(sizes: &SplitChunkSizes) -> f64 { - sizes.values().cloned().sum() -} - -fn compare_modules(a: &[&ModuleIdentifier], b: &[&ModuleIdentifier]) -> Ordering { - let mut a_i = a.iter(); - let mut b_i = b.iter(); - loop { - let a_item = a_i.next(); - let b_item = b_i.next(); - if a_item.is_none() { - return if b_item.is_none() { - Ordering::Equal - } else { - Ordering::Less - }; - } else if b_item.is_none() { - return Ordering::Greater; - } - let res = compare_ids( - a_item.expect("Should be Some"), - b_item.expect("Should be Some"), - ); - if res != Ordering::Equal { - return res; - } - } -} - -pub(crate) fn check_min_size(sizes: &SplitChunkSizes, min_size: &SplitChunkSizes) -> bool { - for key in sizes.keys() { - let size = sizes.get(key).expect("key should exist"); - if size == &0f64 { - continue; - } - if min_size.get(key).map_or(false, |min_size| size < min_size) { - return false; - } - } - true -} - -pub(crate) fn get_violating_min_sizes( - sizes: &SplitChunkSizes, - min_size: &SplitChunkSizes, -) -> Option> { - let mut list: Option> = None; - for key in min_size.keys() { - let size = sizes.get(key).unwrap_or(&0f64); - if size == &0f64 { - continue; - }; - let min_size = min_size.get(key).unwrap_or(&0f64); - if size < min_size { - list.get_or_insert_default().push(*key); - } - } - list -} - -pub(crate) fn check_min_size_reduction( - sizes: &SplitChunkSizes, - min_size_reduction: &SplitChunkSizes, - chunk_count: usize, -) -> bool { - for key in min_size_reduction.keys() { - let size = sizes.get(key).unwrap_or(&0f64); - if size == &0f64 { - continue; - }; - let min_size_reduction = min_size_reduction.get(key).unwrap_or(&0f64); - if (size * chunk_count as f64) < *min_size_reduction { - return false; - } - } - true -} - -pub(crate) fn get_requests(chunk: &Chunk, chunk_group_by_ukey: &ChunkGroupByUkey) -> u32 { - let mut requests = 0; - for group in &chunk.groups { - let group = chunk_group_by_ukey.expect_get(group); - requests = u32::max(requests, group.chunks.len() as u32) - } - requests -} - -pub(crate) fn combine_sizes( - a: &SplitChunkSizes, - b: &SplitChunkSizes, - combine: impl Fn(f64, f64) -> f64, -) -> SplitChunkSizes { - let a_keys = a.keys(); - let b_keys = b.keys(); - let mut res: SplitChunkSizes = Default::default(); - for key in a_keys { - if b.contains_key(key) { - res.insert(*key, combine(a[key], b[key])); - } else { - res.insert(*key, a[key]); - } - } - - for key in b_keys { - if !a.contains_key(key) { - res.insert(*key, b[key]); - } - } - - res -} - -pub(crate) fn normalize_sizes( - value: Option, - default_size_types: &[SizeType], -) -> HashMap { - value - .map(|value| { - default_size_types - .iter() - .cloned() - .map(|size_type| (size_type, value.clone())) - .collect::>() - }) - .unwrap_or_default() -} - -pub(crate) fn merge_sizes2( - mut a: HashMap, - b: HashMap, -) -> HashMap { - a.extend(b); - a -} - -pub(crate) fn merge_sizes(sizes: Vec) -> SplitChunkSizes { - let mut res: SplitChunkSizes = Default::default(); - for size in sizes { - res.extend(size) - } - res -} - -pub(crate) fn normalize_chunks_filter(chunk_type: ChunkType) -> ChunkFilterFn { - Arc::new(move |chunk, chunk_group_by_ukey| chunk_type.is_selected(chunk, chunk_group_by_ukey)) -} diff --git a/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts b/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts index a1eb96ba8a18..1e68a203badf 100644 --- a/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts +++ b/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts @@ -32,21 +32,6 @@ export class SplitChunksPlugin extends RspackBuiltinPlugin { } } -export class OldSplitChunksPlugin extends RspackBuiltinPlugin { - name = BuiltinPluginName.OldSplitChunksPlugin; - affectedHooks = "thisCompilation" as const; - - constructor(private options: OptimizationSplitChunksOptions) { - super(); - } - - raw(compiler: Compiler): BuiltinPlugin { - const rawOptions = toRawSplitChunksOptions(this.options, compiler); - assert(typeof rawOptions !== "undefined"); - return createBuiltinPlugin(this.name, rawOptions); - } -} - function toRawSplitChunksOptions( sc: false | OptimizationSplitChunksOptions, compiler: Compiler diff --git a/packages/rspack/src/builtin-plugin/base.ts b/packages/rspack/src/builtin-plugin/base.ts index a5a5a5da8fc6..48c96e55a9bd 100644 --- a/packages/rspack/src/builtin-plugin/base.ts +++ b/packages/rspack/src/builtin-plugin/base.ts @@ -29,7 +29,6 @@ export enum BuiltinPluginName { WebWorkerTemplatePlugin = "WebWorkerTemplatePlugin", MergeDuplicateChunksPlugin = "MergeDuplicateChunksPlugin", SplitChunksPlugin = "SplitChunksPlugin", - OldSplitChunksPlugin = "OldSplitChunksPlugin", ShareRuntimePlugin = "ShareRuntimePlugin", ContainerPlugin = "ContainerPlugin", ContainerReferencePlugin = "ContainerReferencePlugin", diff --git a/packages/rspack/src/rspackOptionsApply.ts b/packages/rspack/src/rspackOptionsApply.ts index 2f927c1a8acd..d0965bf24230 100644 --- a/packages/rspack/src/rspackOptionsApply.ts +++ b/packages/rspack/src/rspackOptionsApply.ts @@ -36,7 +36,6 @@ import { DefinePlugin, MergeDuplicateChunksPlugin, SplitChunksPlugin, - OldSplitChunksPlugin, ChunkPrefetchPreloadPlugin, NamedModuleIdsPlugin, DeterministicModuleIdsPlugin, @@ -279,14 +278,7 @@ export class RspackOptionsApply { options.optimization.mangleExports !== "size" ).apply(compiler); } - if ( - options.optimization.splitChunks && - options.experiments.newSplitChunks === false - ) { - new OldSplitChunksPlugin(options.optimization.splitChunks).apply( - compiler - ); - } else if (options.optimization.splitChunks) { + if (options.optimization.splitChunks) { new SplitChunksPlugin(options.optimization.splitChunks).apply(compiler); } // TODO: inconsistent: the plugin need to be placed after SplitChunksPlugin