diff --git a/benchmarks/preview-server/package.json b/benchmarks/preview-server/package.json index 9d54d2be3c..e0704fcb77 100644 --- a/benchmarks/preview-server/package.json +++ b/benchmarks/preview-server/package.json @@ -2,6 +2,7 @@ "name": "@benchmarks/preview-server", "private": true, "version": "0.0.0", + "type": "module", "scripts": { "local-vs-2.1.7-canary.2": "tsx ./src/local-vs-2.1.7-canary.2.ts", "local-vs-2.1.7-canary.2-on-startup": "tsx ./src/local-vs-2.1.7-canary.2-on-startup.ts" diff --git a/benchmarks/preview-server/src/local-vs-2.1.7-canary.2-on-startup.ts b/benchmarks/preview-server/src/local-vs-2.1.7-canary.2-on-startup.ts index 457a07b7e4..7a139e58a0 100644 --- a/benchmarks/preview-server/src/local-vs-2.1.7-canary.2-on-startup.ts +++ b/benchmarks/preview-server/src/local-vs-2.1.7-canary.2-on-startup.ts @@ -4,39 +4,45 @@ import { Bench } from 'tinybench'; import { runServer } from './utils/run-server'; const pathToCanaryCliScript = path.resolve( - __dirname, + import.meta.dirname, '../', './node_modules/react-email-2.1.7-canary.2/cli/index.js', ); const pathToLocalCliScript = path.resolve( - __dirname, + import.meta.dirname, '../', './node_modules/react-email/dist/cli/index.js', ); -(async () => { - const bench = new Bench({ - iterations: 30, - }); +const bench = new Bench({ + iterations: 30, +}); - bench - .add('startup on local', async () => { +bench + .add('startup on local', async () => { + try { const server = await runServer(pathToLocalCliScript); await fetch(`${server.url}/preview/magic-links/notion-magic-link`); - server.subprocess.kill(); - }) - .add('startup on 2.1.7-canary.2', async () => { - const server = await runServer(pathToCanaryCliScript); - await fetch(`${server.url}/preview/magic-links/notion-magic-link`); - server.subprocess.kill(); - }); + if (!server.subprocess.kill()) { + throw new Error('could not close sub process for preview server'); + } + } catch (err) { + console.error('Error starting local server:', err); + } + }) + .add('startup on 2.1.7-canary.2', async () => { + const server = await runServer(pathToCanaryCliScript); + await fetch(`${server.url}/preview/magic-links/notion-magic-link`); + if (!server.subprocess.kill()) { + throw new Error('could not close sub process for preview server'); + } + }); - await bench.run(); +await bench.run(); - await fs.writeFile( - 'startup-bench-results-30-iterations.json', - JSON.stringify(bench.results), - 'utf8', - ); -})(); +await fs.writeFile( + 'startup-bench-results-30-iterations.json', + JSON.stringify(bench.results), + 'utf8', +); diff --git a/benchmarks/preview-server/src/local-vs-2.1.7-canary.2.ts b/benchmarks/preview-server/src/local-vs-2.1.7-canary.2.ts index d79d698061..417da3834e 100644 --- a/benchmarks/preview-server/src/local-vs-2.1.7-canary.2.ts +++ b/benchmarks/preview-server/src/local-vs-2.1.7-canary.2.ts @@ -4,43 +4,39 @@ import { Bench } from 'tinybench'; import { runServer } from './utils/run-server'; const pathToCanaryCliScript = path.resolve( - __dirname, + import.meta.dirname, '../', './node_modules/react-email-2.1.7-canary.2/cli/index.js', ); const pathToLocalCliScript = path.resolve( - __dirname, + import.meta.dirname, '../', './node_modules/react-email/dist/cli/index.js', ); -(async () => { - const bench = new Bench({ - iterations: 30, +const bench = new Bench({ + iterations: 30, + warmupIterations: 5, +}); + +const localServer = await runServer(pathToLocalCliScript); +const canaryServer = await runServer(pathToCanaryCliScript); +bench + .add('local', async () => { + await fetch(`${localServer.url}/preview/magic-links/notion-magic-link`); + }) + .add('2.1.7-canary.2', async () => { + await fetch(`${canaryServer.url}/preview/magic-links/notion-magic-link`); }); - const localServer = await runServer(pathToLocalCliScript); - const canaryServer = await runServer(pathToCanaryCliScript); - bench - .add('local', async () => { - await fetch(`${localServer.url}/preview/magic-links/notion-magic-link`); - }) - .add('2.1.7-canary.2', async () => { - await fetch(`${canaryServer.url}/preview/magic-links/notion-magic-link`); - }); +await bench.run(); - await fetch(`${localServer.url}/preview/magic-links/notion-magic-link`); - await fetch(`${canaryServer.url}/preview/magic-links/notion-magic-link`); +localServer.subprocess.kill(); +canaryServer.subprocess.kill(); - await bench.run(); - - localServer.subprocess.kill(); - canaryServer.subprocess.kill(); - - await fs.writeFile( - 'bench-results-30-iterations.json', - JSON.stringify(bench.results), - 'utf8', - ); -})(); +await fs.writeFile( + 'bench-results-30-iterations.json', + JSON.stringify(bench.results), + 'utf8', +); diff --git a/benchmarks/preview-server/src/utils/run-server-and-fetch-preview-page.ts b/benchmarks/preview-server/src/utils/run-server-and-fetch-preview-page.ts deleted file mode 100644 index 39015ebd37..0000000000 --- a/benchmarks/preview-server/src/utils/run-server-and-fetch-preview-page.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { spawn } from 'node:child_process'; -import path from 'node:path'; - -const decoder = new TextDecoder(); - -export function runServerAndFetchPreviewPage(pathToCliScript: string) { - return new Promise((resolve, reject) => { - const node = spawn('node', [pathToCliScript, 'dev'], { - cwd: path.resolve(__dirname, '../../../../apps/demo'), - }); - - node.stdout.on('data', (data) => { - const content = decoder.decode(data); - if (content.includes('Running preview at')) { - const url = /http:\/\/localhost:[\d]+/.exec(content)?.[0]; - if (url) { - fetch(`${url}/preview/magic-links/notion-magic-link`) - .then(async () => { - node.kill(); - resolve(); - }) - .catch(() => { - node.kill(); - reject(); - }); - } else { - node.kill(); - reject( - new Error( - 'URL was non existant in the same line, maybe we changed the way this is displayed?', - { - cause: { content, pathToCliScript }, - }, - ), - ); - } - } - }); - }); -} diff --git a/benchmarks/preview-server/src/utils/run-server.ts b/benchmarks/preview-server/src/utils/run-server.ts index cdd3ec62e5..ce4c94a3fe 100644 --- a/benchmarks/preview-server/src/utils/run-server.ts +++ b/benchmarks/preview-server/src/utils/run-server.ts @@ -11,7 +11,25 @@ export interface Server { export function runServer(pathToCliScript: string) { return new Promise((resolve, reject) => { const node = spawn('node', [pathToCliScript, 'dev'], { - cwd: path.resolve(__dirname, '../../../../apps/demo'), + cwd: path.resolve(import.meta.dirname, '../../../../apps/demo'), + }); + + const kill = () => { + node.kill(); + }; + + process.addListener('exit', kill); + process.addListener('SIGINT', kill); + process.addListener('SIGTERM', kill); + process.addListener('SIGUSR1', kill); + process.addListener('SIGUSR2', kill); + + node.on('close', () => { + process.removeListener('exit', kill); + process.removeListener('SIGINT', kill); + process.removeListener('SIGTERM', kill); + process.removeListener('SIGUSR1', kill); + process.removeListener('SIGUSR2', kill); }); node.stdout.on('data', (data) => { diff --git a/benchmarks/preview-server/tsconfig.json b/benchmarks/preview-server/tsconfig.json new file mode 100644 index 0000000000..ae3329377e --- /dev/null +++ b/benchmarks/preview-server/tsconfig.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "tsconfig/react-library.json", + "include": ["src"], + "exclude": ["node_modules"], + "compilerOptions": { + "target": "esnext", + "noUncheckedIndexedAccess": true, + "resolveJsonModule": true, + "moduleResolution": "bundler", + "module": "esnext", + "declarationMap": false, + "declaration": false, + "outDir": "dist" + } +} diff --git a/benchmarks/tailwind-component/README.md b/benchmarks/tailwind-component/README.md index 234d6d7e05..614c1e9b8b 100644 --- a/benchmarks/tailwind-component/README.md +++ b/benchmarks/tailwind-component/README.md @@ -9,9 +9,10 @@ determining the performance hits that the Tailwind component causes to try impro ├── package.json ├── src | ├── emails -| ├── benchmark-0.0.12-vs-local-version.ts -| ├── benchmark-with-vs-without.ts -| └── tailwind-render.ts +| ├── benchmark-0.0.12-vs-local-version.tsx +| ├── benchmark-0.0.17-vs-local-version.tsx +| ├── benchmark-with-vs-without.tsx +| └── tailwind-render.tsx ├── tailwind.config.js └── tsconfig.json ``` @@ -25,26 +26,13 @@ The `emails` folder contains examples to be used across different benchmarks. ## Running benchmarks -To avoid ESM problems, these benchmarks need to be compiled using `tsup`, -which can be done by running `pnpm compile`, and then using `node` directly. -Something like the following if you want to run the `with-vs-without` benchmark: - -```sh -pnpm compile && node ./dist/benchmark-with-vs-without.js -``` - -They are each compiled into a different entry on the `./dist` folder with their respective names. - We have scripts for each benchmark on our `./package.json` that you can try running: ```json -"scripts": { - "with-vs-without": "pnpm compile && node ./dist/benchmark-with-vs-without.js", - "before-perf-vs-after-perf": "pnpm compile && node ./dist/benchmark-0.0.12-vs-local-version", - - "flamegraph-render-tailwind": "pnpm compile && node --prof ./dist/tailwind-render && node --prof-process --preprocess -j isolate*.log | flamebearer", - - "compile": "tsup src/*.ts", - "lint": "eslint ." -}, + "scripts": { + "with-vs-without": "tsx ./src/benchmark-with-vs-without", + "0.0.17-vs-local": "tsx --max-old-space-size=256 ./src/benchmark-0.0.17-vs-local-version", + "0.0.12-vs-local": "tsx ./src/benchmark-0.0.12-vs-local-version", + "flamegraph-render-tailwind": "tsx --prof ./src/tailwind-render && node --prof-process --preprocess -j isolate*.log | flamebearer" + }, ``` diff --git a/benchmarks/tailwind-component/package.json b/benchmarks/tailwind-component/package.json index 4f7c6b2967..512f619005 100644 --- a/benchmarks/tailwind-component/package.json +++ b/benchmarks/tailwind-component/package.json @@ -1,7 +1,7 @@ { "name": "@benchmarks/tailwind-component", "private": true, - "main": "dist/benchmark.js", + "type": "module", "version": "0.0.0", "scripts": { "with-vs-without": "tsx ./src/benchmark-with-vs-without", diff --git a/benchmarks/tailwind-component/src/benchmark-0.0.12-vs-local-version.tsx b/benchmarks/tailwind-component/src/benchmark-0.0.12-vs-local-version.tsx index a097d2dd77..de5488c082 100644 --- a/benchmarks/tailwind-component/src/benchmark-0.0.12-vs-local-version.tsx +++ b/benchmarks/tailwind-component/src/benchmark-0.0.12-vs-local-version.tsx @@ -5,32 +5,24 @@ import { Tailwind as VersionTwelveTailwind } from 'tailwind-0.0.12'; import { Bench } from 'tinybench'; import EmailWithTailwind from './emails/with-tailwind.js'; -const main = async () => { - const bench = new Bench({ - iterations: 100, - }); - - bench - .add('local', async () => { - await render(); - }) - .add('0.0.12', async () => { - // @ts-expect-error - await render(); - }); +const bench = new Bench({ + iterations: 100, +}); - await bench.run(); +bench + .add('local', async () => { + await render(); + }) + .add('0.0.12', async () => { + // @ts-expect-error + await render(); + }); - return bench; -}; +await bench.run(); -main() - .then((bench) => { - writeFileSync( - 'bench-results-100-iterations.json', - JSON.stringify(bench.results), - 'utf-8', - ); - console.table(bench.table()); - }) - .catch(console.error); +writeFileSync( + 'bench-results-100-iterations.json', + JSON.stringify(bench.results), + 'utf-8', +); +console.table(bench.table()); diff --git a/benchmarks/tailwind-component/src/benchmark-0.0.17-vs-local-version.tsx b/benchmarks/tailwind-component/src/benchmark-0.0.17-vs-local-version.tsx index b833451b29..adb69610f1 100644 --- a/benchmarks/tailwind-component/src/benchmark-0.0.17-vs-local-version.tsx +++ b/benchmarks/tailwind-component/src/benchmark-0.0.17-vs-local-version.tsx @@ -5,31 +5,26 @@ import { Tailwind as VersionSeventeenTailwind } from 'tailwind-0.0.17'; import { Bench } from 'tinybench'; import EmailWithTailwind from './emails/with-tailwind.js'; -const main = async () => { - const bench = new Bench({ - iterations: 100, - }); - - bench - .add('local', async () => { - await render(); - }) - .add('0.0.17', async () => { - await render(); - }); +const bench = new Bench({ + iterations: 100, +}); - await bench.run(); +bench + .add('local', async () => { + await render(); + }) + .add('0.0.17', async () => { + // Doing as any here because of the React types mismatch between versions, but things should be fine + await render( + , + ); + }); - return bench; -}; +await bench.run(); -main() - .then((bench) => { - writeFileSync( - 'bench-results-100-iterations.json', - JSON.stringify(bench.results), - 'utf-8', - ); - console.table(bench.table()); - }) - .catch(console.error); +writeFileSync( + 'bench-results-100-iterations.json', + JSON.stringify(bench.results), + 'utf-8', +); +console.table(bench.table()); diff --git a/benchmarks/tailwind-component/src/benchmark-with-vs-without.tsx b/benchmarks/tailwind-component/src/benchmark-with-vs-without.tsx index b4b30952cb..ab12989131 100644 --- a/benchmarks/tailwind-component/src/benchmark-with-vs-without.tsx +++ b/benchmarks/tailwind-component/src/benchmark-with-vs-without.tsx @@ -7,24 +7,16 @@ import EmailWithoutTailwind from './emails/without-tailwind.js'; // import like this instead of installing from the workspace // to still be able to test versions that are already published -async function main() { - const bench = new Bench({ time: 100 }); +const bench = new Bench({ time: 100 }); - bench - .add('without tailwind', async () => { - await render(); - }) - .add('with current tailwind', async () => { - await render(); - }); - - await bench.run(); +bench + .add('without tailwind', async () => { + await render(); + }) + .add('with current tailwind', async () => { + await render(); + }); - return bench; -} +await bench.run(); -main() - .then((bench) => { - console.table(bench.table()); - }) - .catch(console.error); +console.table(bench.table()); diff --git a/benchmarks/tailwind-component/tsconfig.json b/benchmarks/tailwind-component/tsconfig.json index 89dac25114..0cb9b5b8d2 100644 --- a/benchmarks/tailwind-component/tsconfig.json +++ b/benchmarks/tailwind-component/tsconfig.json @@ -7,7 +7,8 @@ "target": "esnext", "noUncheckedIndexedAccess": true, "resolveJsonModule": true, - "moduleResolution": "Node", + "moduleResolution": "bundler", + "module": "esnext", "declarationMap": false, "declaration": false, "outDir": "dist"