From 43783e975e44e4a339633045ef419e907246ad0e Mon Sep 17 00:00:00 2001 From: sebastien Date: Fri, 23 Oct 2026 19:32:36 +0200 Subject: [PATCH 1/2] refactor(bundler): add `getTargets()` for the client and server bundles, remove the SWC `clientBrowserslistQueries` param (AI-assisted) - getTargets({isServer, bundlerName}) returns getServerTargets() or getClientTargets() - getBrowserslistQueries() is renamed getClientTargets() - getServerBrowserslistQueries() is renamed getServerTargets() and moves next to it, to avoid a circular import with swc.ts - getSwcLoaderOptions() reads the targets itself: the clientBrowserslistQueries param was a leftover from when the SWC options lived in @docusaurus/faster (#12604) Co-Authored-By: Claude Opus 5.5 --- .../docusaurus-bundler/src/browserslist.ts | 57 ++++++++++++++++++- packages/docusaurus-bundler/src/index.ts | 2 +- .../src/loaders/jsLoader.ts | 8 +-- .../docusaurus-bundler/src/minification.ts | 4 +- packages/docusaurus-bundler/src/swc.ts | 46 +-------------- packages/docusaurus/src/webpack/base.ts | 4 +- 6 files changed, 63 insertions(+), 58 deletions(-) diff --git a/packages/docusaurus-bundler/src/browserslist.ts b/packages/docusaurus-bundler/src/browserslist.ts index ff705db55404..7d0d5dfa43c2 100644 --- a/packages/docusaurus-bundler/src/browserslist.ts +++ b/packages/docusaurus-bundler/src/browserslist.ts @@ -6,18 +6,71 @@ */ import browserslist from 'browserslist'; +import semver from 'semver'; import {browserslistToTargets, type TransformOptions} from 'lightningcss'; +import type {CurrentBundler} from '@docusaurus/types'; // Used when the site doesn't provide its own Browserslist config // See https://web.dev/baseline const DefaultBrowserslistQueries = ['baseline widely available']; -export function getBrowserslistQueries(): string[] { +/** + * The targets the client or server bundle is compiled for, like + * `['baseline widely available']` or `['node 24.11.1']` + */ +export function getTargets({ + isServer, + bundlerName, +}: { + isServer: boolean; + bundlerName: CurrentBundler['name']; +}): string[] { + return isServer ? getServerTargets({bundlerName}) : getClientTargets(); +} + +export function getClientTargets(): string[] { return ( browserslist.loadConfig({path: process.cwd()}) ?? DefaultBrowserslistQueries ); } +function getServerTargets({ + bundlerName, +}: { + bundlerName: CurrentBundler['name']; +}): string[] { + // Escape hatch env variable + if (process.env.DOCUSAURUS_SERVER_NODE_TARGET) { + return [`node ${process.env.DOCUSAURUS_SERVER_NODE_TARGET}`]; + } + // For server builds, we want to use the current Node version as target + // But we can't pass a target that Browserslist doesn't know about yet + const nodeTarget = getMinVersion( + process.versions.node, + getLastBrowserslistKnownNodeVersion(bundlerName), + ); + return [`node ${nodeTarget}`]; +} + +// TODO this is not accurate +// for Rspack we should read from the built-in browserslist data +// see https://github.com/facebook/docusaurus/pull/11496 +function getLastBrowserslistKnownNodeVersion( + bundlerName: CurrentBundler['name'], +): string { + if (bundlerName === 'rspack') { + // TODO hardcoded value until Rspack exposes its Browserslist data + // see https://github.com/facebook/docusaurus/pull/11496 + return '26.0.0'; + } + // browserslist('last 1 node versions')[0]!.replace('node ', '') + return browserslist.nodeVersions.at(-1)!; +} + +function getMinVersion(v1: string, v2: string): string { + return semver.lt(v1, v2) ? v1 : v2; +} + // LightningCSS doesn't expose any type for minimizer-webpack-plugin setup // So we derive it ourselves // see https://lightningcss.dev/docs.html#with-webpack @@ -27,6 +80,6 @@ type LightningCssMinimizerOptions = Omit< >; export function getLightningCssMinimizerOptions(): LightningCssMinimizerOptions { - const browsers = browserslist(getBrowserslistQueries()); + const browsers = browserslist(getClientTargets()); return {targets: browserslistToTargets(browsers)}; } diff --git a/packages/docusaurus-bundler/src/index.ts b/packages/docusaurus-bundler/src/index.ts index 9ecb97e0ac18..4eea4282afac 100644 --- a/packages/docusaurus-bundler/src/index.ts +++ b/packages/docusaurus-bundler/src/index.ts @@ -15,7 +15,7 @@ export { registerBundlerTracing, } from './currentBundler'; -export {getBrowserslistQueries} from './browserslist'; +export {getClientTargets} from './browserslist'; export {getMinimizers} from './minification'; export {getHtmlMinifier, type HtmlMinifier} from './minifyHtml'; export {createJsLoaderFactory} from './loaders/jsLoader'; diff --git a/packages/docusaurus-bundler/src/loaders/jsLoader.ts b/packages/docusaurus-bundler/src/loaders/jsLoader.ts index d73cbd4fe16c..e510c31cad4c 100644 --- a/packages/docusaurus-bundler/src/loaders/jsLoader.ts +++ b/packages/docusaurus-bundler/src/loaders/jsLoader.ts @@ -8,7 +8,6 @@ import {getBabelOptions, getCustomBabelConfigFilePath} from '@docusaurus/babel'; import {getSwcLoaderOptions} from '../swc'; import {getCurrentBundler} from '../currentBundler'; -import {getBrowserslistQueries} from '../browserslist'; import type {ConfigureWebpackUtils, DocusaurusConfig} from '@docusaurus/types'; async function createBabelJsLoaderFactory({ @@ -27,15 +26,10 @@ async function createBabelJsLoaderFactory({ function createRspackSwcJsLoaderFactory(): ConfigureWebpackUtils['getJSLoader'] { const loader = 'builtin:swc-loader'; - const clientBrowserslistQueries = getBrowserslistQueries(); return ({isServer}) => { return { loader, - options: getSwcLoaderOptions({ - isServer, - bundlerName: 'rspack', - clientBrowserslistQueries, - }), + options: getSwcLoaderOptions({isServer, bundlerName: 'rspack'}), }; }; } diff --git a/packages/docusaurus-bundler/src/minification.ts b/packages/docusaurus-bundler/src/minification.ts index ef0a52954cb3..630a37b542a8 100644 --- a/packages/docusaurus-bundler/src/minification.ts +++ b/packages/docusaurus-bundler/src/minification.ts @@ -10,7 +10,7 @@ import {createRequire} from 'node:module'; import logger from '@docusaurus/logger'; import {rspack} from './rspack'; import { - getBrowserslistQueries, + getClientTargets, getLightningCssMinimizerOptions, } from './browserslist'; import type * as MinifyFunctions from './minifyFunctions'; @@ -137,7 +137,7 @@ function getRspackMinimizers(): RspackPluginInstance[] { // While LightningCSS targets are normally not Browserslist queries // See https://rspack.dev/plugins/rspack/lightning-css-minimizer-rspack-plugin#minimizeroptions // See https://lightningcss.dev/transpilation.html - targets: getBrowserslistQueries(), + targets: getClientTargets(), }, }), ]; diff --git a/packages/docusaurus-bundler/src/swc.ts b/packages/docusaurus-bundler/src/swc.ts index f26a714f3b83..668930d92c6b 100644 --- a/packages/docusaurus-bundler/src/swc.ts +++ b/packages/docusaurus-bundler/src/swc.ts @@ -5,25 +5,20 @@ * LICENSE file in the root directory of this source tree. */ -import browserslist from 'browserslist'; -import semver from 'semver'; +import {getTargets} from './browserslist'; import type {SwcLoaderOptions} from '@rspack/core'; import type {CurrentBundler} from '@docusaurus/types'; export function getSwcLoaderOptions({ isServer, bundlerName, - clientBrowserslistQueries, }: { isServer: boolean; bundlerName: CurrentBundler['name']; - clientBrowserslistQueries: string[]; }): SwcLoaderOptions { return { env: { - targets: isServer - ? getServerBrowserslistQueries({bundlerName}) - : clientBrowserslistQueries, + targets: getTargets({isServer, bundlerName}), }, jsc: { parser: { @@ -43,40 +38,3 @@ export function getSwcLoaderOptions({ }, }; } - -// TODO this is not accurate -// for Rspack we should read from the built-in browserslist data -// see https://github.com/facebook/docusaurus/pull/11496 -function getLastBrowserslistKnownNodeVersion( - bundlerName: CurrentBundler['name'], -): string { - if (bundlerName === 'rspack') { - // TODO hardcoded value until Rspack exposes its Browserslist data - // see https://github.com/facebook/docusaurus/pull/11496 - return '26.0.0'; - } - // browserslist('last 1 node versions')[0]!.replace('node ', '') - return browserslist.nodeVersions.at(-1)!; -} - -function getMinVersion(v1: string, v2: string): string { - return semver.lt(v1, v2) ? v1 : v2; -} - -function getServerBrowserslistQueries({ - bundlerName, -}: { - bundlerName: CurrentBundler['name']; -}): string[] { - // Escape hatch env variable - if (process.env.DOCUSAURUS_SERVER_NODE_TARGET) { - return [`node ${process.env.DOCUSAURUS_SERVER_NODE_TARGET}`]; - } - // For server builds, we want to use the current Node version as target - // But we can't pass a target that Browserslist doesn't know about yet - const nodeTarget = getMinVersion( - process.versions.node, - getLastBrowserslistKnownNodeVersion(bundlerName), - ); - return [`node ${nodeTarget}`]; -} diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index d0305c029d3e..f8c03ce65bdc 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -8,7 +8,7 @@ import path from 'node:path'; import { createJsLoaderFactory, - getBrowserslistQueries, + getClientTargets, getCSSExtractPlugin, getMinimizers, } from '@docusaurus/bundler'; @@ -114,7 +114,7 @@ export async function createBaseConfig({ const themeAliasesHash = md5Hash(JSON.stringify(themeAliases)); // Loader and minimizer options are not part of the cache key // Changing the Browserslist config must evict the cache - const browserslistHash = md5Hash(JSON.stringify(getBrowserslistQueries())); + const browserslistHash = md5Hash(JSON.stringify(getClientTargets())); // Asset module parser options are not part of the cache key // Changing the asset inline max size must evict the cache return `${siteMetadata.docusaurusVersion}-${themeAliasesHash}-${browserslistHash}-${ASSET_INLINE_MAX_SIZE}`; From 7383bb06913ab803e3b03ba05b3930012b4e07fb Mon Sep 17 00:00:00 2001 From: sebastien Date: Fri, 23 Oct 2026 19:45:33 +0200 Subject: [PATCH 2/2] refactor(bundler): separate the client queries from the client targets (AI-assisted) - getClientQueries() returns the Browserslist queries - getClientTargets() returns the browsers they match - SWC keeps receiving the client queries: Rspack resolves them with its own Browserslist data - getTargets() moves to the cache eviction PR, its only user Co-Authored-By: Claude Opus 5.5 --- .../docusaurus-bundler/src/browserslist.ts | 29 +++++++------------ packages/docusaurus-bundler/src/index.ts | 2 +- .../docusaurus-bundler/src/minification.ts | 4 +-- packages/docusaurus-bundler/src/swc.ts | 5 ++-- packages/docusaurus/src/webpack/base.ts | 4 +-- 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/packages/docusaurus-bundler/src/browserslist.ts b/packages/docusaurus-bundler/src/browserslist.ts index 7d0d5dfa43c2..2acf4a8a14c8 100644 --- a/packages/docusaurus-bundler/src/browserslist.ts +++ b/packages/docusaurus-bundler/src/browserslist.ts @@ -14,27 +14,21 @@ import type {CurrentBundler} from '@docusaurus/types'; // See https://web.dev/baseline const DefaultBrowserslistQueries = ['baseline widely available']; -/** - * The targets the client or server bundle is compiled for, like - * `['baseline widely available']` or `['node 24.11.1']` - */ -export function getTargets({ - isServer, - bundlerName, -}: { - isServer: boolean; - bundlerName: CurrentBundler['name']; -}): string[] { - return isServer ? getServerTargets({bundlerName}) : getClientTargets(); -} - -export function getClientTargets(): string[] { +export function getClientQueries(): string[] { return ( browserslist.loadConfig({path: process.cwd()}) ?? DefaultBrowserslistQueries ); } -function getServerTargets({ +/** + * The browsers that the client queries match, like + * `['chrome 120', 'firefox 115']` + */ +function getClientTargets(): string[] { + return browserslist(getClientQueries()); +} + +export function getServerTargets({ bundlerName, }: { bundlerName: CurrentBundler['name']; @@ -80,6 +74,5 @@ type LightningCssMinimizerOptions = Omit< >; export function getLightningCssMinimizerOptions(): LightningCssMinimizerOptions { - const browsers = browserslist(getClientTargets()); - return {targets: browserslistToTargets(browsers)}; + return {targets: browserslistToTargets(getClientTargets())}; } diff --git a/packages/docusaurus-bundler/src/index.ts b/packages/docusaurus-bundler/src/index.ts index 4eea4282afac..4f34e0f646b7 100644 --- a/packages/docusaurus-bundler/src/index.ts +++ b/packages/docusaurus-bundler/src/index.ts @@ -15,7 +15,7 @@ export { registerBundlerTracing, } from './currentBundler'; -export {getClientTargets} from './browserslist'; +export {getClientQueries} from './browserslist'; export {getMinimizers} from './minification'; export {getHtmlMinifier, type HtmlMinifier} from './minifyHtml'; export {createJsLoaderFactory} from './loaders/jsLoader'; diff --git a/packages/docusaurus-bundler/src/minification.ts b/packages/docusaurus-bundler/src/minification.ts index 630a37b542a8..71f3cebb2441 100644 --- a/packages/docusaurus-bundler/src/minification.ts +++ b/packages/docusaurus-bundler/src/minification.ts @@ -10,7 +10,7 @@ import {createRequire} from 'node:module'; import logger from '@docusaurus/logger'; import {rspack} from './rspack'; import { - getClientTargets, + getClientQueries, getLightningCssMinimizerOptions, } from './browserslist'; import type * as MinifyFunctions from './minifyFunctions'; @@ -137,7 +137,7 @@ function getRspackMinimizers(): RspackPluginInstance[] { // While LightningCSS targets are normally not Browserslist queries // See https://rspack.dev/plugins/rspack/lightning-css-minimizer-rspack-plugin#minimizeroptions // See https://lightningcss.dev/transpilation.html - targets: getClientTargets(), + targets: getClientQueries(), }, }), ]; diff --git a/packages/docusaurus-bundler/src/swc.ts b/packages/docusaurus-bundler/src/swc.ts index 668930d92c6b..939bc33d35d9 100644 --- a/packages/docusaurus-bundler/src/swc.ts +++ b/packages/docusaurus-bundler/src/swc.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {getTargets} from './browserslist'; +import {getClientQueries, getServerTargets} from './browserslist'; import type {SwcLoaderOptions} from '@rspack/core'; import type {CurrentBundler} from '@docusaurus/types'; @@ -18,7 +18,8 @@ export function getSwcLoaderOptions({ }): SwcLoaderOptions { return { env: { - targets: getTargets({isServer, bundlerName}), + // Rspack resolves the client queries with its own Browserslist data + targets: isServer ? getServerTargets({bundlerName}) : getClientQueries(), }, jsc: { parser: { diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index f8c03ce65bdc..4f31f6801af7 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -8,7 +8,7 @@ import path from 'node:path'; import { createJsLoaderFactory, - getClientTargets, + getClientQueries, getCSSExtractPlugin, getMinimizers, } from '@docusaurus/bundler'; @@ -114,7 +114,7 @@ export async function createBaseConfig({ const themeAliasesHash = md5Hash(JSON.stringify(themeAliases)); // Loader and minimizer options are not part of the cache key // Changing the Browserslist config must evict the cache - const browserslistHash = md5Hash(JSON.stringify(getClientTargets())); + const browserslistHash = md5Hash(JSON.stringify(getClientQueries())); // Asset module parser options are not part of the cache key // Changing the asset inline max size must evict the cache return `${siteMetadata.docusaurusVersion}-${themeAliasesHash}-${browserslistHash}-${ASSET_INLINE_MAX_SIZE}`;