diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6af7c985916e..3c0af74cbe00 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -121,22 +121,25 @@ pnpm exec changeset ### Running benchmarks -We have benchmarks to keep performance under control. You can run these by running (from the project root): +We have benchmarks to keep performance under control. They are located in the `benchmarks` directory, and it exposes a CLI you can use to run them. + +You can run all available benchmarks sequentially by running (from the project root): ```shell -pnpm run benchmark --filter astro +pnpm run benchmark ``` -Which will fail if the performance has regressed by **10%** or more. - -To update the times cd into the `packages/astro` folder and run the following: +To run a specific benchmark only, you can add the name of the benchmark after the command: ```shell -node test/benchmark/build.bench.js --save -node test/benchmark/dev.bench.js --save +pnpm run benchmark memory ``` -Which will update the build and dev benchmarks. +Use `pnpm run benchmark --help` to see all available options. + +To run these benchmarks in a PR on GitHub instead of using the CLI, you can comment `!bench`. The benchmarks will run on both the PR branch and the `main` branch, and the results will be posted as a new comment. + +To run only a specific benchmark on CI, add its name after the command in your comment, for example, `!bench memory`. ## Code Structure diff --git a/packages/astro/package.json b/packages/astro/package.json index f901ddf785b7..2809376d6405 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -90,7 +90,6 @@ "build:ci": "pnpm run prebuild && astro-scripts build \"src/**/*.ts\"", "dev": "astro-scripts dev --prebuild \"src/runtime/server/astro-island.ts\" --prebuild \"src/runtime/client/{idle,load,media,only,visible}.ts\" \"src/**/*.ts\"", "postbuild": "astro-scripts copy \"src/**/*.astro\"", - "benchmark": "node test/benchmark/dev.bench.js && node test/benchmark/build.bench.js", "test:unit": "mocha --exit --timeout 30000 ./test/units/**/*.test.js", "test:unit:match": "mocha --exit --timeout 30000 ./test/units/**/*.test.js -g", "test": "pnpm run test:unit && mocha --exit --timeout 20000 --ignore **/lit-element.test.js && mocha --timeout 20000 **/lit-element.test.js", diff --git a/packages/astro/test/benchmark/benchmark.js b/packages/astro/test/benchmark/benchmark.js deleted file mode 100644 index d8b1c72fc39c..000000000000 --- a/packages/astro/test/benchmark/benchmark.js +++ /dev/null @@ -1,71 +0,0 @@ -import { promises as fsPromises, existsSync } from 'fs'; -import { performance } from 'perf_hooks'; -import * as assert from 'uvu/assert'; - -const MUST_BE_AT_LEAST_PERC_OF = 90; - -const shouldSave = process.argv.includes('--save'); - -export class Benchmark { - constructor(options) { - this.options = options; - this.setup = options.setup || Function.prototype; - } - - async execute() { - const { run } = this.options; - const start = performance.now(); - const end = await run(this.options); - const time = Math.floor(end - start); - return time; - } - - async run() { - const { file } = this.options; - - await this.setup(); - const time = await this.execute(); - - if (existsSync(file)) { - const raw = await fsPromises.readFile(file, 'utf-8'); - const data = JSON.parse(raw); - if (Math.floor((data.time / time) * 100) > MUST_BE_AT_LEAST_PERC_OF) { - this.withinPreviousRuns = true; - } else { - this.withinPreviousRuns = false; - } - } - this.time = time; - } - - report() { - const { name } = this.options; - console.log(name, 'took', this.time, 'ms'); - } - - check() { - assert.ok(this.withinPreviousRuns !== false, `${this.options.name} ran too slowly`); - } - - async save() { - const { file, name } = this.options; - const data = JSON.stringify( - { - name, - time: this.time, - }, - null, - ' ' - ); - await fsPromises.writeFile(file, data, 'utf-8'); - } - - async test() { - await this.run(); - if (shouldSave) { - await this.save(); - } - this.report(); - this.check(); - } -} diff --git a/packages/astro/test/benchmark/build-cached.json b/packages/astro/test/benchmark/build-cached.json deleted file mode 100644 index d0ec5912ddef..000000000000 --- a/packages/astro/test/benchmark/build-cached.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Snowpack Example Build Cached", - "time": 8496 -} diff --git a/packages/astro/test/benchmark/build-uncached.json b/packages/astro/test/benchmark/build-uncached.json deleted file mode 100644 index 101621c720a7..000000000000 --- a/packages/astro/test/benchmark/build-uncached.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Snowpack Example Build Uncached", - "time": 16200 -} diff --git a/packages/astro/test/benchmark/build.bench.js b/packages/astro/test/benchmark/build.bench.js deleted file mode 100644 index a140082a325a..000000000000 --- a/packages/astro/test/benchmark/build.bench.js +++ /dev/null @@ -1,85 +0,0 @@ -/** @todo migrate these to use the independent docs repository at https://github.com/withastro/docs */ - -import { fileURLToPath } from 'url'; -import { performance } from 'perf_hooks'; -import { build as astroBuild } from '#astro/build'; -import { loadConfig } from '#astro/config'; -import { Benchmark } from './benchmark.js'; -import { deleteAsync } from 'del'; -import { Writable } from 'stream'; -import { format as utilFormat } from 'util'; - -const snowpackExampleRoot = new URL('../../../../docs/', import.meta.url); - -export const errorWritable = new Writable({ - objectMode: true, - write(event, _, callback) { - let dest = process.stderr; - dest.write(utilFormat(...event.args)); - dest.write('\n'); - - callback(); - }, -}); - -let build; -async function setupBuild() { - const astroConfig = await loadConfig(fileURLToPath(snowpackExampleRoot)); - - const logging = { - level: 'error', - dest: errorWritable, - }; - - build = () => astroBuild(astroConfig, logging); -} - -async function runBuild() { - await build(); - return performance.now(); -} - -const benchmarks = [ - new Benchmark({ - name: 'Snowpack Example Build Uncached', - root: snowpackExampleRoot, - file: new URL('./build-uncached.json', import.meta.url), - async setup() { - process.chdir(new URL('../../../../', import.meta.url).pathname); - const spcache = new URL('../../node_modules/.cache/', import.meta.url); - await Promise.all([deleteAsync(spcache.pathname, { force: true }), setupBuild()]); - }, - run: runBuild, - }), - new Benchmark({ - name: 'Snowpack Example Build Cached', - root: snowpackExampleRoot, - file: new URL('./build-cached.json', import.meta.url), - async setup() { - process.chdir(new URL('../../../../', import.meta.url).pathname); - await setupBuild(); - await this.execute(); - }, - run: runBuild, - }), - /*new Benchmark({ - name: 'Snowpack Example Dev Server Cached', - root: snowpackExampleRoot, - file: new URL('./dev-server-cached.json', import.meta.url), - async setup() { - // Execute once to make sure Snowpack is cached. - await this.execute(); - } - })*/ -]; - -async function run() { - for (const b of benchmarks) { - await b.test(); - } -} - -run().catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/packages/astro/test/benchmark/dev-server-cached.json b/packages/astro/test/benchmark/dev-server-cached.json deleted file mode 100644 index 16eb8a471643..000000000000 --- a/packages/astro/test/benchmark/dev-server-cached.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Snowpack Example Dev Server Cached", - "time": 1229 -} diff --git a/packages/astro/test/benchmark/dev-server-uncached.json b/packages/astro/test/benchmark/dev-server-uncached.json deleted file mode 100644 index c0d72650dd6f..000000000000 --- a/packages/astro/test/benchmark/dev-server-uncached.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "Snowpack Example Dev Server Uncached", - "time": 3913 -} diff --git a/packages/astro/test/benchmark/dev.bench.js b/packages/astro/test/benchmark/dev.bench.js deleted file mode 100644 index 134992634abc..000000000000 --- a/packages/astro/test/benchmark/dev.bench.js +++ /dev/null @@ -1,63 +0,0 @@ -/** @todo migrate these to use the independent docs repository at https://github.com/withastro/docs */ - -import { performance } from 'perf_hooks'; -import { Benchmark } from './benchmark.js'; -import { runDevServer } from '../helpers.js'; -import { deleteAsync } from 'del'; - -const docsExampleRoot = new URL('../../../../docs/', import.meta.url); - -async function runToStarted(root) { - const args = []; - const process = runDevServer(root, args); - - let started = null; - process.stdout.setEncoding('utf8'); - for await (const chunk of process.stdout) { - if (/Server started/.test(chunk)) { - started = performance.now(); - break; - } - } - - process.kill(); - return started; -} - -const benchmarks = [ - new Benchmark({ - name: 'Docs Site Example Dev Server Uncached', - root: docsExampleRoot, - file: new URL('./dev-server-uncached.json', import.meta.url), - async setup() { - const spcache = new URL('../../node_modules/.cache/', import.meta.url); - await deleteAsync(spcache.pathname); - }, - run({ root }) { - return runToStarted(root); - }, - }), - new Benchmark({ - name: 'Docs Site Example Dev Server Cached', - root: docsExampleRoot, - file: new URL('./dev-server-cached.json', import.meta.url), - async setup() { - // Execute once to make sure Docs Site is cached. - await this.execute(); - }, - run({ root }) { - return runToStarted(root); - }, - }), -]; - -async function run() { - for (const b of benchmarks) { - await b.test(); - } -} - -run().catch((err) => { - console.error(err); - process.exit(1); -}); diff --git a/packages/astro/test/benchmark/simple/astro.config.mjs b/packages/astro/test/benchmark/simple/astro.config.mjs deleted file mode 100644 index 16a331be35b9..000000000000 --- a/packages/astro/test/benchmark/simple/astro.config.mjs +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'astro/config'; -import nodejs from '@astrojs/node'; - -export default defineConfig({ - output: 'server', - adapter: nodejs({ mode: 'middleware' }), -}); diff --git a/packages/astro/test/benchmark/simple/package.json b/packages/astro/test/benchmark/simple/package.json deleted file mode 100644 index bec29ab55e62..000000000000 --- a/packages/astro/test/benchmark/simple/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "@benchmark/simple", - "scripts": { - "start": "node server.mjs", - "build": "astro build", - "dev": "astro dev" - }, - "dependencies": { - "astro": "workspace:*", - "@astrojs/node": "workspace:*" - } -} diff --git a/packages/astro/test/benchmark/simple/server.mjs b/packages/astro/test/benchmark/simple/server.mjs deleted file mode 100644 index 3fde151e1480..000000000000 --- a/packages/astro/test/benchmark/simple/server.mjs +++ /dev/null @@ -1,19 +0,0 @@ -import http from 'http'; -import { handler } from './dist/server/entry.mjs'; - -const listener = (req, res) => { - handler(req, res, (err) => { - if (err) { - res.writeHead(500); - res.end(err.toString()); - } else { - res.writeHead(404); - res.end('Not found'); - } - }); -}; - -const server = http.createServer(listener); -server.listen(3002); -// eslint-disable-next-line no-console -console.log(`Listening at http://localhost:3002`); diff --git a/packages/astro/test/benchmark/simple/src/components/Layout.astro b/packages/astro/test/benchmark/simple/src/components/Layout.astro deleted file mode 100644 index 7224ba686867..000000000000 --- a/packages/astro/test/benchmark/simple/src/components/Layout.astro +++ /dev/null @@ -1,8 +0,0 @@ - -
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-{content}
-