Skip to content

Commit

Permalink
feat: support test, include and exclude options for `SwcCssMini…
Browse files Browse the repository at this point in the history
…mizerRspackPlugin` (#7111)

* pass options top minimizer

* update docs

* fix api.md

* move match_object to lib.rs

* Update crates/rspack_plugin_swc_css_minimizer/src/lib.rs

Co-authored-by: Gengkun <[email protected]>

* remove unnecessary default spread

* fix rustfmt error

---------

Co-authored-by: Gengkun <[email protected]>
  • Loading branch information
simonxabris and ahabhgk authored Jul 14, 2024
1 parent 070a6c5 commit 7540e88
Show file tree
Hide file tree
Showing 16 changed files with 271 additions and 8 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1499,6 +1499,12 @@ export interface RawStatsOptions {
colors: boolean
}

export interface RawSwcCssMinimizerRspackPluginOptions {
test?: string | RegExp | (string | RegExp)[]
include?: string | RegExp | (string | RegExp)[]
exclude?: string | RegExp | (string | RegExp)[]
}

export interface RawSwcJsMinimizerRspackPluginOptions {
extractComments?: RawExtractComments
compress: any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ mod raw_mf;
mod raw_progress;
mod raw_runtime_chunk;
mod raw_size_limits;
mod raw_swc_css_minimizer;
mod raw_swc_js_minimizer;

use napi::{bindgen_prelude::FromNapiValue, Env, JsUnknown};
use napi_derive::napi;
use raw_lightning_css_minimizer::RawLightningCssMinimizerRspackPluginOptions;
use raw_swc_css_minimizer::RawSwcCssMinimizerRspackPluginOptions;
use rspack_core::{BoxPlugin, Plugin, PluginExt};
use rspack_error::Result;
use rspack_ids::{
Expand Down Expand Up @@ -447,7 +449,11 @@ impl BuiltinPlugin {
plugins.push(plugin);
}
BuiltinPluginName::SwcCssMinimizerRspackPlugin => {
plugins.push(SwcCssMinimizerRspackPlugin::default().boxed())
let plugin = SwcCssMinimizerRspackPlugin::new(
downcast_into::<RawSwcCssMinimizerRspackPluginOptions>(self.options)?.try_into()?,
)
.boxed();
plugins.push(plugin);
}
BuiltinPluginName::LightningCssMinimizerRspackPlugin => plugins.push(
LightningCssMinimizerRspackPlugin::new(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use napi::{bindgen_prelude::Either3, Either};
use napi_derive::napi;
use rspack_error::Result;
use rspack_napi::regexp::{JsRegExp, JsRegExpExt};
use rspack_plugin_swc_css_minimizer::{
SwcCssMinimizerRspackPluginOptions, SwcCssMinimizerRule, SwcCssMinimizerRules,
};

type RawSwcCssMinimizerRule = Either<String, JsRegExp>;
type RawSwcCssMinimizerRules = Either3<String, JsRegExp, Vec<RawSwcCssMinimizerRule>>;
struct RawSwcCssMinimizerRuleWrapper(RawSwcCssMinimizerRule);
struct RawSwcCssMinimizerRulesWrapper(RawSwcCssMinimizerRules);

#[derive(Debug)]
#[napi(object, object_to_js = false)]
pub struct RawSwcCssMinimizerRspackPluginOptions {
#[napi(ts_type = "string | RegExp | (string | RegExp)[]")]
pub test: Option<RawSwcCssMinimizerRules>,
#[napi(ts_type = "string | RegExp | (string | RegExp)[]")]
pub include: Option<RawSwcCssMinimizerRules>,
#[napi(ts_type = "string | RegExp | (string | RegExp)[]")]
pub exclude: Option<RawSwcCssMinimizerRules>,
}

fn into_condition(c: Option<RawSwcCssMinimizerRules>) -> Option<SwcCssMinimizerRules> {
c.map(|test| RawSwcCssMinimizerRulesWrapper(test).into())
}

impl TryFrom<RawSwcCssMinimizerRspackPluginOptions> for SwcCssMinimizerRspackPluginOptions {
type Error = rspack_error::Error;

fn try_from(value: RawSwcCssMinimizerRspackPluginOptions) -> Result<Self> {
Ok(Self {
test: into_condition(value.test),
include: into_condition(value.include),
exclude: into_condition(value.exclude),
})
}
}

impl From<RawSwcCssMinimizerRuleWrapper> for SwcCssMinimizerRule {
fn from(x: RawSwcCssMinimizerRuleWrapper) -> Self {
match x.0 {
Either::A(v) => Self::String(v),
Either::B(v) => Self::Regexp(v.to_rspack_regex()),
}
}
}

impl From<RawSwcCssMinimizerRulesWrapper> for SwcCssMinimizerRules {
fn from(value: RawSwcCssMinimizerRulesWrapper) -> Self {
match value.0 {
Either3::A(v) => Self::String(v),
Either3::B(v) => Self::Regexp(v.to_rspack_regex()),
Either3::C(v) => Self::Array(
v.into_iter()
.map(|v| RawSwcCssMinimizerRuleWrapper(v).into())
.collect(),
),
}
}
}
2 changes: 2 additions & 0 deletions crates/rspack_plugin_swc_css_minimizer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ rspack_error = { path = "../rspack_error" }
rspack_hook = { path = "../rspack_hook" }
swc_core = { workspace = true, features = ["css_codegen", "css_parser", "css_minifier"] }
tracing = { workspace = true }
rspack_regex = { path = "../rspack_regex" }
rspack_util = { path = "../rspack_util" }

[package.metadata.cargo-shear]
ignored = ["tracing"]
86 changes: 84 additions & 2 deletions crates/rspack_plugin_swc_css_minimizer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,52 @@ use regex::Regex;
use rspack_core::{rspack_sources::MapOptions, Compilation, CompilationProcessAssets, Plugin};
use rspack_error::Result;
use rspack_hook::{plugin, plugin_hook};
use rspack_regex::RspackRegex;
use rspack_util::try_any_sync;
use swc_css_compiler::{SwcCssCompiler, SwcCssSourceMapGenConfig};

static CSS_ASSET_REGEXP: Lazy<Regex> =
Lazy::new(|| Regex::new(r"\.css(\?.*)?$").expect("Invalid RegExp"));

#[derive(Debug, Default)]
pub struct SwcCssMinimizerRspackPluginOptions {
pub test: Option<SwcCssMinimizerRules>,
pub include: Option<SwcCssMinimizerRules>,
pub exclude: Option<SwcCssMinimizerRules>,
}

#[plugin]
#[derive(Debug, Default)]
pub struct SwcCssMinimizerRspackPlugin;
pub struct SwcCssMinimizerRspackPlugin {
options: SwcCssMinimizerRspackPluginOptions,
}

impl SwcCssMinimizerRspackPlugin {
pub fn new(options: SwcCssMinimizerRspackPluginOptions) -> Self {
Self::new_inner(options)
}
}

#[plugin_hook(CompilationProcessAssets for SwcCssMinimizerRspackPlugin, stage = Compilation::PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE)]
async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
let minify_options = &self.options;

compilation
.assets_mut()
.par_iter_mut()
.filter(|(filename, _)| CSS_ASSET_REGEXP.is_match(filename))
.filter(|(filename, original)| {
if !CSS_ASSET_REGEXP.is_match(filename) {
return false;
}

let is_matched = match_object(minify_options, filename).unwrap_or(false);

if !is_matched || original.get_info().minimized {
return false;
}

true
})
.try_for_each(|(filename, original)| -> Result<()> {
if original.get_info().minimized {
return Ok(());
Expand Down Expand Up @@ -69,3 +100,54 @@ impl Plugin for SwcCssMinimizerRspackPlugin {

// TODO: chunk hash
}

#[derive(Debug, Clone, Hash)]
pub enum SwcCssMinimizerRule {
String(String),
Regexp(RspackRegex),
}

impl SwcCssMinimizerRule {
pub fn try_match(&self, data: &str) -> rspack_error::Result<bool> {
match self {
Self::String(s) => Ok(data.starts_with(s)),
Self::Regexp(r) => Ok(r.test(data)),
}
}
}

#[derive(Debug, Clone, Hash)]
pub enum SwcCssMinimizerRules {
String(String),
Regexp(rspack_regex::RspackRegex),
Array(Vec<SwcCssMinimizerRule>),
}

impl SwcCssMinimizerRules {
pub fn try_match(&self, data: &str) -> rspack_error::Result<bool> {
match self {
Self::String(s) => Ok(data.starts_with(s)),
Self::Regexp(r) => Ok(r.test(data)),
Self::Array(l) => try_any_sync(l, |i| i.try_match(data)),
}
}
}

pub fn match_object(obj: &SwcCssMinimizerRspackPluginOptions, str: &str) -> Result<bool> {
if let Some(condition) = &obj.test {
if !condition.try_match(str)? {
return Ok(false);
}
}
if let Some(condition) = &obj.include {
if !condition.try_match(str)? {
return Ok(false);
}
}
if let Some(condition) = &obj.exclude {
if condition.try_match(str)? {
return Ok(false);
}
}
Ok(true)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
html {
margin: 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require("./a.css");
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
html {
margin: 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require("./b.css");
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const fs = require("fs");
const path = require("path");

it("[minify-exclude-css]: chunk a should be minified", () => {
const content = fs.readFileSync(path.resolve(__dirname, "a.css"), "utf-8");
expect(content).not.toMatch("\n");
});

it("[minify-exclude-css]: chunk b should not be minified", () => {
const content = fs.readFileSync(path.resolve(__dirname, "b.css"), "utf-8");
expect(content).toMatch("\n");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const rspack = require("@rspack/core");
/**
* @type {import("@rspack/core").Configuration}
*/
module.exports = {
entry: {
a: "./a.js",
b: "./b.js",
main: "./index.js"
},
output: {
filename: "[name].js"
},
module: {
generator: {
"css/auto": {
exportsOnly: false
}
}
},
optimization: {
minimize: true,
minimizer: [
new rspack.SwcCssMinimizerRspackPlugin({
exclude: [/b\.css/]
})
]
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import("../../../..").TConfigCaseConfig} */
module.exports = {
findBundle: (i, options) => {
return ["main.js"];
}
};
17 changes: 15 additions & 2 deletions packages/rspack/etc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5004,9 +5004,15 @@ const matchPart: (str: string, test: Matcher) => boolean;
// @public (undocumented)
type MinifyCondition = string | RegExp;

// @public (undocumented)
type MinifyCondition_2 = string | RegExp;

// @public (undocumented)
type MinifyConditions = MinifyCondition | MinifyCondition[];

// @public (undocumented)
type MinifyConditions_2 = MinifyCondition_2 | MinifyCondition_2[];

// @public (undocumented)
export type Mode = z.infer<typeof mode>;

Expand Down Expand Up @@ -13143,15 +13149,22 @@ const strictModuleExceptionHandling: z.ZodBoolean;

// @public (undocumented)
export const SwcCssMinimizerRspackPlugin: {
new (options?: any): {
new (options?: SwcCssMinimizerRspackPluginOptions | undefined): {
name: BuiltinPluginName;
_args: [options?: any];
_args: [options?: SwcCssMinimizerRspackPluginOptions | undefined];
affectedHooks: "done" | "compilation" | "failed" | "environment" | "emit" | "make" | "compile" | "afterEmit" | "invalid" | "thisCompilation" | "afterDone" | "normalModuleFactory" | "contextModuleFactory" | "initialize" | "shouldEmit" | "infrastructureLog" | "beforeRun" | "run" | "assetEmitted" | "shutdown" | "watchRun" | "watchClose" | "afterEnvironment" | "afterPlugins" | "afterResolvers" | "beforeCompile" | "afterCompile" | "finishMake" | "entryOption" | undefined;
raw(compiler: Compiler_2): BuiltinPlugin;
apply(compiler: Compiler_2): void;
};
};

// @public (undocumented)
type SwcCssMinimizerRspackPluginOptions = {
test?: MinifyConditions_2;
exclude?: MinifyConditions_2;
include?: MinifyConditions_2;
};

// @public (undocumented)
export const SwcJsMinimizerRspackPlugin: {
new (options?: SwcJsMinimizerRspackPluginOptions | undefined): {
Expand Down
24 changes: 22 additions & 2 deletions packages/rspack/src/builtin-plugin/SwcCssMinimizerPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
import { BuiltinPluginName } from "@rspack/binding";
import {
BuiltinPluginName,
RawSwcCssMinimizerRspackPluginOptions
} from "@rspack/binding";

import { create } from "./base";

type MinifyCondition = string | RegExp;
type MinifyConditions = MinifyCondition | MinifyCondition[];

export type SwcCssMinimizerRspackPluginOptions = {
test?: MinifyConditions;
exclude?: MinifyConditions;
include?: MinifyConditions;
};

export const SwcCssMinimizerRspackPlugin = create(
BuiltinPluginName.SwcCssMinimizerRspackPlugin,
(options?: any /* TODO: extend more options */) => undefined
(
options?: SwcCssMinimizerRspackPluginOptions
): RawSwcCssMinimizerRspackPluginOptions => {
return {
test: options?.test,
include: options?.include,
exclude: options?.exclude
};
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,22 @@ This plugin can be used to compress CSS assets. See [optimization.minimizer](/co
module.exports = {
// ...
optimization: {
minimizer: [new rspack.SwcCssMinimizerRspackPlugin()],
minimizer: [new rspack.SwcCssMinimizerRspackPlugin(options)],
},
};
```

- options

- **Type:**

```ts
type SwcCssMinimizerRspackPluginOptions = {
test?: MinifyConditions;
exclude?: MinifyConditions;
include?: MinifyConditions;
};

type MinifyCondition = string | RegExp;
type MinifyConditions = MinifyCondition | MinifyCondition[];
```

2 comments on commit 7540e88

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ran ecosystem CI: Open

suite result
modernjs ❌ failure
_selftest ✅ success
nx ✅ success
rspress ✅ success
rsbuild ✅ success
examples ✅ success

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2024-07-14 070a6c5) Current Change
10000_development-mode + exec 2.24 s ± 19 ms 2.22 s ± 16 ms -0.63 %
10000_development-mode_hmr + exec 698 ms ± 4.9 ms 696 ms ± 6.1 ms -0.26 %
10000_production-mode + exec 2.81 s ± 22 ms 2.82 s ± 43 ms +0.31 %
arco-pro_development-mode + exec 1.92 s ± 69 ms 1.91 s ± 81 ms -0.42 %
arco-pro_development-mode_hmr + exec 435 ms ± 2.1 ms 434 ms ± 0.6 ms -0.27 %
arco-pro_production-mode + exec 3.43 s ± 53 ms 3.43 s ± 67 ms -0.02 %
threejs_development-mode_10x + exec 1.68 s ± 20 ms 1.69 s ± 22 ms +0.42 %
threejs_development-mode_10x_hmr + exec 862 ms ± 6.4 ms 862 ms ± 6.1 ms -0.05 %
threejs_production-mode_10x + exec 5.68 s ± 24 ms 5.66 s ± 33 ms -0.31 %

Please sign in to comment.