From 6ddfd5e05c8849789abce12fba56af6abc3ef543 Mon Sep 17 00:00:00 2001
From: hzy <28915578+hzy@users.noreply.github.com>
Date: Tue, 9 Sep 2025 18:02:54 +0800
Subject: [PATCH] ci(benchmark/react): add LoadScript to benchmark
---
benchmark/react/cases/001-fib/index.ts | 101 +++++++++---------
.../react/cases/002-hello-reactLynx/index.tsx | 14 +--
.../react/cases/003-hello-list/index.tsx | 8 +-
.../react/cases/004-various-update/index.tsx | 8 +-
.../react/cases/005-load-script/index.tsx | 12 +++
benchmark/react/lynx.config.js | 8 +-
benchmark/react/package.json | 2 +
benchmark/react/plugins/pluginScriptLoad.mjs | 52 +++++++++
benchmark/react/rspeedy-env.d.ts | 9 ++
.../src/{dummyRoot.jsx => dummyRoot.tsx} | 4 +-
10 files changed, 154 insertions(+), 64 deletions(-)
create mode 100644 benchmark/react/cases/005-load-script/index.tsx
create mode 100644 benchmark/react/plugins/pluginScriptLoad.mjs
rename benchmark/react/src/{dummyRoot.jsx => dummyRoot.tsx} (81%)
diff --git a/benchmark/react/cases/001-fib/index.ts b/benchmark/react/cases/001-fib/index.ts
index 1138b4785c..6adeb38728 100644
--- a/benchmark/react/cases/001-fib/index.ts
+++ b/benchmark/react/cases/001-fib/index.ts
@@ -2,61 +2,62 @@
// Licensed under the Apache License Version 2.0 that can be found in the
// LICENSE file in the root directory of this source tree.
-import '@lynx-js/react';
import { Bench } from 'tinybench';
import { withCodspeed } from '../../src/withCodspeed.js';
-if (__MAIN_THREAD__) {
- function fib(n: number): number {
- if (n <= 1) return n;
- return fib(n - 1) + fib(n - 2);
- }
-
- function fib2(n: number): number {
- const memo: number[] = Array.from({ length: n + 1 });
- const dp = (n: number): number => {
+runAfterLoadScript(() => {
+ if (__MAIN_THREAD__) {
+ function fib(n: number): number {
if (n <= 1) return n;
- if (memo[n]) return memo[n];
- memo[n] = dp(n - 1) + dp(n - 2);
- return memo[n];
- };
- return dp(n);
- }
+ return fib(n - 1) + fib(n - 2);
+ }
- function fib3(n: number): number {
- if (n === 0) return 0;
- if (n === 1) return 1;
- let prev = 0, curr = 1;
- for (let i = 2; i <= n; i++) {
- const next = prev + curr;
- prev = curr;
- curr = next;
+ function fib2(n: number): number {
+ const memo: number[] = Array.from({ length: n + 1 });
+ const dp = (n: number): number => {
+ if (n <= 1) return n;
+ if (memo[n]) return memo[n];
+ memo[n] = dp(n - 1) + dp(n - 2);
+ return memo[n];
+ };
+ return dp(n);
+ }
+
+ function fib3(n: number): number {
+ if (n === 0) return 0;
+ if (n === 1) return 1;
+ let prev = 0, curr = 1;
+ for (let i = 2; i <= n; i++) {
+ const next = prev + curr;
+ prev = curr;
+ curr = next;
+ }
+ return curr;
}
- return curr;
- }
- const bench = withCodspeed(
- new Bench({
- name: 'simple benchmark',
- time: 5,
- iterations: 20,
- }),
- );
-
- bench
- .add(`${__REPO_FILEPATH__}::more faster fib(20)`, () => {
- fib3(20);
- })
- .add(`${__REPO_FILEPATH__}::faster fib(20)`, () => {
- fib2(20);
- })
- .add(`${__REPO_FILEPATH__}::slower fib(20)`, () => {
- fib(20);
- });
-
- bench.runSync();
-
- console.log(bench.name);
- console.log(JSON.stringify(bench.table(), undefined, 2));
-}
+ const bench = withCodspeed(
+ new Bench({
+ name: 'simple benchmark',
+ time: 5,
+ iterations: 20,
+ }),
+ );
+
+ bench
+ .add(`${__REPO_FILEPATH__}::more faster fib(20)`, () => {
+ fib3(20);
+ })
+ .add(`${__REPO_FILEPATH__}::faster fib(20)`, () => {
+ fib2(20);
+ })
+ .add(`${__REPO_FILEPATH__}::slower fib(20)`, () => {
+ fib(20);
+ });
+
+ bench.runSync();
+
+ console.log(bench.name);
+ console.log(JSON.stringify(bench.table(), undefined, 2));
+ }
+});
diff --git a/benchmark/react/cases/002-hello-reactLynx/index.tsx b/benchmark/react/cases/002-hello-reactLynx/index.tsx
index 9e241c6812..3e86f2c300 100644
--- a/benchmark/react/cases/002-hello-reactLynx/index.tsx
+++ b/benchmark/react/cases/002-hello-reactLynx/index.tsx
@@ -7,9 +7,11 @@ import { root } from '@lynx-js/react';
import RecursiveText from './RecursiveText.js';
import { RunBenchmarkUntilHydrate } from '../../src/RunBenchmarkUntil.js';
-root.render(
- <>
-
-
- >,
-);
+runAfterLoadScript(() => {
+ root.render(
+ <>
+
+
+ >,
+ );
+});
diff --git a/benchmark/react/cases/003-hello-list/index.tsx b/benchmark/react/cases/003-hello-list/index.tsx
index 32479814bb..8659841bd1 100644
--- a/benchmark/react/cases/003-hello-list/index.tsx
+++ b/benchmark/react/cases/003-hello-list/index.tsx
@@ -68,6 +68,8 @@ function BenchmarkList() {
);
}
-root.render(
- ,
-);
+runAfterLoadScript(() => {
+ root.render(
+ ,
+ );
+});
diff --git a/benchmark/react/cases/004-various-update/index.tsx b/benchmark/react/cases/004-various-update/index.tsx
index 3d48867849..ddec0a53e9 100644
--- a/benchmark/react/cases/004-various-update/index.tsx
+++ b/benchmark/react/cases/004-various-update/index.tsx
@@ -227,6 +227,8 @@ function F() {
);
}
-root.render(
- ,
-);
+runAfterLoadScript(() => {
+ root.render(
+ ,
+ );
+});
diff --git a/benchmark/react/cases/005-load-script/index.tsx b/benchmark/react/cases/005-load-script/index.tsx
new file mode 100644
index 0000000000..f486343551
--- /dev/null
+++ b/benchmark/react/cases/005-load-script/index.tsx
@@ -0,0 +1,12 @@
+// Copyright 2025 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+import { root } from '@lynx-js/react';
+import '@lynx-js/react/experimental/lazy/import';
+
+runAfterLoadScript(() => {
+ root.render(
+ <>>,
+ );
+});
diff --git a/benchmark/react/lynx.config.js b/benchmark/react/lynx.config.js
index 451c28de76..d9b2b81b37 100644
--- a/benchmark/react/lynx.config.js
+++ b/benchmark/react/lynx.config.js
@@ -7,9 +7,11 @@ import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin';
import { defineConfig } from '@lynx-js/rspeedy';
import { pluginRepoFilePath } from './plugins/pluginRepoFilePath.mjs';
+import { pluginScriptLoad } from './plugins/pluginScriptLoad.mjs';
export default defineConfig({
output: {
+ filenameHash: false,
minify: {
js: true,
jsOptions: {
@@ -25,7 +27,7 @@ export default defineConfig({
entry: {
'001-fib': [
'event-target-polyfill',
- './src/dummyRoot.jsx',
+ './src/dummyRoot.tsx',
'./cases/001-fib/index.ts',
],
'002-hello-reactLynx': [
@@ -40,6 +42,9 @@ export default defineConfig({
'004-various-update': [
'./cases/004-various-update/index.tsx',
],
+ '005-load-script': [
+ './cases/005-load-script/index.tsx',
+ ],
},
},
plugins: [
@@ -49,6 +54,7 @@ export default defineConfig({
pipelineSchedulerConfig: 0,
debugInfoOutside: false,
}),
+ pluginScriptLoad(),
pluginQRCode({}),
],
performance: {
diff --git a/benchmark/react/package.json b/benchmark/react/package.json
index e7a854c345..8218d17611 100644
--- a/benchmark/react/package.json
+++ b/benchmark/react/package.json
@@ -9,6 +9,7 @@
"bench:002-hello-reactLynx": "benchx_cli run dist/002-hello-reactLynx.lynx.bundle --wait-for-id=stop-benchmark-true",
"bench:003-hello-list": "benchx_cli run dist/003-hello-list.lynx.bundle --wait-for-id=stop-benchmark-true",
"bench:004-various-update": "benchx_cli run dist/004-various-update.lynx.bundle --wait-for-id=stop-benchmark-true",
+ "bench:005-load-script": "benchx_cli run dist/005-load-script.lynx.bundle",
"build": "rspeedy build",
"dev": "rspeedy dev",
"perfetto": "pnpm run --sequential --stream --aggregate-output '/^perfetto:.*/'",
@@ -16,6 +17,7 @@
"perfetto:002-hello-reactLynx": "benchx_cli -o dist/002-hello-reactLynx.ptrace run dist/002-hello-reactLynx.lynx.bundle --wait-for-id=stop-benchmark-true",
"perfetto:003-hello-list": "benchx_cli -o dist/003-hello-list.ptrace run dist/003-hello-list.lynx.bundle --wait-for-id=stop-benchmark-true",
"perfetto:004-various-update": "benchx_cli -o dist/004-various-update.ptrace run dist/004-various-update.lynx.bundle --wait-for-id=stop-benchmark-true",
+ "perfetto:005-load-script": "benchx_cli -o dist/005-load-script.ptrace run dist/005-load-script.lynx.bundle",
"test": "echo 'No tests specified'"
},
"dependencies": {
diff --git a/benchmark/react/plugins/pluginScriptLoad.mjs b/benchmark/react/plugins/pluginScriptLoad.mjs
new file mode 100644
index 0000000000..f5678bec28
--- /dev/null
+++ b/benchmark/react/plugins/pluginScriptLoad.mjs
@@ -0,0 +1,52 @@
+// Copyright 2025 The Lynx Authors. All rights reserved.
+// Licensed under the Apache License Version 2.0 that can be found in the
+// LICENSE file in the root directory of this source tree.
+
+/**
+ * @returns {import("@lynx-js/rspeedy").RsbuildPlugin}
+ */
+export const pluginScriptLoad = () => ({
+ name: 'pluginScriptLoad',
+ /**
+ * @param {import("@lynx-js/rspeedy").RsbuildPluginAPI} api
+ */
+ setup(api) {
+ api.modifyRspackConfig((_config, { rspack, appendPlugins }) => {
+ appendPlugins(
+ new rspack.BannerPlugin({
+ stage: rspack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
+ raw: true,
+ banner: () => {
+ return `\
+const runAfterLoadScript = (() => {
+ const q = [];
+ const r = (cb) => { q.push(cb); };
+ r.flush = () => { for (const cb of q) { cb(); } };
+ return r;
+})();
+Codspeed.startBenchmark();
+`;
+ },
+ }),
+ );
+ appendPlugins(
+ new rspack.BannerPlugin({
+ stage: rspack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
+ footer: true,
+ raw: true,
+ banner: ({ filename }) => {
+ // TODO(hzy): avoid hardcoded case dir
+ const caseDir = `benchmark/react`;
+ const chunkName = filename.replace(/^\.rspeedy\//, '');
+ // dprint-ignore
+ return `\
+Codspeed.stopBenchmark();
+Codspeed.setExecutedBenchmark(\`${caseDir}::\${${JSON.stringify(chunkName)}}_LoadScript\`);
+runAfterLoadScript.flush();
+`;
+ },
+ }),
+ );
+ });
+ },
+});
diff --git a/benchmark/react/rspeedy-env.d.ts b/benchmark/react/rspeedy-env.d.ts
index bed4b6ec3c..b840e7dccf 100644
--- a/benchmark/react/rspeedy-env.d.ts
+++ b/benchmark/react/rspeedy-env.d.ts
@@ -11,4 +11,13 @@ declare const Codspeed: {
zeroStats(): void;
};
+/**
+ * This function will be called after the script is loaded and executed.
+ * Codspeed don't allow stacked benchmark, but sadly we have some cases
+ * benchmark is executed while loading script, we need to move those cases
+ * to after script load using this API.
+ * @param cb The callback to run after script loaded.
+ */
+declare function runAfterLoadScript(cb: () => void): void;
+
declare const __REPO_FILEPATH__: string;
diff --git a/benchmark/react/src/dummyRoot.jsx b/benchmark/react/src/dummyRoot.tsx
similarity index 81%
rename from benchmark/react/src/dummyRoot.jsx
rename to benchmark/react/src/dummyRoot.tsx
index 5c7871f1af..d0bceb1e5e 100644
--- a/benchmark/react/src/dummyRoot.jsx
+++ b/benchmark/react/src/dummyRoot.tsx
@@ -4,4 +4,6 @@
import { root } from '@lynx-js/react';
-root.render(<>>);
+runAfterLoadScript(() => {
+ root.render(<>>);
+});