Skip to content

New Workload: React Server Side Rendering Startup #116

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

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
760ef6f
adding web sssr
camillobruni Aug 7, 2025
47e0a16
wip
camillobruni Aug 7, 2025
f159ea6
adding stuff
camillobruni Aug 7, 2025
27f257f
fix
camillobruni Aug 7, 2025
062a4cc
update
camillobruni Aug 7, 2025
5b7a194
fixes
camillobruni Aug 7, 2025
cd91ad4
update
camillobruni Aug 7, 2025
5d1543e
Merge branch 'WebKit:main' into 2025-08-07_web_ssr
camillobruni Aug 7, 2025
ccecfa8
Merge branch 'main' into 2025-08-07_web_ssr
camillobruni Aug 8, 2025
3f61cd5
Merge branch '2025-08-07_web_ssr' of github.com:camillobruni/JetStrea…
camillobruni Aug 8, 2025
dc87fee
update
camillobruni Aug 8, 2025
cb9badf
update
camillobruni Aug 8, 2025
8612487
add comment-injecting terser plugin
camillobruni Aug 10, 2025
384cb64
more
camillobruni Aug 10, 2025
3ed8ab4
update
camillobruni Aug 11, 2025
c6e4585
adding more files
camillobruni Aug 11, 2025
636d6a0
add CACHE_BUST_COMMENT counting
camillobruni Aug 11, 2025
34ce451
backup
camillobruni Aug 11, 2025
9c2717d
use RE to count comments
camillobruni Aug 11, 2025
31489cc
fixing
camillobruni Aug 11, 2025
6723625
update comment adder
camillobruni Aug 11, 2025
1b51510
rename
camillobruni Aug 11, 2025
3d865c1
renaming
camillobruni Aug 11, 2025
8ca7363
add more detail
camillobruni Aug 11, 2025
fa1ff84
update
camillobruni Aug 11, 2025
0bdc931
Merge remote-tracking branch 'webkit/main' into 2025-08-07_web_ssr
camillobruni Aug 12, 2025
56f014a
pre-format
camillobruni Aug 12, 2025
0eb7f42
pre-format
camillobruni Aug 12, 2025
edc344c
cleanup
camillobruni Aug 12, 2025
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
16 changes: 15 additions & 1 deletion JetStreamDriver.js
Original file line number Diff line number Diff line change
Expand Up @@ -1218,7 +1218,7 @@ class AsyncBenchmark extends DefaultBenchmark {
get runnerCode() {
return `
async function doRun() {
let __benchmark = new Benchmark();
let __benchmark = new Benchmark(${this.iterations});
await __benchmark.init?.();
let results = [];
let benchmarkName = "${this.name}";
Expand Down Expand Up @@ -1923,6 +1923,20 @@ let BENCHMARKS = [
],
tags: ["Default", "Proxy"],
}),
new AsyncBenchmark({
name: "web-ssr",
files: [
"./web-ssr/benchmark.js",
],
preload: {
// Debug Sources for nicer profiling.
// sourceCodeBlob: "./web-ssr/dist/react-render-test.js",
REACT_RENDER_TEST_BLOB: "./web-ssr/dist/react-render-test.minified.js",
},
tags: ["Default", "web", "ssr"],
iterations: 5,
worstCaseCount: 3,
}),
// Class fields
new DefaultBenchmark({
name: "raytrace-public-class-fields",
Expand Down
3 changes: 3 additions & 0 deletions web-ssr/babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
14 changes: 14 additions & 0 deletions web-ssr/benchmark-node.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// node standalone version of the benchmark for local testing.

const {renderTest } = require("./src/react-render-test.cjs")

console.log("Starting TypeScript in-memory compilation benchmark...");
const startTime = performance.now();

renderTest();

const endTime = performance.now();
const duration = (endTime - startTime) / 1000;

console.log(`TypeScript compilation finished.`);
console.log(`Compilation took ${duration.toFixed(2)} seconds.`);
91 changes: 91 additions & 0 deletions web-ssr/benchmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
globalThis.console = {
log() { },
warn() { },
assert(condition) {
if (!condition) throw new Error("Invalid assertion");
}
};

globalThis.clearTimeout = function () { };


function quickHash(str) {
let hash = 5381;
let i = str.length;
while (i > 0) {
hash = (hash * 33) ^ (str.charCodeAt(i) | 0);
i-= 919;
}
return hash | 0;
}

const CACHE_BUST_COMMENT = "/*ThouShaltNotCache*/";
const CACHE_BUST_COMMENT_RE = new RegExp(`\n${RegExp.escape(CACHE_BUST_COMMENT)}\n`, "g");

// JetStream benchmark.
class Benchmark {
measureStartup = true;
iterationCount = 0;
iteration = 0;
lastResult = {};
sourceCode;
sourceHash = 0
iterationSourceCodes = [];

constructor(iterationCount) {
this.iterationCount = iterationCount
}

async init() {
this.sourceCode = await getString(REACT_RENDER_TEST_BLOB);
this.expect("Cache Comment Count", this.sourceCode.match(CACHE_BUST_COMMENT_RE).length, 597);
// Warm up the hash function.
this.sourceHash = quickHash(this.sourceCode);
for (let i = 0; i < this.iterationCount; i++)
this.iterationSourceCodes[i] = this.prepareCode(i);
}


prepareCode(iteration) {
if (!this.measureStartup)
return this.sourceCode;
// Alter the code per iteration to prevent caching.
const iterationId = `${String.fromCharCode(97 + (iteration % 25))}${iteration}`;
const sourceCode = this.sourceCode.replaceAll(CACHE_BUST_COMMENT_RE, `/*${iterationId}*/`);
return sourceCode;
}

runIteration() {
let sourceCode = this.iterationSourceCodes[this.iteration];
if (!sourceCode)
throw new Error(`Could not find source for iteration ${this.iteration}`);
// Module in sourceCode it assigned to the ReactRenderTest variable.
let ReactRenderTest;

let initStart = performance.now();
const res = eval(sourceCode);
const runStart = performance.now();

this.lastResult = ReactRenderTest.renderTest();
this.lastResult.htmlHash = quickHash(this.lastResult.html);
const end = performance.now();

const loadTime = runStart - initStart;
const runTime = end - runStart;
// For local debugging:
// print(`Iteration ${this.iteration}:`);
// print(` Load time: ${loadTime.toFixed(2)}ms`);
// print(` Render time: ${runTime.toFixed(2)}ms`);
this.iteration++;
}

validate() {
this.expect("HTML length", this.lastResult.html.length, 183778);
this.expect("HTML hash", this.lastResult.htmlHash, 1177839858);
}

expect(name, value, expected) {
if (value != expected)
throw new Error(`Expected ${name} to be ${expected}, but got ${value}`);
}
}
29 changes: 29 additions & 0 deletions web-ssr/build/cache-buster-comment-plugin.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Babel plugin that adds CACHE_BUST_COMMENT to every function body.
const CACHE_BUST_COMMENT = "ThouShaltNotCache";


module.exports = function({ types: t }) {
return {
visitor: {
Function(path) {
const bodyPath = path.get("body");
// Handle arrow functions: () => "value"
// Convert them to block statements: () => { return "value"; }
if (!bodyPath.isBlockStatement()) {
const newBody = t.blockStatement([t.returnStatement(bodyPath.node)]);
path.set("body", newBody);
}

// Handle empty function bodies: function foo() {}
// Add an empty statement so we have a first node to attach the comment to.
if (path.get("body.body").length === 0) {
path.get("body").pushContainer("body", t.emptyStatement());
}

const firstNode = path.node.body.body[0];
t.addComment(firstNode, "leading", CACHE_BUST_COMMENT);

}
},
};
};
1,221 changes: 1,221 additions & 0 deletions web-ssr/dist/react-render-test.js

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions web-ssr/dist/react-render-test.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom-server-legacy.browser.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react-dom-server.browser.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react-dom.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
1 change: 1 addition & 0 deletions web-ssr/dist/react-render-test.js.map

Large diffs are not rendered by default.

1,221 changes: 1,221 additions & 0 deletions web-ssr/dist/react-render-test.minified.js

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions web-ssr/dist/react-render-test.minified.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom-server-legacy.browser.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react-dom-server.browser.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react-dom.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
1 change: 1 addition & 0 deletions web-ssr/dist/react-render-test.minified.js.map

Large diffs are not rendered by default.

Loading
Loading