Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 3 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ website/i18n/**/*
#!website/i18n/fr/**/*

.netlify

website/rspack-tracing.json
website/bundler-cpu-profile.json
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
"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",
"examples:generate": "node admin/scripts/generateExamples.js",
"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",
Expand Down
10 changes: 10 additions & 0 deletions packages/docusaurus-faster/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ({
Expand Down
11 changes: 9 additions & 2 deletions packages/docusaurus/src/commands/start/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -21,7 +21,7 @@ export type StartCLIOptions = HostPortOptions &
minify?: boolean;
};

export async function start(
async function doStart(
siteDirParam: string = '.',
cliOptions: Partial<StartCLIOptions> = {},
): Promise<void> {
Expand Down Expand Up @@ -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));
}
11 changes: 7 additions & 4 deletions packages/docusaurus/src/webpack/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -339,6 +340,8 @@ export async function createBaseConfig({
// for more reasoning
ignoreOrder: true,
}),
],
process.env.DOCUSAURUS_BUNDLER_CPU_PROFILE &&
new BundlerCPUProfilerPlugin(),
].filter(Boolean),
};
}
Original file line number Diff line number Diff line change
@@ -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,
);
});
});
}
}
Loading