feat(core): Add bundler tracing/profiling (#11006)

* Add rspack tracing/profiling

* Add CLI start PerfLogger

* cleanup BundlerCPUProfilerPlugin
This commit is contained in:
Sébastien Lorber 2025-03-19 12:14:06 +01:00 committed by GitHub
parent e88f1aaf96
commit 3782244ce7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 80 additions and 6 deletions

3
.gitignore vendored
View file

@ -45,3 +45,6 @@ website/i18n/**/*
#!website/i18n/fr/**/*
.netlify
website/rspack-tracing.json
website/bundler-cpu-profile.json

View file

@ -15,6 +15,7 @@
"scripts": {
"start": "yarn build:packages && yarn start:website",
"start:website": "yarn workspace website start",
"start:website:profile": "DOCUSAURUS_BUNDLER_CPU_PROFILE=true DOCUSAURUS_RSPACK_TRACE=true yarn workspace website start",
"start:website:baseUrl": "yarn workspace website start:baseUrl",
"start:website:blogOnly": "yarn workspace website start:blogOnly",
"start:website:deployPreview": "cross-env NETLIFY=true CONTEXT='deploy-preview' yarn workspace website start",
@ -22,6 +23,7 @@
"build": "yarn build:packages && yarn build:website",
"build:packages": "lerna run build --no-private",
"build:website": "yarn workspace website build",
"build:website:profile": "DOCUSAURUS_BUNDLER_CPU_PROFILE=true DOCUSAURUS_RSPACK_TRACE=true yarn workspace website build",
"build:website:baseUrl": "yarn workspace website build:baseUrl",
"build:website:blogOnly": "yarn workspace website build:blogOnly",
"build:website:deployPreview:testWrap": "yarn workspace website test:swizzle:wrap:ts",

View file

@ -11,6 +11,16 @@ import browserslist from 'browserslist';
import {minify as swcHtmlMinifier} from '@swc/html';
import type {JsMinifyOptions, Options as SwcOptions} from '@swc/core';
// See https://rspack.dev/contribute/development/profiling
// File can be opened with https://ui.perfetto.dev/
if (process.env.DOCUSAURUS_RSPACK_TRACE) {
Rspack.experiments.globalTrace.register(
'trace',
'chrome',
'./rspack-tracing.json',
);
}
export const swcLoader = require.resolve('swc-loader');
export const getSwcLoaderOptions = ({

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import logger from '@docusaurus/logger';
import logger, {PerfLogger} from '@docusaurus/logger';
import openBrowser from '../utils/openBrowser/openBrowser';
import {setupSiteFileWatchers} from './watcher';
import {createWebpackDevServer} from './webpack';
@ -21,7 +21,7 @@ export type StartCLIOptions = HostPortOptions &
minify?: boolean;
};
export async function start(
async function doStart(
siteDirParam: string = '.',
cliOptions: Partial<StartCLIOptions> = {},
): Promise<void> {
@ -62,3 +62,10 @@ export async function start(
await openBrowser(reloadableSite.getOpenUrl());
}
}
export async function start(
siteDirParam: string = '.',
cliOptions: Partial<StartCLIOptions> = {},
): Promise<void> {
return PerfLogger.async('CLI start', () => doStart(siteDirParam, cliOptions));
}

View file

@ -9,13 +9,14 @@ import fs from 'fs-extra';
import path from 'path';
import {getCustomBabelConfigFilePath} from '@docusaurus/babel';
import {
createJsLoaderFactory,
getCSSExtractPlugin,
getMinimizers,
createJsLoaderFactory,
} from '@docusaurus/bundler';
import {md5Hash, getFileLoaderUtils} from '@docusaurus/utils';
import {loadThemeAliases, loadDocusaurusAliases} from './aliases';
import {getFileLoaderUtils, md5Hash} from '@docusaurus/utils';
import {loadDocusaurusAliases, loadThemeAliases} from './aliases';
import {BundlerCPUProfilerPlugin} from './plugins/BundlerCPUProfilerPlugin';
import type {Configuration} from 'webpack';
import type {
ConfigureWebpackUtils,
@ -339,6 +340,8 @@ export async function createBaseConfig({
// for more reasoning
ignoreOrder: true,
}),
],
process.env.DOCUSAURUS_BUNDLER_CPU_PROFILE &&
new BundlerCPUProfilerPlugin(),
].filter(Boolean),
};
}

View file

@ -0,0 +1,49 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import inspector from 'node:inspector';
import fs from 'fs-extra';
import type {Compiler} from 'webpack';
// Bundle CPU profiling plugin, contributed by the Rspack team
// Can be opened in https://www.speedscope.app/
// See also https://github.com/jerrykingxyz/docusaurus/pull/1
// See also https://github.com/facebook/docusaurus/pull/10985
export class BundlerCPUProfilerPlugin {
output: string;
constructor(output?: string) {
this.output = output ?? './bundler-cpu-profile.json';
}
apply(compiler: Compiler): void {
const session = new inspector.Session();
session.connect();
session.post('Profiler.enable');
session.post('Profiler.start');
// In dev/watch mode, we restart the profiler before each compilation
compiler.hooks.watchRun.tapPromise(
BundlerCPUProfilerPlugin.name,
async () => {
session.post('Profiler.start');
},
);
compiler.hooks.done.tapPromise(BundlerCPUProfilerPlugin.name, async () => {
session.post('Profiler.stop', (error, param) => {
if (error) {
console.error('Failed to generate JS CPU profile:', error);
return;
}
fs.writeFile(this.output, JSON.stringify(param.profile)).catch(
console.error,
);
});
});
}
}