diff --git a/crates/mako/src/build/transform.rs b/crates/mako/src/build/transform.rs index b76481998..4f57cf79d 100644 --- a/crates/mako/src/build/transform.rs +++ b/crates/mako/src/build/transform.rs @@ -14,7 +14,7 @@ use swc_core::ecma::transforms::base::helpers::{Helpers, HELPERS}; use swc_core::ecma::transforms::base::{resolver, Assumptions}; use swc_core::ecma::transforms::compat::reserved_words; use swc_core::ecma::transforms::optimization::simplifier; -use swc_core::ecma::transforms::optimization::simplify::{dce, Config as SimpilifyConfig}; +use swc_core::ecma::transforms::optimization::simplify::{dce, Config as SimplifyConfig}; use swc_core::ecma::transforms::proposal::decorators; use swc_core::ecma::visit::{Fold, VisitMut}; @@ -236,7 +236,7 @@ impl Transform { // this must be kept for tree shaking to work Box::new(simplifier( unresolved_mark, - SimpilifyConfig { + SimplifyConfig { dce: dce::Config { top_level: false, ..Default::default() diff --git a/crates/mako/src/config/code_splitting.rs b/crates/mako/src/config/code_splitting.rs index 73e973f98..e517ce539 100644 --- a/crates/mako/src/config/code_splitting.rs +++ b/crates/mako/src/config/code_splitting.rs @@ -1,11 +1,10 @@ -use regex::Regex; use serde::{Deserialize, Serialize}; use super::generic_usize::GenericUsizeDefault; use crate::create_deserialize_fn; -#[derive(Deserialize, Serialize, Clone, Debug, Default)] -pub enum OptimizeAllowChunks { +#[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)] +pub enum AllowChunks { #[serde(rename = "all")] All, #[serde(rename = "entry")] @@ -51,7 +50,7 @@ pub struct CodeSplittingGranularOptions { pub struct CodeSplittingAdvancedOptions { #[serde(default = "GenericUsizeDefault::<20000>::value")] pub min_size: usize, - pub groups: Vec, + pub groups: Vec, } impl Default for CodeSplittingAdvancedOptions { @@ -63,22 +62,22 @@ impl Default for CodeSplittingAdvancedOptions { } } -#[derive(Deserialize, Serialize, Clone, Debug)] -pub enum OptimizeChunkNameSuffixStrategy { +#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] +pub enum ChunkNameSuffixStrategy { #[serde(rename = "packageName")] PackageName, #[serde(rename = "dependentsHash")] DependentsHash, } -#[derive(Deserialize, Serialize, Clone, Debug)] +#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] #[serde(rename_all = "camelCase")] -pub struct OptimizeChunkGroup { +pub struct ChunkGroup { pub name: String, #[serde(default)] - pub name_suffix: Option, + pub name_suffix: Option, #[serde(default)] - pub allow_chunks: OptimizeAllowChunks, + pub allow_chunks: AllowChunks, #[serde(default = "GenericUsizeDefault::<1>::value")] pub min_chunks: usize, #[serde(default = "GenericUsizeDefault::<20000>::value")] @@ -89,14 +88,15 @@ pub struct OptimizeChunkGroup { pub min_module_size: Option, #[serde(default)] pub priority: i8, - #[serde(default, with = "optimize_test_format")] - pub test: Option, + #[serde(default)] + // A string raw of regex + pub test: Option, } -impl Default for OptimizeChunkGroup { +impl Default for ChunkGroup { fn default() -> Self { Self { - allow_chunks: OptimizeAllowChunks::default(), + allow_chunks: AllowChunks::default(), min_chunks: GenericUsizeDefault::<1>::value(), min_size: GenericUsizeDefault::<20000>::value(), max_size: GenericUsizeDefault::<5000000>::value(), @@ -109,37 +109,4 @@ impl Default for OptimizeChunkGroup { } } -/** - * custom formatter for convert string to regex - * @see https://serde.rs/custom-date-format.html - */ -mod optimize_test_format { - use regex::Regex; - use serde::{self, Deserialize, Deserializer, Serializer}; - - pub fn serialize(v: &Option, serializer: S) -> Result - where - S: Serializer, - { - if let Some(v) = v { - serializer.serialize_str(&v.to_string()) - } else { - serializer.serialize_none() - } - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let v = String::deserialize(deserializer)?; - - if v.is_empty() { - Ok(None) - } else { - Ok(Regex::new(v.as_str()).ok()) - } - } -} - create_deserialize_fn!(deserialize_code_splitting, CodeSplitting); diff --git a/crates/mako/src/generate/optimize_chunk.rs b/crates/mako/src/generate/optimize_chunk.rs index 72d6ff928..c5d0b2db9 100644 --- a/crates/mako/src/generate/optimize_chunk.rs +++ b/crates/mako/src/generate/optimize_chunk.rs @@ -3,23 +3,22 @@ use std::string::String; use hashlink::LinkedHashSet; use indexmap::{IndexMap, IndexSet}; -use regex::Regex; use tracing::debug; use crate::compiler::Compiler; use crate::config::{ - CodeSplitting, CodeSplittingAdvancedOptions, CodeSplittingGranularOptions, - CodeSplittingStrategy, CodeSplittingStrategyOptions, GenericUsizeDefault, OptimizeAllowChunks, - OptimizeChunkGroup, OptimizeChunkNameSuffixStrategy, + AllowChunks, ChunkGroup, ChunkNameSuffixStrategy, CodeSplitting, CodeSplittingAdvancedOptions, + CodeSplittingGranularOptions, CodeSplittingStrategy, CodeSplittingStrategyOptions, + GenericUsizeDefault, }; use crate::generate::chunk::{Chunk, ChunkId, ChunkType}; use crate::generate::group_chunk::GroupUpdateResult; use crate::module::{Module, ModuleId, ModuleInfo}; use crate::resolve::{ResolvedResource, ResolverResource}; -use crate::utils::url_safe_base64_encode; +use crate::utils::{create_cached_regex, url_safe_base64_encode}; pub struct OptimizeChunksInfo { - pub group_options: OptimizeChunkGroup, + pub group_options: ChunkGroup, pub module_to_chunks: IndexMap>, } @@ -171,7 +170,7 @@ impl Compiler { // check test regex if let Some(test) = &optimize_info.group_options.test { - if !test.is_match(&module_id.id) { + if !create_cached_regex(test).is_match(&module_id.id) { continue; } } @@ -330,7 +329,7 @@ impl Compiler { for info in &mut *optimize_chunks_infos { if let Some(name_suffix) = &info.group_options.name_suffix { match name_suffix { - OptimizeChunkNameSuffixStrategy::PackageName => { + ChunkNameSuffixStrategy::PackageName => { let mut module_to_package_map: HashMap> = HashMap::new(); info.module_to_chunks.keys().for_each(|module_id| { @@ -367,7 +366,7 @@ impl Compiler { }) }); } - OptimizeChunkNameSuffixStrategy::DependentsHash => { + ChunkNameSuffixStrategy::DependentsHash => { let mut module_to_dependents_md5_map: HashMap> = HashMap::new(); info.module_to_chunks @@ -426,12 +425,11 @@ impl Compiler { let info_chunk_id = ChunkId { id: info.group_options.name.clone(), }; - let info_chunk_type = - if matches!(info.group_options.allow_chunks, OptimizeAllowChunks::Async) { - ChunkType::Sync - } else { - ChunkType::Entry(info_chunk_id.clone(), info.group_options.name.clone(), true) - }; + let info_chunk_type = if matches!(info.group_options.allow_chunks, AllowChunks::Async) { + ChunkType::Sync + } else { + ChunkType::Entry(info_chunk_id.clone(), info.group_options.name.clone(), true) + }; let info_chunk = Chunk { modules: info .module_to_chunks @@ -513,18 +511,14 @@ impl Compiler { /* the following is util methods */ - fn check_chunk_type_allow( - &self, - allow_chunks: &OptimizeAllowChunks, - chunk_type: &ChunkType, - ) -> bool { + fn check_chunk_type_allow(&self, allow_chunks: &AllowChunks, chunk_type: &ChunkType) -> bool { match allow_chunks { - OptimizeAllowChunks::All => matches!( + AllowChunks::All => matches!( chunk_type, &ChunkType::Entry(_, _, false) | &ChunkType::Async ), - OptimizeAllowChunks::Entry => matches!(chunk_type, &ChunkType::Entry(_, _, false)), - OptimizeAllowChunks::Async => chunk_type == &ChunkType::Async, + AllowChunks::Entry => matches!(chunk_type, &ChunkType::Entry(_, _, false)), + AllowChunks::Async => chunk_type == &ChunkType::Async, } } @@ -594,13 +588,13 @@ impl Compiler { fn code_splitting_strategy_auto() -> CodeSplittingAdvancedOptions { CodeSplittingAdvancedOptions { groups: vec![ - OptimizeChunkGroup { + ChunkGroup { name: "vendors".to_string(), - test: Regex::new(r"[/\\]node_modules[/\\]").ok(), + test: Some(r"[/\\]node_modules[/\\]".to_string()), priority: -10, ..Default::default() }, - OptimizeChunkGroup { + ChunkGroup { name: "common".to_string(), min_chunks: 2, // always split, to avoid multi-instance risk @@ -619,34 +613,36 @@ fn code_splitting_strategy_granular( ) -> CodeSplittingAdvancedOptions { CodeSplittingAdvancedOptions { groups: vec![ - OptimizeChunkGroup { + ChunkGroup { name: "framework".to_string(), - allow_chunks: OptimizeAllowChunks::All, + allow_chunks: AllowChunks::All, test: if framework_packages.is_empty() { - Regex::new("^$").ok() + Some("^$".to_string()) } else { - Regex::new(&format!( - r#"[/\\]node_modules[/\\].*({})[/\\]"#, - framework_packages.join("|") - )) - .ok() + Some( + format!( + r#"[/\\]node_modules[/\\].*({})[/\\]"#, + framework_packages.join("|") + ) + .to_string(), + ) }, priority: -10, ..Default::default() }, - OptimizeChunkGroup { + ChunkGroup { name: "lib".to_string(), - name_suffix: Some(OptimizeChunkNameSuffixStrategy::PackageName), - allow_chunks: OptimizeAllowChunks::Async, - test: Regex::new(r"[/\\]node_modules[/\\]").ok(), + name_suffix: Some(ChunkNameSuffixStrategy::PackageName), + allow_chunks: AllowChunks::Async, + test: Some(r"[/\\]node_modules[/\\]".to_string()), min_module_size: Some(lib_min_size), priority: -20, ..Default::default() }, - OptimizeChunkGroup { + ChunkGroup { name: "shared".to_string(), - name_suffix: Some(OptimizeChunkNameSuffixStrategy::DependentsHash), - allow_chunks: OptimizeAllowChunks::Async, + name_suffix: Some(ChunkNameSuffixStrategy::DependentsHash), + allow_chunks: AllowChunks::Async, priority: -30, min_chunks: 2, ..Default::default() diff --git a/crates/mako/src/plugins/ssu.rs b/crates/mako/src/plugins/ssu.rs index 843e3d152..9060a4794 100644 --- a/crates/mako/src/plugins/ssu.rs +++ b/crates/mako/src/plugins/ssu.rs @@ -8,15 +8,14 @@ use std::sync::{Arc, Mutex}; use anyhow::Result; use dashmap::DashSet; use rayon::prelude::*; -use regex::Regex; use serde::{Deserialize, Serialize}; use tracing::debug; use crate::ast::file::{Content, File, JsContent}; use crate::compiler::{Args, Compiler, Context}; use crate::config::{ - CodeSplitting, CodeSplittingAdvancedOptions, CodeSplittingStrategy, - CodeSplittingStrategyOptions, Config, OptimizeAllowChunks, OptimizeChunkGroup, + AllowChunks, ChunkGroup, CodeSplitting, CodeSplittingAdvancedOptions, CodeSplittingStrategy, + CodeSplittingStrategyOptions, Config, }; use crate::generate::chunk::ChunkType; use crate::generate::chunk_pot::util::{hash_hashmap, hash_vec}; @@ -164,18 +163,18 @@ impl Plugin for SUPlus { CodeSplittingAdvancedOptions { min_size: 0, groups: vec![ - OptimizeChunkGroup { + ChunkGroup { name: "node_modules".to_string(), name_suffix: None, - allow_chunks: OptimizeAllowChunks::All, + allow_chunks: AllowChunks::All, min_chunks: 0, min_size: 0, max_size: usize::MAX, min_module_size: None, priority: 10, - test: Regex::new(r"[/\\]node_modules[/\\]").ok(), + test: Some(r"[/\\]node_modules[/\\]".to_string()), }, - OptimizeChunkGroup { + ChunkGroup { name: "common".to_string(), min_chunks: 0, // always split, to avoid multi-instance risk diff --git a/crates/mako/src/utils.rs b/crates/mako/src/utils.rs index afde8941a..a469dd3a8 100644 --- a/crates/mako/src/utils.rs +++ b/crates/mako/src/utils.rs @@ -72,6 +72,7 @@ pub(crate) fn get_pkg_name(root: &Path) -> Option { pub fn create_cached_regex(re: &str) -> Regex { Regex::new(re).unwrap() } + #[cfg(test)] mod tests { use super::*;