Skip to content

Commit 350bb44

Browse files
authored
feat: add support for tracing rspack (#1150)
* feat: add support for profiling rspack * fix: shutdown gracefully * chore: changeset * fix: tests
1 parent 3748b41 commit 350bb44

File tree

7 files changed

+110
-1
lines changed

7 files changed

+110
-1
lines changed

.changeset/shy-worlds-type.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@callstack/repack": minor
3+
---
4+
5+
Support `RSPACK_PROFILE` env var for obtaining traces from Rspack

packages/repack/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"estree-util-is-identifier-name": "^1.1.0",
8585
"events": "^3.3.0",
8686
"execa": "^5.0.0",
87+
"exit-hook": "^4.0.0",
8788
"flow-remove-types": "^2.268.0",
8889
"gradient-string": "^2.0.2",
8990
"image-size": "^1.1.1",

packages/repack/src/commands/common/__tests__/setupInteractions.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ describe('setupInteractions', () => {
2323
} as unknown as Logger;
2424

2525
mockProcess = {
26+
on: (event: string) => {
27+
if (event === 'SIGINT') {
28+
mockProcess.exit();
29+
}
30+
},
2631
stdin: {
2732
setRawMode: jest.fn(),
2833
on: jest.fn(),

packages/repack/src/commands/common/setupInteractions.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,17 @@ export function setupInteractions(
4141
readline.emitKeypressEvents(process.stdin);
4242
process.stdin.setRawMode(true);
4343

44+
// graceful shutdown
45+
process.on('SIGINT', () => {
46+
process.exit();
47+
});
48+
4449
process.stdin.on('keypress', (_key, data) => {
4550
const { ctrl, name } = data;
4651
if (ctrl === true) {
4752
switch (name) {
4853
case 'c':
49-
process.exit();
54+
process.emit('SIGINT', 'SIGINT');
5055
break;
5156

5257
case 'z':
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* Reference: https://github.com/web-infra-dev/rspack/blob/bad70431988d77d8a95320066f72c77b6cc4c120/packages/rspack-cli/src/utils/profile.ts
3+
*/
4+
5+
/**
6+
* `RSPACK_PROFILE=ALL` // all trace events
7+
* `RSPACK_PROFILE=OVERVIEW` // overview trace events
8+
* `RSPACK_PROFILE=warn,tokio::net=info` // trace filter from https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax
9+
*/
10+
import fs from 'node:fs';
11+
import path from 'node:path';
12+
import { rspack } from '@rspack/core';
13+
14+
const overviewTraceFilter = 'info';
15+
const allTraceFilter = 'trace';
16+
const defaultRustTraceLayer = 'chrome';
17+
18+
function resolveLayer(value: string) {
19+
if (value === 'OVERVIEW') {
20+
return overviewTraceFilter;
21+
}
22+
if (value === 'ALL') {
23+
return allTraceFilter;
24+
}
25+
return value;
26+
}
27+
28+
export async function applyProfile(
29+
filterValue: string,
30+
traceLayer: string = defaultRustTraceLayer,
31+
traceOutput?: string
32+
) {
33+
const { asyncExitHook } = await import('exit-hook');
34+
35+
if (traceLayer !== 'chrome' && traceLayer !== 'logger') {
36+
throw new Error(`unsupported trace layer: ${traceLayer}`);
37+
}
38+
39+
if (!traceOutput) {
40+
const timestamp = Date.now();
41+
const defaultOutputDir = path.resolve(
42+
`.rspack-profile-${timestamp}-${process.pid}`
43+
);
44+
const defaultRustTraceChromeOutput = path.join(
45+
defaultOutputDir,
46+
'trace.json'
47+
);
48+
const defaultRustTraceLoggerOutput = 'stdout';
49+
50+
const defaultTraceOutput =
51+
traceLayer === 'chrome'
52+
? defaultRustTraceChromeOutput
53+
: defaultRustTraceLoggerOutput;
54+
55+
// biome-ignore lint/style/noParameterAssign: setting default value makes sense
56+
traceOutput = defaultTraceOutput;
57+
}
58+
59+
const filter = resolveLayer(filterValue);
60+
61+
await ensureFileDir(traceOutput);
62+
await rspack.experiments.globalTrace.register(
63+
filter,
64+
traceLayer,
65+
traceOutput
66+
);
67+
asyncExitHook(rspack.experiments.globalTrace.cleanup, {
68+
wait: 500,
69+
});
70+
}
71+
72+
async function ensureFileDir(outputFilePath: string) {
73+
const dir = path.dirname(outputFilePath);
74+
await fs.promises.mkdir(dir, { recursive: true });
75+
}

packages/repack/src/commands/rspack/start.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,15 @@ export async function start(
7373
});
7474
}
7575

76+
if (process.env.RSPACK_PROFILE) {
77+
const { applyProfile } = await import('./profile.js');
78+
await applyProfile(
79+
process.env.RSPACK_PROFILE,
80+
process.env.RSPACK_TRACE_LAYER,
81+
process.env.RSPACK_TRACE_OUTPUT
82+
);
83+
}
84+
7685
const compiler = new Compiler(configs, reporter, cliConfig.root);
7786

7887
const { createServer } = await import('@callstack/repack-dev-server');

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)