From d12115780133577d53e7e716bd196f7e754f3433 Mon Sep 17 00:00:00 2001 From: sebastien Date: Wed, 19 Mar 2025 11:07:00 +0100 Subject: [PATCH 1/3] Add rspack tracing/profiling --- .gitignore | 3 ++ package.json | 2 ++ packages/docusaurus-faster/src/index.ts | 10 +++++++ packages/docusaurus/src/webpack/base.ts | 40 +++++++++++++++++++++++-- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 51636c8c18d4..3dfa56974b28 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ website/i18n/**/* #!website/i18n/fr/**/* .netlify + +website/rspack-tracing.json +website/rspack-cpu-profile.json diff --git a/package.json b/package.json index ceb6c4a1893e..e46df09f3ead 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "scripts": { "start": "yarn build:packages && yarn start:website", "start:website": "yarn workspace website start", + "start:website:profile": "DOCUSAURUS_RSPACK_JS_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_RSPACK_JS_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", diff --git a/packages/docusaurus-faster/src/index.ts b/packages/docusaurus-faster/src/index.ts index cba2c68730f2..ba0b2ae8c900 100644 --- a/packages/docusaurus-faster/src/index.ts +++ b/packages/docusaurus-faster/src/index.ts @@ -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 = ({ diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index 3ab34f87a97e..0af06a020983 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -7,6 +7,7 @@ import fs from 'fs-extra'; import path from 'path'; +import inspector from 'node:inspector'; import {getCustomBabelConfigFilePath} from '@docusaurus/babel'; import { getCSSExtractPlugin, @@ -16,7 +17,7 @@ import { import {md5Hash, getFileLoaderUtils} from '@docusaurus/utils'; import {loadThemeAliases, loadDocusaurusAliases} from './aliases'; -import type {Configuration} from 'webpack'; +import type {Configuration, Compiler} from 'webpack'; import type { ConfigureWebpackUtils, FasterConfig, @@ -339,6 +340,41 @@ export async function createBaseConfig({ // for more reasoning ignoreOrder: true, }), - ], + process.env.DOCUSAURUS_RSPACK_JS_PROFILE && + new RspackProfileJSCPUProfilePlugin(), + ].filter(Boolean), }; } + +// 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 +class RspackProfileJSCPUProfilePlugin { + output: string; + constructor(output?: string) { + this.output = output ?? './rspack-cpu-profile.json'; + } + + apply(compiler: Compiler) { + const session = new inspector.Session(); + session.connect(); + session.post('Profiler.enable'); + session.post('Profiler.start'); + compiler.hooks.done.tapAsync( + RspackProfileJSCPUProfilePlugin.name, + (_stats, callback) => { + 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, + ); + }); + return callback(); + }, + ); + } +} From e0e21fcbd0a42cae5fc073aa6d68f47b2c9e7c64 Mon Sep 17 00:00:00 2001 From: sebastien Date: Wed, 19 Mar 2025 11:07:40 +0100 Subject: [PATCH 2/3] Add CLI start PerfLogger --- packages/docusaurus/src/commands/start/start.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus/src/commands/start/start.ts b/packages/docusaurus/src/commands/start/start.ts index 3b4c8d3fde8c..6cf7824b2ab6 100644 --- a/packages/docusaurus/src/commands/start/start.ts +++ b/packages/docusaurus/src/commands/start/start.ts @@ -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 = {}, ): Promise { @@ -62,3 +62,10 @@ export async function start( await openBrowser(reloadableSite.getOpenUrl()); } } + +export async function start( + siteDirParam: string = '.', + cliOptions: Partial = {}, +): Promise { + return PerfLogger.async('CLI start', () => doStart(siteDirParam, cliOptions)); +} From bf28379428b623d73ec9359fbe00da20c1174d53 Mon Sep 17 00:00:00 2001 From: sebastien Date: Wed, 19 Mar 2025 11:59:30 +0100 Subject: [PATCH 3/3] cleanup BundlerCPUProfilerPlugin --- .gitignore | 2 +- package.json | 4 +- packages/docusaurus/src/webpack/base.ts | 47 +++--------------- .../plugins/BundlerCPUProfilerPlugin.ts | 49 +++++++++++++++++++ 4 files changed, 59 insertions(+), 43 deletions(-) create mode 100644 packages/docusaurus/src/webpack/plugins/BundlerCPUProfilerPlugin.ts diff --git a/.gitignore b/.gitignore index 3dfa56974b28..d44178396ae3 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,4 @@ website/i18n/**/* .netlify website/rspack-tracing.json -website/rspack-cpu-profile.json +website/bundler-cpu-profile.json diff --git a/package.json b/package.json index e46df09f3ead..57a627693512 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "scripts": { "start": "yarn build:packages && yarn start:website", "start:website": "yarn workspace website start", - "start:website:profile": "DOCUSAURUS_RSPACK_JS_PROFILE=true DOCUSAURUS_RSPACK_TRACE=true 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", @@ -23,7 +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_RSPACK_JS_PROFILE=true DOCUSAURUS_RSPACK_TRACE=true 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", diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index 0af06a020983..ecd02d0e0e32 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -7,17 +7,17 @@ import fs from 'fs-extra'; import path from 'path'; -import inspector from 'node:inspector'; 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 type {Configuration, Compiler} from 'webpack'; +import {getFileLoaderUtils, md5Hash} from '@docusaurus/utils'; +import {loadDocusaurusAliases, loadThemeAliases} from './aliases'; +import {BundlerCPUProfilerPlugin} from './plugins/BundlerCPUProfilerPlugin'; +import type {Configuration} from 'webpack'; import type { ConfigureWebpackUtils, FasterConfig, @@ -340,41 +340,8 @@ export async function createBaseConfig({ // for more reasoning ignoreOrder: true, }), - process.env.DOCUSAURUS_RSPACK_JS_PROFILE && - new RspackProfileJSCPUProfilePlugin(), + process.env.DOCUSAURUS_BUNDLER_CPU_PROFILE && + new BundlerCPUProfilerPlugin(), ].filter(Boolean), }; } - -// 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 -class RspackProfileJSCPUProfilePlugin { - output: string; - constructor(output?: string) { - this.output = output ?? './rspack-cpu-profile.json'; - } - - apply(compiler: Compiler) { - const session = new inspector.Session(); - session.connect(); - session.post('Profiler.enable'); - session.post('Profiler.start'); - compiler.hooks.done.tapAsync( - RspackProfileJSCPUProfilePlugin.name, - (_stats, callback) => { - 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, - ); - }); - return callback(); - }, - ); - } -} diff --git a/packages/docusaurus/src/webpack/plugins/BundlerCPUProfilerPlugin.ts b/packages/docusaurus/src/webpack/plugins/BundlerCPUProfilerPlugin.ts new file mode 100644 index 000000000000..f16fdbd3c9e1 --- /dev/null +++ b/packages/docusaurus/src/webpack/plugins/BundlerCPUProfilerPlugin.ts @@ -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, + ); + }); + }); + } +}