Skip to content
Open
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 .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ jobs:
with:
node-version: 24.21.0

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2

- name: Install Global Dependencies
run: |
npm i cross-env -g
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Build Tools Comparison

Benchmark comparing JavaScript bundlers and build tools ([Rspack](https://github.com/web-infra-dev/rspack), [Rsbuild](https://github.com/web-infra-dev/rsbuild), [webpack](https://github.com/webpack/webpack), [Vite](https://github.com/vitejs/vite), [Rolldown](https://github.com/rolldown/rolldown), [esbuild](https://github.com/evanw/esbuild), [Rollup](https://github.com/rollup/rollup), [Parcel](https://github.com/parcel-bundler/parcel), [Farm](https://github.com/farm-fe/farm) and [Utoo](https://github.com/utooland/utoo)) for dev server startup time, build performance and bundle size for applications with different module sizes.
Benchmark comparing JavaScript bundlers and build tools ([Rspack](https://github.com/web-infra-dev/rspack), [Rsbuild](https://github.com/web-infra-dev/rsbuild), [webpack](https://github.com/webpack/webpack), [Vite](https://github.com/vitejs/vite), [Rolldown](https://github.com/rolldown/rolldown), [esbuild](https://github.com/evanw/esbuild), [Rollup](https://github.com/rollup/rollup), [Parcel](https://github.com/parcel-bundler/parcel), [Farm](https://github.com/farm-fe/farm), [Utoo](https://github.com/utooland/utoo) and [Bun](https://bun.com)) for dev server startup time, build performance and bundle size for applications with different module sizes.

## Metrics

Expand Down
1 change: 1 addition & 0 deletions cases/react-1k/benchmark-config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const config = {
'farm',
'parcel',
'utoo',
'bun',
],
rootFile: 'f0.jsx',
leafFile: 'd0/d0/d0/f0.jsx',
Expand Down
34 changes: 34 additions & 0 deletions cases/react-1k/bun-build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { spawn } from 'node:child_process';

// Printed before the Bun process starts so the harness can measure build time.
console.log('Benchmark Start Time:', Date.now());

const child = spawn(
'bun',
[
'build',
'./index.html',
'--outdir=dist',
'--target=browser',
'--minify',
'--production',
'--define',
'process.env.NODE_ENV:"production"',
],
{
stdio: 'inherit',
cwd: import.meta.dirname,
env: {
...process.env,
NODE_ENV: 'production',
},
},
);

child.on('exit', (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 1);
});
26 changes: 26 additions & 0 deletions cases/react-1k/bun-dev.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { spawn } from 'node:child_process';

// Printed before the Bun process starts so the harness can measure startup.
console.log('Benchmark Start Time:', Date.now());

// Keep in sync with the Bun BuildTool port in scripts/benchmark.ts.
const port = '3000';
const child = spawn('bun', ['--port', port, './index.html'], {
stdio: 'inherit',
cwd: import.meta.dirname,
env: process.env,
});

child.on('exit', (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 1);
});

for (const signal of ['SIGINT', 'SIGTERM']) {
process.on(signal, () => {
child.kill(signal);
});
}
2 changes: 2 additions & 0 deletions cases/react-1k/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "react-1k",
"version": "0.0.0",
"scripts": {
"build:bun": "node ./bun-build.mjs",
"build:farm": "farm build",
"build:parcel": "parcel build index.html",
"build:rolldown": "cross-env NODE_ENV=production rolldown -c ./rolldown.config.mjs",
Expand All @@ -10,6 +11,7 @@
"build:utoo": "cross-env NODE_ENV=production up build",
"build:vite": "vite build",
"build:webpack": "cross-env NODE_ENV=production webpack build --mode production",
"start:bun": "node ./bun-dev.mjs",
"start:farm": "farm start",
"start:parcel": "parcel -p 3200 index.html",
"start:rsbuild": "rsbuild dev",
Expand Down
49 changes: 44 additions & 5 deletions scripts/benchmark.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { spawn, type ChildProcess } from 'node:child_process';
import {
execFileSync,
spawn,
type ChildProcess,
} from 'node:child_process';
import os from 'node:os';
import {
monitorProcess,
Expand Down Expand Up @@ -144,7 +148,12 @@ interface BuildToolOptions {
startScript: string;
startedRegex: RegExp;
buildScript: string;
binFilePath: string;
/**
* Path under `node_modules` to a CLI entry that can be patched with the
* benchmark start timestamp. Omit for tools that ship their own wrapper
* (for example Bun) and already print `Benchmark Start Time`.
*/
binFilePath?: string;
}

class BuildTool {
Expand All @@ -153,7 +162,7 @@ class BuildTool {
private readonly startScript: string;
private readonly startedRegex: RegExp;
private readonly buildScript: string;
private readonly binFilePath: string;
private readonly binFilePath?: string;

constructor({
name,
Expand All @@ -168,8 +177,10 @@ class BuildTool {
this.startScript = startScript;
this.startedRegex = startedRegex;
this.buildScript = buildScript;
this.binFilePath = path.join(process.cwd(), 'node_modules', binFilePath);
this.hackBinFile();
if (binFilePath) {
this.binFilePath = path.join(process.cwd(), 'node_modules', binFilePath);
this.hackBinFile();
}
}

cleanCache(): void {
Expand All @@ -180,6 +191,8 @@ class BuildTool {
'node_modules/.vite',
'node_modules/.farm',
'.turbopack',
// Bun may write compile/cache artifacts under the case directory.
'.bun',
]) {
fse.removeSync(path.join(dir, cache));
}
Expand All @@ -188,6 +201,8 @@ class BuildTool {

// Add a `console.log('Benchmark start', Date.now())` to the bin file's second line
private hackBinFile(): void {
if (!this.binFilePath) return;

logger.info(
'Setup bin file for',
color.green(this.name),
Expand Down Expand Up @@ -439,6 +454,30 @@ parseToolNames().forEach((name) => {
}),
);
break;
case 'bun': {
// Bun is a system binary (not an npm package). Wrappers under the case
// directory print `Benchmark Start Time` themselves.
let bunVersion: string;
try {
bunVersion = execFileSync('bun', ['--version'], {
encoding: 'utf8',
}).trim();
} catch {
throw new Error(
'Bun is not installed or not on PATH. Install Bun to run this benchmark tool.',
);
}
buildTools.push(
new BuildTool({
name: 'Bun ' + bunVersion,
port: 3000,
startScript: 'start:bun',
startedRegex: /dev server ready in (.+) (s|ms)/,
buildScript: 'build:bun',
}),
);
break;
}
}
});

Expand Down
Loading