Skip to content

Commit cba1e02

Browse files
authored
feat(core): faster CSS minimizer - siteConfig.future.experimental_faster.lightningCssMinimizer (#10522)
1 parent 3b7c828 commit cba1e02

File tree

12 files changed

+247
-38
lines changed

12 files changed

+247
-38
lines changed

packages/docusaurus-bundler/src/importFaster.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
*/
77

88
import type {ConfigureWebpackUtils} from '@docusaurus/types';
9-
import type {MinimizerOptions, CustomOptions} from 'terser-webpack-plugin';
9+
import type {
10+
MinimizerOptions as JsMinimizerOptions,
11+
CustomOptions,
12+
} from 'terser-webpack-plugin';
13+
import type {MinimizerOptions as CssMinimizerOptions} from 'css-minimizer-webpack-plugin';
1014

1115
async function importFaster() {
1216
return import('@docusaurus/faster');
@@ -30,9 +34,16 @@ export async function importSwcJsLoaderFactory(): Promise<
3034
return faster.getSwcJsLoaderFactory;
3135
}
3236

33-
export async function importSwcJsMinifierOptions(): Promise<
34-
MinimizerOptions<CustomOptions>
37+
export async function importSwcJsMinimizerOptions(): Promise<
38+
JsMinimizerOptions<CustomOptions>
3539
> {
3640
const faster = await ensureFaster();
37-
return faster.getSwcJsMinifierOptions() as MinimizerOptions<CustomOptions>;
41+
return faster.getSwcJsMinimizerOptions() as JsMinimizerOptions<CustomOptions>;
42+
}
43+
44+
export async function importLightningCssMinimizerOptions(): Promise<
45+
CssMinimizerOptions<CustomOptions>
46+
> {
47+
const faster = await ensureFaster();
48+
return faster.getLightningCssMinimizerOptions() as CssMinimizerOptions<CustomOptions>;
3849
}

packages/docusaurus-bundler/src/minification.ts

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77

88
import TerserPlugin from 'terser-webpack-plugin';
99
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
10-
import {importSwcJsMinifierOptions} from './importFaster';
10+
import {
11+
importSwcJsMinimizerOptions,
12+
importLightningCssMinimizerOptions,
13+
} from './importFaster';
1114
import type {CustomOptions, CssNanoOptions} from 'css-minimizer-webpack-plugin';
1215
import type {WebpackPluginInstance} from 'webpack';
1316
import type {CurrentBundler, FasterConfig} from '@docusaurus/types';
1417

1518
export type MinimizersConfig = {
16-
faster: Pick<FasterConfig, 'swcJsMinimizer'>;
19+
faster: Pick<FasterConfig, 'swcJsMinimizer' | 'lightningCssMinimizer'>;
1720
currentBundler: CurrentBundler;
1821
};
1922

@@ -31,9 +34,11 @@ function getTerserParallel() {
3134
return terserParallel;
3235
}
3336

34-
async function getJsMinimizer({faster}: MinimizersConfig) {
37+
async function getJsMinimizer({
38+
faster,
39+
}: MinimizersConfig): Promise<WebpackPluginInstance> {
3540
if (faster.swcJsMinimizer) {
36-
const terserOptions = await importSwcJsMinifierOptions();
41+
const terserOptions = await importSwcJsMinimizerOptions();
3742
return new TerserPlugin({
3843
parallel: getTerserParallel(),
3944
minify: TerserPlugin.swcMinify,
@@ -69,7 +74,21 @@ async function getJsMinimizer({faster}: MinimizersConfig) {
6974
});
7075
}
7176

72-
function getAdvancedCssMinifier() {
77+
async function getLightningCssMinimizer(): Promise<WebpackPluginInstance> {
78+
return new CssMinimizerPlugin({
79+
minify: CssMinimizerPlugin.lightningCssMinify,
80+
minimizerOptions: await importLightningCssMinimizerOptions(),
81+
});
82+
}
83+
84+
async function getCssNanoMinimizer(): Promise<WebpackPluginInstance> {
85+
// This is an historical env variable to opt-out of the advanced minimizer
86+
// Sometimes there's a bug in it and people are happy to disable it
87+
const useSimpleCssMinifier = process.env.USE_SIMPLE_CSS_MINIFIER === 'true';
88+
if (useSimpleCssMinifier) {
89+
return new CssMinimizerPlugin();
90+
}
91+
7392
// Using the array syntax to add 2 minimizers
7493
// see https://github.com/webpack-contrib/css-minimizer-webpack-plugin#array
7594
return new CssMinimizerPlugin<[CssNanoOptions, CustomOptions]>({
@@ -101,21 +120,18 @@ function getAdvancedCssMinifier() {
101120
});
102121
}
103122

104-
function getCssMinimizer(): WebpackPluginInstance {
105-
// This is an historical env variable to opt-out of the advanced minifier
106-
// Sometimes there's a bug in it and people are happy to disable it
107-
const useSimpleCssMinifier = process.env.USE_SIMPLE_CSS_MINIFIER === 'true';
108-
if (useSimpleCssMinifier) {
109-
return new CssMinimizerPlugin();
110-
} else {
111-
return getAdvancedCssMinifier();
112-
}
123+
async function getCssMinimizer(
124+
params: MinimizersConfig,
125+
): Promise<WebpackPluginInstance> {
126+
return params.faster.lightningCssMinimizer
127+
? getLightningCssMinimizer()
128+
: getCssNanoMinimizer();
113129
}
114130

115131
async function getWebpackMinimizers(
116132
params: MinimizersConfig,
117133
): Promise<WebpackPluginInstance[]> {
118-
return Promise.all([getJsMinimizer(params), getCssMinimizer()]);
134+
return Promise.all([getJsMinimizer(params), getCssMinimizer(params)]);
119135
}
120136

121137
async function getRspackMinimizers({

packages/docusaurus-faster/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
},
1919
"license": "MIT",
2020
"dependencies": {
21-
"webpack": "^5.88.1",
2221
"@swc/core": "^1.7.14",
23-
"swc-loader": "^0.2.6"
22+
"browserslist": "^4.24.0",
23+
"lightningcss": "^1.27.0",
24+
"swc-loader": "^0.2.6",
25+
"webpack": "^5.88.1"
2426
},
2527
"engines": {
2628
"node": ">=18.0"

packages/docusaurus-faster/src/index.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8+
import * as lightningcss from 'lightningcss';
9+
import browserslist from 'browserslist';
810
import type {RuleSetRule} from 'webpack';
911
import type {JsMinifyOptions} from '@swc/core';
1012

@@ -39,7 +41,7 @@ export function getSwcJsLoaderFactory({
3941
// They should rather be kept in sync for now to avoid any unexpected behavior
4042
// The goal of faster minifier is not to fine-tune options but only to be faster
4143
// See core minification.ts
42-
export function getSwcJsMinifierOptions(): JsMinifyOptions {
44+
export function getSwcJsMinimizerOptions(): JsMinifyOptions {
4345
return {
4446
ecma: 2020,
4547
compress: {
@@ -55,3 +57,16 @@ export function getSwcJsMinifierOptions(): JsMinifyOptions {
5557
},
5658
};
5759
}
60+
61+
// LightningCSS doesn't expose any type for css-minimizer-webpack-plugin setup
62+
// So we derive it ourselves
63+
// see https://lightningcss.dev/docs.html#with-webpack
64+
type LightningCssMinimizerOptions = Omit<
65+
lightningcss.TransformOptions<never>,
66+
'filename' | 'code'
67+
>;
68+
69+
export function getLightningCssMinimizerOptions(): LightningCssMinimizerOptions {
70+
const queries = browserslist();
71+
return {targets: lightningcss.browserslistToTargets(queries)};
72+
}

packages/docusaurus-types/src/config.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export type StorageConfig = {
126126
export type FasterConfig = {
127127
swcJsLoader: boolean;
128128
swcJsMinimizer: boolean;
129+
lightningCssMinimizer: boolean;
129130
mdxCrossCompilerCache: boolean;
130131
rspackBundler: boolean;
131132
};

packages/docusaurus/src/server/__tests__/__snapshots__/config.test.ts.snap

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ exports[`loadSiteConfig website with .cjs siteConfig 1`] = `
99
"customFields": {},
1010
"future": {
1111
"experimental_faster": {
12+
"lightningCssMinimizer": false,
1213
"mdxCrossCompilerCache": false,
1314
"rspackBundler": false,
1415
"swcJsLoader": false,
@@ -76,6 +77,7 @@ exports[`loadSiteConfig website with ts + js config 1`] = `
7677
"customFields": {},
7778
"future": {
7879
"experimental_faster": {
80+
"lightningCssMinimizer": false,
7981
"mdxCrossCompilerCache": false,
8082
"rspackBundler": false,
8183
"swcJsLoader": false,
@@ -143,6 +145,7 @@ exports[`loadSiteConfig website with valid JS CJS config 1`] = `
143145
"customFields": {},
144146
"future": {
145147
"experimental_faster": {
148+
"lightningCssMinimizer": false,
146149
"mdxCrossCompilerCache": false,
147150
"rspackBundler": false,
148151
"swcJsLoader": false,
@@ -210,6 +213,7 @@ exports[`loadSiteConfig website with valid JS ESM config 1`] = `
210213
"customFields": {},
211214
"future": {
212215
"experimental_faster": {
216+
"lightningCssMinimizer": false,
213217
"mdxCrossCompilerCache": false,
214218
"rspackBundler": false,
215219
"swcJsLoader": false,
@@ -277,6 +281,7 @@ exports[`loadSiteConfig website with valid TypeScript CJS config 1`] = `
277281
"customFields": {},
278282
"future": {
279283
"experimental_faster": {
284+
"lightningCssMinimizer": false,
280285
"mdxCrossCompilerCache": false,
281286
"rspackBundler": false,
282287
"swcJsLoader": false,
@@ -344,6 +349,7 @@ exports[`loadSiteConfig website with valid TypeScript ESM config 1`] = `
344349
"customFields": {},
345350
"future": {
346351
"experimental_faster": {
352+
"lightningCssMinimizer": false,
347353
"mdxCrossCompilerCache": false,
348354
"rspackBundler": false,
349355
"swcJsLoader": false,
@@ -411,6 +417,7 @@ exports[`loadSiteConfig website with valid async config 1`] = `
411417
"customFields": {},
412418
"future": {
413419
"experimental_faster": {
420+
"lightningCssMinimizer": false,
414421
"mdxCrossCompilerCache": false,
415422
"rspackBundler": false,
416423
"swcJsLoader": false,
@@ -480,6 +487,7 @@ exports[`loadSiteConfig website with valid async config creator function 1`] = `
480487
"customFields": {},
481488
"future": {
482489
"experimental_faster": {
490+
"lightningCssMinimizer": false,
483491
"mdxCrossCompilerCache": false,
484492
"rspackBundler": false,
485493
"swcJsLoader": false,
@@ -549,6 +557,7 @@ exports[`loadSiteConfig website with valid config creator function 1`] = `
549557
"customFields": {},
550558
"future": {
551559
"experimental_faster": {
560+
"lightningCssMinimizer": false,
552561
"mdxCrossCompilerCache": false,
553562
"rspackBundler": false,
554563
"swcJsLoader": false,
@@ -621,6 +630,7 @@ exports[`loadSiteConfig website with valid siteConfig 1`] = `
621630
"favicon": "img/docusaurus.ico",
622631
"future": {
623632
"experimental_faster": {
633+
"lightningCssMinimizer": false,
624634
"mdxCrossCompilerCache": false,
625635
"rspackBundler": false,
626636
"swcJsLoader": false,

packages/docusaurus/src/server/__tests__/__snapshots__/site.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ exports[`load loads props for site with custom i18n path 1`] = `
8383
"customFields": {},
8484
"future": {
8585
"experimental_faster": {
86+
"lightningCssMinimizer": false,
8687
"mdxCrossCompilerCache": false,
8788
"rspackBundler": false,
8889
"swcJsLoader": false,

packages/docusaurus/src/server/__tests__/configValidation.test.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ describe('normalizeConfig', () => {
4848
experimental_faster: {
4949
swcJsLoader: true,
5050
swcJsMinimizer: true,
51+
lightningCssMinimizer: true,
5152
mdxCrossCompilerCache: true,
5253
rspackBundler: true,
5354
},
@@ -745,6 +746,7 @@ describe('future', () => {
745746
experimental_faster: {
746747
swcJsLoader: true,
747748
swcJsMinimizer: true,
749+
lightningCssMinimizer: true,
748750
mdxCrossCompilerCache: true,
749751
rspackBundler: true,
750752
},
@@ -1096,6 +1098,7 @@ describe('future', () => {
10961098
const faster: FasterConfig = {
10971099
swcJsLoader: true,
10981100
swcJsMinimizer: true,
1101+
lightningCssMinimizer: true,
10991102
mdxCrossCompilerCache: true,
11001103
rspackBundler: true,
11011104
};
@@ -1281,6 +1284,77 @@ describe('future', () => {
12811284
});
12821285
});
12831286

1287+
describe('lightningCssMinimizer', () => {
1288+
it('accepts - undefined', () => {
1289+
const faster: Partial<FasterConfig> = {
1290+
lightningCssMinimizer: undefined,
1291+
};
1292+
expect(
1293+
normalizeConfig({
1294+
future: {
1295+
experimental_faster: faster,
1296+
},
1297+
}),
1298+
).toEqual(fasterContaining({lightningCssMinimizer: false}));
1299+
});
1300+
1301+
it('accepts - true', () => {
1302+
const faster: Partial<FasterConfig> = {
1303+
lightningCssMinimizer: true,
1304+
};
1305+
expect(
1306+
normalizeConfig({
1307+
future: {
1308+
experimental_faster: faster,
1309+
},
1310+
}),
1311+
).toEqual(fasterContaining({lightningCssMinimizer: true}));
1312+
});
1313+
1314+
it('accepts - false', () => {
1315+
const faster: Partial<FasterConfig> = {
1316+
lightningCssMinimizer: false,
1317+
};
1318+
expect(
1319+
normalizeConfig({
1320+
future: {
1321+
experimental_faster: faster,
1322+
},
1323+
}),
1324+
).toEqual(fasterContaining({lightningCssMinimizer: false}));
1325+
});
1326+
1327+
it('rejects - null', () => {
1328+
// @ts-expect-error: invalid
1329+
const faster: Partial<FasterConfig> = {lightningCssMinimizer: 42};
1330+
expect(() =>
1331+
normalizeConfig({
1332+
future: {
1333+
experimental_faster: faster,
1334+
},
1335+
}),
1336+
).toThrowErrorMatchingInlineSnapshot(`
1337+
""future.experimental_faster.lightningCssMinimizer" must be a boolean
1338+
"
1339+
`);
1340+
});
1341+
1342+
it('rejects - number', () => {
1343+
// @ts-expect-error: invalid
1344+
const faster: Partial<FasterConfig> = {lightningCssMinimizer: 42};
1345+
expect(() =>
1346+
normalizeConfig({
1347+
future: {
1348+
experimental_faster: faster,
1349+
},
1350+
}),
1351+
).toThrowErrorMatchingInlineSnapshot(`
1352+
""future.experimental_faster.lightningCssMinimizer" must be a boolean
1353+
"
1354+
`);
1355+
});
1356+
});
1357+
12841358
describe('mdxCrossCompilerCache', () => {
12851359
it('accepts - undefined', () => {
12861360
const faster: Partial<FasterConfig> = {

packages/docusaurus/src/server/configValidation.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export const DEFAULT_STORAGE_CONFIG: StorageConfig = {
4444
export const DEFAULT_FASTER_CONFIG: FasterConfig = {
4545
swcJsLoader: false,
4646
swcJsMinimizer: false,
47+
lightningCssMinimizer: false,
4748
mdxCrossCompilerCache: false,
4849
rspackBundler: false,
4950
};
@@ -52,6 +53,7 @@ export const DEFAULT_FASTER_CONFIG: FasterConfig = {
5253
export const DEFAULT_FASTER_CONFIG_TRUE: FasterConfig = {
5354
swcJsLoader: true,
5455
swcJsMinimizer: true,
56+
lightningCssMinimizer: true,
5557
mdxCrossCompilerCache: true,
5658
rspackBundler: true,
5759
};
@@ -221,6 +223,9 @@ const FASTER_CONFIG_SCHEMA = Joi.alternatives()
221223
swcJsMinimizer: Joi.boolean().default(
222224
DEFAULT_FASTER_CONFIG.swcJsMinimizer,
223225
),
226+
lightningCssMinimizer: Joi.boolean().default(
227+
DEFAULT_FASTER_CONFIG.lightningCssMinimizer,
228+
),
224229
mdxCrossCompilerCache: Joi.boolean().default(
225230
DEFAULT_FASTER_CONFIG.mdxCrossCompilerCache,
226231
),

project-words.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ lastmod
164164
Lastmod
165165
lifecycles
166166
Lifecycles
167+
lightningcss
167168
linkify
168169
Linkify
169170
Localizable

0 commit comments

Comments
 (0)