chore: Add benchmarks for i18n vs vanilla usage (#2372)
This commit is contained in:
@@ -110,6 +110,7 @@
|
||||
"@types/node": "catalog:",
|
||||
"oxlint": "catalog:",
|
||||
"publint": "catalog:",
|
||||
"tinybench": "^6.0.1",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
@@ -2304,7 +2305,7 @@
|
||||
|
||||
"through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="],
|
||||
|
||||
"tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
|
||||
"tinybench": ["tinybench@6.0.1", "", {}, "sha512-cMdWsxmysdg8mNWf1pujiWl3TW0cU6m8QuNw55QlnP3I6N96Grb0wnu5N0syHIu3LbiVZCNqlfWzWDq84HZphA=="],
|
||||
|
||||
"tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="],
|
||||
|
||||
@@ -2782,6 +2783,8 @@
|
||||
|
||||
"vitest/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
"vitest/tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
|
||||
|
||||
"vue/@vue/shared": ["@vue/shared@3.5.34", "", {}, "sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA=="],
|
||||
|
||||
"widest-line/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# I18n Benchmarks
|
||||
|
||||
These benchmarks must be ran in an actual browser extension environment.
|
||||
|
||||
To run them, run `bench/run.ts` and load the `bench/` directory into a browser as an extension. Or just:
|
||||
|
||||
```sh
|
||||
bun --cwd packages/i18n bench
|
||||
```
|
||||
|
||||
Benchmarks are defined in `bench/background.ts`. Add or edit them there.
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"simple": {
|
||||
"message": "Just plain text"
|
||||
},
|
||||
"substitution": {
|
||||
"message": "Includes one substitution: $1"
|
||||
},
|
||||
"singular": {
|
||||
"message": "There is $1 item"
|
||||
},
|
||||
"plural": {
|
||||
"message": "There are $1 items"
|
||||
},
|
||||
"wxtPlural": {
|
||||
"message": "There is $1 item | There are $1 items"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import { Bench } from 'tinybench';
|
||||
import { createI18n } from '../src';
|
||||
|
||||
declare const chrome: any;
|
||||
|
||||
export const i18n = createI18n();
|
||||
|
||||
// Keep service worker alive
|
||||
setTimeout(() => {
|
||||
chrome.runtime.getPlatformInfo();
|
||||
}, 20e3);
|
||||
|
||||
(async () => {
|
||||
const results: Record<string, any> = {};
|
||||
const runBench = async (bench: Bench) => {
|
||||
await reportProgress(`[start] ${bench.name}`);
|
||||
await bench.run();
|
||||
results[bench.name!] = bench.table();
|
||||
await reportProgress(`[done] ${bench.name}`);
|
||||
};
|
||||
|
||||
{
|
||||
const key = 'simple';
|
||||
const simple = new Bench({ name: 'Simple' })
|
||||
.add('Vanilla', () => void chrome.i18n.getMessage(key))
|
||||
.add('WXT I18n', () => void i18n.t(key));
|
||||
await runBench(simple);
|
||||
}
|
||||
|
||||
{
|
||||
const key = 'substitution';
|
||||
const value = 'test';
|
||||
const substitution = new Bench({ name: 'Substitution' })
|
||||
.add('Vanilla', () => void chrome.i18n.getMessage(key, [value]))
|
||||
.add('WXT I18n', () => void i18n.t(key, [value]));
|
||||
await runBench(substitution);
|
||||
}
|
||||
|
||||
{
|
||||
const vanillaPluralKey = 'plural';
|
||||
const wxtKey = 'wxtPlural';
|
||||
const one = 1;
|
||||
const pluralSingular = new Bench({
|
||||
name: 'Plural (singular form)',
|
||||
})
|
||||
.add(
|
||||
'Vanilla',
|
||||
() => void chrome.i18n.getMessage(vanillaPluralKey, [one]),
|
||||
)
|
||||
.add('WXT I18n', () => void i18n.t(wxtKey, one));
|
||||
await runBench(pluralSingular);
|
||||
|
||||
const two = 2;
|
||||
const vanillaSingularKey = 'singular';
|
||||
const pluralPlural = new Bench({
|
||||
name: 'Plural (plural form)',
|
||||
time: 1000,
|
||||
})
|
||||
.add(
|
||||
'Vanilla',
|
||||
() => void chrome.i18n.getMessage(vanillaSingularKey, [two]),
|
||||
)
|
||||
.add('WXT I18n', () => void i18n.t(wxtKey, two));
|
||||
await runBench(pluralPlural);
|
||||
}
|
||||
|
||||
// Report results
|
||||
await reportResults(results);
|
||||
})();
|
||||
|
||||
async function reportProgress(message: string) {
|
||||
const res = await fetch('http://localhost:3000/progress', {
|
||||
method: 'POST',
|
||||
body: message,
|
||||
});
|
||||
if (!res.ok) throw Error('Progress report failed...');
|
||||
}
|
||||
|
||||
async function reportResults(results: any) {
|
||||
const res = await fetch('http://localhost:3000/results', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(results, null, 2),
|
||||
});
|
||||
if (!res.ok) throw Error('Results report failed...');
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/chrome-manifest",
|
||||
"name": "WXT I18n Benchmark",
|
||||
"version": "1.0.0",
|
||||
"manifest_version": 3,
|
||||
"default_locale": "en",
|
||||
"background": {
|
||||
"type": "module",
|
||||
"service_worker": "dist/background.js"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { join, relative } from 'node:path';
|
||||
|
||||
const distDir = join(import.meta.dir, 'dist');
|
||||
const backgroundSrc = join(import.meta.dir, 'background.ts');
|
||||
|
||||
console.log('\nBuilding benchmark extension...');
|
||||
await Bun.build({
|
||||
entrypoints: [backgroundSrc],
|
||||
outdir: distDir,
|
||||
format: 'esm',
|
||||
});
|
||||
console.log('Done!');
|
||||
|
||||
console.log(
|
||||
`\nInstall the extension from ./${relative(process.cwd(), import.meta.dir)} (or reload it) to run benchmarks.`,
|
||||
);
|
||||
console.log('Waiting for benchmark results...');
|
||||
|
||||
const CORS_HEADERS = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
};
|
||||
|
||||
Bun.serve({
|
||||
fetch: async (request) => {
|
||||
// CORS support
|
||||
if (request.method === 'OPTIONS') {
|
||||
return new Response(undefined, { headers: CORS_HEADERS });
|
||||
}
|
||||
|
||||
const url = new URL(request.url);
|
||||
if (url.pathname === '/progress') {
|
||||
console.log(`\x1b[2m← ${await request.text()}\x1b[0m`);
|
||||
return new Response(undefined, { status: 202, headers: CORS_HEADERS });
|
||||
}
|
||||
|
||||
if (url.pathname === '/results') {
|
||||
const body = await request.json();
|
||||
for (const [name, table] of Object.entries(body)) {
|
||||
console.log('\n' + name);
|
||||
console.table(table);
|
||||
}
|
||||
setTimeout(() => void process.exit(0));
|
||||
return new Response(undefined, { status: 202, headers: CORS_HEADERS });
|
||||
}
|
||||
|
||||
return new Response(undefined, { status: 404, headers: CORS_HEADERS });
|
||||
},
|
||||
});
|
||||
@@ -24,6 +24,7 @@
|
||||
"build": "buildc -- tsdown",
|
||||
"check": "buildc --deps-only -- check",
|
||||
"test": "buildc --deps-only -- vitest",
|
||||
"bench": "buildc --deps-only -- bun run bench/run.ts",
|
||||
"test:coverage": "bun run test run --coverage",
|
||||
"prepack": "bun run build"
|
||||
},
|
||||
@@ -46,6 +47,7 @@
|
||||
"@types/node": "catalog:",
|
||||
"oxlint": "catalog:",
|
||||
"publint": "catalog:",
|
||||
"tinybench": "^6.0.1",
|
||||
"tsdown": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"types": ["node"]
|
||||
"types": ["bun"]
|
||||
},
|
||||
"exclude": ["node_modules/**", "dist/**"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user