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(<>); +});