Skip to content

Commit

Permalink
perf: use browserslist-rs for lightningcss (#7544)
Browse files Browse the repository at this point in the history
* perf: use browserslist-rs for lightningcss

* Update crates/rspack_binding_options/src/options/raw_builtins/raw_lightning_css_minimizer.rs

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

---------

Co-authored-by: Hana <[email protected]>
  • Loading branch information
JSerFeng and h-a-n-a authored Aug 13, 2024
1 parent 9bbfdbc commit ce9b3fa
Show file tree
Hide file tree
Showing 16 changed files with 82 additions and 121 deletions.
2 changes: 1 addition & 1 deletion crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1313,7 +1313,7 @@ export interface RawLightningCssBrowsers {

export interface RawLightningCssMinimizerOptions {
errorRecovery: boolean
targets?: RawLightningCssBrowsers
targets?: Array<string>
include?: number
exclude?: number
draft?: RawDraft
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use napi_derive::napi;
use rspack_binding_values::{into_asset_conditions, RawAssetConditions};
use rspack_error::Result;
use rspack_plugin_lightning_css_minimizer::{
Browsers, Draft, MinimizerOptions, NonStandard, PluginOptions, PseudoClasses,
Draft, MinimizerOptions, NonStandard, PluginOptions, PseudoClasses,
};

#[derive(Debug)]
Expand All @@ -22,7 +22,7 @@ pub struct RawLightningCssMinimizerRspackPluginOptions {
#[napi(object)]
pub struct RawLightningCssMinimizerOptions {
pub error_recovery: bool,
pub targets: Option<RawLightningCssBrowsers>,
pub targets: Option<Vec<String>>,
pub include: Option<u32>,
pub exclude: Option<u32>,
pub draft: Option<RawDraft>,
Expand Down Expand Up @@ -79,17 +79,15 @@ impl TryFrom<RawLightningCssMinimizerRspackPluginOptions> for PluginOptions {
remove_unused_local_idents: value.remove_unused_local_idents,
minimizer_options: MinimizerOptions {
error_recovery: value.minimizer_options.error_recovery,
targets: value.minimizer_options.targets.map(|t| Browsers {
android: t.android,
chrome: t.chrome,
edge: t.edge,
firefox: t.firefox,
ie: t.ie,
ios_saf: t.ios_saf,
opera: t.opera,
safari: t.safari,
samsung: t.samsung,
}),
targets: value
.minimizer_options
.targets
.map(|t| {
rspack_loader_lightningcss::lightningcss::targets::Browsers::from_browserslist(t)
})
.transpose()
.map_err(|e| rspack_error::error!("Failed to parse browserslist: {}", e))?
.flatten(),
include: value.minimizer_options.include,
exclude: value.minimizer_options.exclude,
draft: value.minimizer_options.draft.map(|d| Draft {
Expand Down
13 changes: 9 additions & 4 deletions crates/rspack_binding_options/src/plugins/js_loader/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,17 @@ pub fn get_builtin_loader(builtin: &str, options: Option<&str>) -> BoxLoader {
}

if builtin.starts_with(LIGHTNINGCSS_LOADER_IDENTIFIER) {
let config = serde_json::from_str(options.unwrap_or("{}")).unwrap_or_else(|e| {
panic!("Could not parse builtin:lightningcss-loader options:{options:?},error: {e:?}")
});
let config: rspack_loader_lightningcss::config::RawConfig =
serde_json::from_str(options.unwrap_or("{}")).unwrap_or_else(|e| {
panic!("Could not parse builtin:lightningcss-loader options:{options:?},error: {e:?}")
});
// TODO: builtin-loader supports function
return Arc::new(rspack_loader_lightningcss::LightningCssLoader::new(
None, config, builtin,
None,
config.try_into().unwrap_or_else(|e| {
panic!("Could not parse builtin:lightningcss-loader options:{options:?},error: {e:?}")
}),
builtin,
));
}

Expand Down
37 changes: 35 additions & 2 deletions crates/rspack_loader_lightningcss/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ pub struct PseudoClasses {
pub focus_within: Option<String>,
}

#[derive(Debug, Deserialize, Default)]
#[serde(rename_all = "camelCase", default)]
#[derive(Debug, Default)]
pub struct Config {
pub error_recovery: Option<bool>,
pub targets: Option<Browsers>,
Expand All @@ -35,3 +34,37 @@ pub struct Config {
pub pseudo_classes: Option<PseudoClasses>,
pub unused_symbols: Option<Vec<String>>,
}

#[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct RawConfig {
pub error_recovery: Option<bool>,
pub targets: Option<Vec<String>>,
pub include: Option<u32>,
pub exclude: Option<u32>,
pub draft: Option<Draft>,
pub non_standard: Option<NonStandard>,
pub pseudo_classes: Option<PseudoClasses>,
pub unused_symbols: Option<Vec<String>>,
}

impl TryFrom<RawConfig> for Config {
type Error = rspack_error::Error;
fn try_from(value: RawConfig) -> Result<Self, Self::Error> {
Ok(Self {
error_recovery: value.error_recovery,
targets: value
.targets
.map(lightningcss::targets::Browsers::from_browserslist)
.transpose()
.map_err(|err| rspack_error::error!("Failed to parse browserslist: {}", err))?
.flatten(),
include: value.include,
exclude: value.exclude,
draft: value.draft,
non_standard: value.non_standard,
pseudo_classes: value.pseudo_classes,
unused_symbols: value.unused_symbols,
})
}
}
3 changes: 2 additions & 1 deletion crates/rspack_loader_lightningcss/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::borrow::Cow;

use config::Config;
use derivative::Derivative;
pub use lightningcss;
use lightningcss::{
printer::{PrinterOptions, PseudoClasses},
stylesheet::{MinifyOptions, ParserFlags, ParserOptions, StyleSheet},
Expand All @@ -13,7 +14,7 @@ use rspack_error::Result;
use rspack_loader_runner::{Identifiable, Identifier};
use tokio::sync::Mutex;

mod config;
pub mod config;

pub const LIGHTNINGCSS_LOADER_IDENTIFIER: &str = "builtin:lightningcss-loader";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Object {
"main.js",
],
"filteredModules": undefined,
"hash": "6264df4ebe23175182cf",
"hash": "333e59d94047c9b4ec6c",
"id": "909",
"idHints": Array [],
"initial": true,
Expand Down Expand Up @@ -176,7 +176,7 @@ Object {
"errorsCount": 0,
"filteredAssets": undefined,
"filteredModules": undefined,
"hash": "614628b5932899e281aa",
"hash": "a156b269cd7b4340da9d",
"modules": Array [
Object {
"assets": Array [],
Expand Down Expand Up @@ -324,7 +324,7 @@ Object {
"main.js",
],
"filteredModules": undefined,
"hash": "74703a42d091bf923302",
"hash": "a2024ddd80c1dac51782",
"id": "909",
"idHints": Array [],
"initial": true,
Expand Down Expand Up @@ -691,7 +691,7 @@ Object {
"errorsCount": 0,
"filteredAssets": undefined,
"filteredModules": undefined,
"hash": "500785fc8e6b099fa5e6",
"hash": "959ba20161293349edf3",
"modules": Array [
Object {
"assets": Array [],
Expand Down Expand Up @@ -1458,7 +1458,7 @@ Object {
"files": Array [
"main.js",
],
"hash": "6264df4ebe23175182cf",
"hash": "333e59d94047c9b4ec6c",
"id": "909",
"idHints": Array [],
"initial": true,
Expand Down Expand Up @@ -1714,7 +1714,7 @@ Object {
"main.js",
],
"filteredModules": undefined,
"hash": "507b35a9bc223de6c9b0",
"hash": "add6ca394a084131cdb7",
"id": "909",
"idHints": Array [],
"initial": true,
Expand Down Expand Up @@ -2063,7 +2063,7 @@ exports.c = require(\\"./c?c=3\\");
"errorsCount": 0,
"filteredAssets": undefined,
"filteredModules": undefined,
"hash": "f155d1e27c19baefa4cc",
"hash": "0e205cc26142ad8eade1",
"modules": Array [
Object {
"assets": Array [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
const rspack = require('@rspack/core')
const browserslist = require('browserslist')

/** @type {import("@rspack/core").Configuration} */
module.exports = {
module: {
Expand All @@ -18,7 +15,7 @@ module.exports = {
/** @type {import("@rspack/core").LightningcssLoaderOptions} */
options: {
unusedSymbols: ['unused'],
targets: browserslist('> 0.2%')
targets: '> 0.2%'
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion packages/rspack-test-tools/tests/statsAPICases/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module.exports = {
entry ./fixtures/a
cjs self exports reference self [585] ./fixtures/a.js
Rspack compiled successfully (614628b5932899e281aa)"
Rspack compiled successfully (a156b269cd7b4340da9d)"
`);
}
};
4 changes: 2 additions & 2 deletions packages/rspack-test-tools/tests/statsAPICases/chunks.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module.exports = {
"chunkB.js",
],
"filteredModules": undefined,
"hash": "3cd21283efb6761456db",
"hash": "9aa837bfaefd1fd4ec18",
"id": "250",
"idHints": Array [],
"initial": false,
Expand Down Expand Up @@ -144,7 +144,7 @@ module.exports = {
"main.js",
],
"filteredModules": undefined,
"hash": "a18b3c5199301c15e563",
"hash": "0e471e878e0dbdf0ba5a",
"id": "909",
"idHints": Array [],
"initial": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/rspack/etc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5706,7 +5706,7 @@ export type LightningCssMinimizerRspackPluginOptions = {
removeUnusedLocalIdents?: boolean;
minimizerOptions?: {
errorRecovery?: boolean;
targets?: Targets | string[] | string;
targets?: string[] | string;
include?: LightningcssFeatureOptions;
exclude?: LightningcssFeatureOptions;
draft?: Drafts;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import {
BuiltinPluginName,
type RawLightningCssBrowsers,
type RawLightningCssMinimizerRspackPluginOptions
} from "@rspack/binding";

import browserslist from "browserslist";
import {
type Drafts,
type FeatureOptions,
type NonStandard,
type PseudoClasses,
type Targets,
browserslistToTargets,
toFeatures
} from "../builtin-loader/lightningcss";
import type { AssetConditions } from "../util/assetCondition";
Expand All @@ -24,7 +20,7 @@ export type LightningCssMinimizerRspackPluginOptions = {
removeUnusedLocalIdents?: boolean;
minimizerOptions?: {
errorRecovery?: boolean;
targets?: Targets | string[] | string;
targets?: string[] | string;
include?: FeatureOptions;
exclude?: FeatureOptions;
draft?: Drafts;
Expand Down Expand Up @@ -56,12 +52,7 @@ export const LightningCssMinimizerRspackPlugin = create(
: // exclude all features, avoid downgrade css syntax when minimize
// 1048575 = Features.Empty | Features.Nesting | ... | Features.LogicalProperties
1048575,
targets:
typeof targets === "string" || Array.isArray(targets)
? (browserslistToTargets(
browserslist(targets)
) as RawLightningCssBrowsers)
: targets,
targets: typeof targets === "string" ? [targets] : targets,
draft: draft ? { customMedia: draft.customMedia ?? false } : undefined,
nonStandard: nonStandard
? {
Expand Down
10 changes: 2 additions & 8 deletions packages/rspack/src/config/adapterRuleUse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import type { Module } from "../Module";
import { resolvePluginImport } from "../builtin-loader";
import {
type FeatureOptions,
browserslistToTargets,
toFeatures
} from "../builtin-loader/lightningcss";
import { type LoaderObject, parsePathQueryFragment } from "../loader-runner";
Expand All @@ -26,7 +25,6 @@ import type {
RuleSetUseItem,
Target
} from "./zod";
import browserslist = require("browserslist");

export const BUILTIN_LOADER_PREFIX = "builtin:";

Expand Down Expand Up @@ -213,12 +211,8 @@ const getSwcLoaderOptions: GetLoaderOptions = (o, _) => {

const getLightningcssLoaderOptions: GetLoaderOptions = (o, _) => {
if (o && typeof o === "object") {
if (o.targets && typeof o.targets === "string") {
o.targets = browserslistToTargets(browserslist(o.targets));
}

if (o.targets && Array.isArray(o.targets)) {
o.targets = browserslistToTargets(browserslist(o.targets));
if (typeof o.targets === "string") {
o.targets = [o.targets];
}

if (o.include && typeof o.include === "object") {
Expand Down
33 changes: 2 additions & 31 deletions website/docs/en/guide/features/builtin-lightningcss-loader.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ type LightningcssFeatureOptions = {

type LightningcssLoaderOptions = {
errorRecovery?: boolean;
targets?: Targets | string[] | string;
targets?: string[] | string;
include?: LightningcssFeatureOptions;
exclude?: LightningcssFeatureOptions;
draft?: Drafts;
Expand All @@ -106,7 +106,7 @@ type LightningcssLoaderOptions = {

### targets

The `targets` option supports multiple formats, it can be set as a browserslist query string, a browserslist query result, or the native `targets` of lightningcss.
browserslist query string.

Here are some examples of setting targets.

Expand All @@ -133,32 +133,3 @@ const loader = {
},
};
```

- Setting the browserslist query result:

```js
const browserslist = require('browserslist');

const loader = {
loader: 'builtin:lightningcss-loader',
/** @type {import('@rspack/core').LightningcssLoaderOptions} */
options: {
targets: browserslist('> 0.2%'),
},
};
```

- Setting as lightningcss's native `targets`, which relies on lightningcss's internal `browserslistToTargets` method to convert a `browserslist` query result to lightningcss's `targets` format:

```js
const browserslist = require('browserslist');
const lightningcss = require('lightningcss');

const loader = {
loader: 'builtin:lightningcss-loader',
/** @type {import('@rspack/core').LightningcssLoaderOptions} */
options: {
targets: lightningcss.browserslistToTargets(browserslist('> 0.2%')),
},
};
```
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ At this point, the information that class name b is unused will be obtained via

Configuration passed to Lightning CSS for minification.

Below are the configurations supported. For detailed usage, please refer to [Lightning CSS documentation](https://lightningcss.dev/transpilation.html)
Below are the configurations supported, `targets` configuration is plain browserslist query, for other detailed usage, please refer to [Lightning CSS documentation](https://lightningcss.dev/transpilation.html)

:::info

Expand All @@ -86,7 +86,7 @@ We recommend and encourage users to configure their own `targets` to achieve the
```ts
type LightningCssMinimizerOptions = {
errorRecovery?: boolean;
targets?: Targets | string[] | string;
targets?: string[] | string;
include?: LightningcssFeatureOptions;
exclude?: LightningcssFeatureOptions;
draft?: Drafts;
Expand Down
Loading

2 comments on commit ce9b3fa

@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 ❌ failure
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-08-13 bea8415) Current Change
10000_development-mode + exec 2.3 s ± 17 ms 2.33 s ± 27 ms +1.09 %
10000_development-mode_hmr + exec 701 ms ± 11 ms 700 ms ± 7.1 ms -0.08 %
10000_production-mode + exec 2.85 s ± 35 ms 2.89 s ± 44 ms +1.49 %
arco-pro_development-mode + exec 1.91 s ± 85 ms 1.87 s ± 61 ms -1.76 %
arco-pro_development-mode_hmr + exec 433 ms ± 2.2 ms 434 ms ± 2.3 ms +0.15 %
arco-pro_production-mode + exec 3.46 s ± 88 ms 3.39 s ± 83 ms -2.25 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.56 s ± 104 ms 3.48 s ± 67 ms -2.24 %
threejs_development-mode_10x + exec 1.7 s ± 20 ms 1.69 s ± 16 ms -0.72 %
threejs_development-mode_10x_hmr + exec 820 ms ± 13 ms 798 ms ± 8.1 ms -2.69 %
threejs_production-mode_10x + exec 5.49 s ± 19 ms 5.48 s ± 46 ms -0.29 %

Please sign in to comment.