diff --git a/.github/workflows/npmjs.yml b/.github/workflows/npmjs.yml index 2387fd9..4402832 100644 --- a/.github/workflows/npmjs.yml +++ b/.github/workflows/npmjs.yml @@ -10,30 +10,32 @@ on: jobs: build: runs-on: ubuntu-latest + permissions: + pull-requests: write strategy: matrix: - target: ['node'] + target: ['Node'] node: ['14', '16'] include: - - target: web + - target: Web node: 16 - browser: firefox - - target: web + browser: Firefox + - target: Web node: 16 - browser: chromium - - target: web + browser: Chromium + - target: Web node: 16 - browser: webkit + browser: WebKit steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v3 + - uses: actions/cache@v3 id: cache with: path: | node_modules ~/.cache/ms-playwright key: ${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }} - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} registry-url: https://registry.npmjs.org/ @@ -43,7 +45,18 @@ jobs: - if: matrix.node == '16' && matrix.browser == 'webkit' run: sudo npx playwright install-deps - run: ENV=${{ matrix.target }} BROWSER=${{ matrix.browser }} npm test - - run: ENV=${{ matrix.target }} BROWSER=${{ matrix.browser }} npm run benchmarks + - id: benchmarks + run: ENV=${{ matrix.target }} BROWSER=${{ matrix.browser }} npm run benchmarks + - uses: marocchino/sticky-pull-request-comment@v2 + if: matrix.target == 'Node' + with: + header: Node ${{ matrix.node }} + path: ./.benchmarks.md + - uses: marocchino/sticky-pull-request-comment@v2 + if: matrix.target == 'Web' + with: + header: ${{ matrix.browser}} + path: ./.benchmarks.md - if: github.event_name == 'release' && github.event.action == 'published' && matrix.node == '16' && matrix.target == 'node' run: npm publish env: diff --git a/.gitignore b/.gitignore index 3bcac18..46e3b73 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ Thumbs.db test-coverage coverage.shield.badge.md dist +.benchmarks.md diff --git a/config/build.shared.ts b/config/build.shared.ts index 81e60c1..818ae5f 100644 --- a/config/build.shared.ts +++ b/config/build.shared.ts @@ -2,7 +2,8 @@ import { createHash } from 'crypto'; import { readFileSync } from 'fs'; import pkg from '../package.json'; -export const ENV = process.env.ENV?.toLowerCase() === 'web' ? 'web' : 'node'; +export const TARGET_ENV = + process.env.ENV?.toLowerCase() === 'web' ? 'web' : 'node'; const md5 = (message: string | Buffer) => { const hash = createHash('md5'); @@ -30,6 +31,6 @@ const BROWSER = export const define = { PACKAGE_VERSION: JSON.stringify(PACKAGE_VERSION), VERSION: JSON.stringify(VERSION), - ENV: JSON.stringify(ENV), + ENV: JSON.stringify(TARGET_ENV), BROWSER: JSON.stringify(BROWSER), }; diff --git a/test/benchmarks.ts b/test/benchmarks.ts index efed7c9..20e49dc 100644 --- a/test/benchmarks.ts +++ b/test/benchmarks.ts @@ -1,8 +1,9 @@ import { Suite } from 'benchmark'; import type Benchmark from 'benchmark'; +import { writeFileSync } from 'fs'; import { setFlagsFromString } from 'v8'; import { runInNewContext } from 'vm'; -import { writeFileSync } from 'fs'; +import { fileURLToPath } from 'url'; import { setup } from './web/setup'; if (ENV === 'web') { @@ -107,70 +108,69 @@ for await (const suite of suites.values()) { await runSuite(suite); } -const { GITHUB_STEP_SUMMARY } = process.env; +const SUMMARY_PATH = fileURLToPath( + new URL('../.benchmarks.md', import.meta.url) +); -if (GITHUB_STEP_SUMMARY) { - const sum = (ns: number[]) => ns.reduce((acc, n) => acc + n, 0); - const avg = (ns: number[]) => sum(ns) / ns.length; - - const benchmarks = [...suites.values()] - .flatMap((suite): Benchmark[] => suite.slice(0, suite.length)) - .filter((benchmark) => benchmark.name !== RELOAD_WORKAROUND) - .sort((a, b) => a.hz - b.hz); - - const times = benchmarks.map(({ times }) => times!.elapsed); - const time = sum(times).toFixed(2); - const means = benchmarks.map(({ stats }) => stats.mean * 1000); - const average = avg(means); - const nonOutlierIndex = Math.max( - means.findIndex((mean, index) => { - if (index === 0 || index > means.length - 2) { - return false; - } +const sum = (ns: number[]) => ns.reduce((acc, n) => acc + n, 0); +const avg = (ns: number[]) => sum(ns) / ns.length; + +const benchmarks = [...suites.values()] + .flatMap((suite): Benchmark[] => suite.slice(0, suite.length)) + .filter((benchmark) => benchmark.name !== RELOAD_WORKAROUND) + .sort((a, b) => a.hz - b.hz); + +const times = benchmarks.map(({ times }) => times!.elapsed); +const time = sum(times).toFixed(2); +const means = benchmarks.map(({ stats }) => stats.mean * 1000); +const average = avg(means); +const nonOutlierIndex = Math.max( + means.findIndex((mean, index) => { + if (index === 0 || index > means.length - 2) { + return false; + } - const previous = means[index - 1]; - const next = means[index + 1]; + const previous = means[index - 1]; + const next = means[index + 1]; - return ( - previous / average > (mean / average) * 2 && - mean / average <= (next / average) * 2 - ); - }), - 0 - ); - const averageWithoutOutliers = avg(means.slice(nonOutlierIndex)); - - /** - * Roughly based on {@link https://github.com/bestiejs/benchmark.js/blob/42f3b732bac3640eddb3ae5f50e445f3141016fd/benchmark.js#L1525}, simplified and modified to output a GitHub Actions summary. - */ - const summaries = benchmarks.map((bench, index) => { - const { error, name, stats } = bench; - let result = error?.message; - - if (result == null) { - const size = stats.sample.length; - const mean = `${means[index].toFixed(2)} ms`; - - const [hzWhole, hzFractional] = String( - bench.hz.toFixed(bench.hz < 100 ? 2 : 0) - ).split('.'); - const hz = - hzWhole.replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + - (hzFractional ? `.${hzFractional}` : ''); - const rme = `±${stats.rme.toFixed(2)}%`; - const samples = `${size} run${size === 1 ? '' : 's'}`; - - result = `${mean} (${hz} ops/s ${rme}, ${samples})`; - } + return ( + previous / average > (mean / average) * 2 && + mean / average <= (next / average) * 2 + ); + }), + 0 +); +const averageWithoutOutliers = avg(means.slice(nonOutlierIndex)); - return [name, result]; - }); - const [slowest] = summaries; - const fastest = summaries[summaries.length - 1]; +/** + * Roughly based on {@link https://github.com/bestiejs/benchmark.js/blob/42f3b732bac3640eddb3ae5f50e445f3141016fd/benchmark.js#L1525}, simplified and modified to output a GitHub Actions summary. + */ +const summaries = benchmarks.map((bench, index) => { + const { error, name, stats } = bench; + let result = error?.message; + + if (result == null) { + const size = stats.sample.length; + const mean = `${means[index].toFixed(2)} ms`; + + const [hzWhole, hzFractional] = String( + bench.hz.toFixed(bench.hz < 100 ? 2 : 0) + ).split('.'); + const hz = + hzWhole.replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + + (hzFractional ? `.${hzFractional}` : ''); + const rme = `±${stats.rme.toFixed(2)}%`; + const samples = `${size} run${size === 1 ? '' : 's'}`; + + result = `${mean} (${hz} ops/s ${rme}, ${samples})`; + } - const summary = /* html */ ` -

Benchmarks

+ return [name, result]; +}); +const [slowest] = summaries; +const fastest = summaries[summaries.length - 1]; +const summary = /* html */ ` @@ -218,9 +218,14 @@ if (GITHUB_STEP_SUMMARY) {
` - .trim() - .replace(/(^|\n)\s+/g, '$1'); + .trim() + .replace(/(^|\n)\s+/g, '$1'); + +writeFileSync(SUMMARY_PATH, summary); + +const { GITHUB_STEP_SUMMARY } = process.env; +if (GITHUB_STEP_SUMMARY != null) { writeFileSync(GITHUB_STEP_SUMMARY, summary); } diff --git a/vite.config.ts b/vite.config.ts index 2238044..b272fc0 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,10 +3,10 @@ import type { LibraryFormats } from 'vite'; import type { UserConfig } from 'vitest/config'; import { defineConfig } from 'vitest/config'; import config from './config/config.json'; -import { define, ENV } from './config/build.shared'; +import { define, TARGET_ENV } from './config/build.shared'; export default defineConfig(async () => { - const isWeb = ENV === 'web'; + const isWeb = TARGET_ENV === 'web'; const entryNames = isWeb ? ['transformer'] : ['app', 'transformer']; const entry = entryNames.map((name) => resolve(__dirname, `./src/${name}.ts`)