diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 6dd9ec193..ebd0eb925 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -47,6 +47,9 @@ jobs: - name: Check scripts run: yarn check-scripts + - name: Check bundle sizes + run: yarn lazy check-bundle-size + - name: Check PR template run: yarn update-pr-template --check env: diff --git a/.gitignore b/.gitignore index cf55eb9ab..3d8a8c461 100644 --- a/.gitignore +++ b/.gitignore @@ -100,3 +100,5 @@ apps/docs/api /vercel.json license-report-prod.html license-report.html + +.bundle-meta.json \ No newline at end of file diff --git a/apps/dotcom-worker/package.json b/apps/dotcom-worker/package.json index 726294bad..5f8500ede 100644 --- a/apps/dotcom-worker/package.json +++ b/apps/dotcom-worker/package.json @@ -18,6 +18,7 @@ "test-ci": "lazy inherit", "test": "yarn run -T jest", "test-coverage": "lazy inherit", + "check-bundle-size": "yarn run -T tsx ../../scripts/check-worker-bundle.ts --entry src/lib/worker.ts --size-limit-bytes 350000", "lint": "yarn run -T tsx ../../scripts/lint.ts" }, "dependencies": { diff --git a/apps/health-worker/package.json b/apps/health-worker/package.json index bf7b2aea7..bc731e62c 100644 --- a/apps/health-worker/package.json +++ b/apps/health-worker/package.json @@ -6,6 +6,7 @@ "deploy": "wrangler deploy", "dev": "wrangler dev", "start": "wrangler dev", + "check-bundle-size": "yarn run -T tsx ../../scripts/check-worker-bundle.ts --entry src/index.ts --size-limit-bytes 35000", "lint": "yarn run -T tsx ../../scripts/lint.ts" }, "dependencies": { @@ -15,6 +16,7 @@ "@cloudflare/workers-types": "^4.20240620.0", "@types/node": "~20.11", "discord-api-types": "^0.37.67", + "esbuild": "^0.18.4", "typescript": "^5.3.3", "wrangler": "3.61.0" } diff --git a/scripts/check-worker-bundle.ts b/scripts/check-worker-bundle.ts new file mode 100644 index 000000000..e3a31641c --- /dev/null +++ b/scripts/check-worker-bundle.ts @@ -0,0 +1,63 @@ +import { existsSync, readFileSync, rmSync } from 'fs' +import kleur from 'kleur' +import minimist from 'minimist' +import { resolve } from 'path' +import { exec } from './lib/exec' + +const args = minimist(process.argv.slice(2)) +const sizeLimit = Number(args['size-limit-bytes']) +if (!isFinite(sizeLimit) || sizeLimit < 1) { + console.error( + 'Invalid usage. Usage: yarn tsx check-worker-bundle.ts --size-limit-bytes --entry ' + ) + process.exit(1) +} + +const entry = args['entry'] +if (!existsSync(entry)) { + console.error('Entry file does not exist:', entry) + process.exit(1) +} + +const bundleMetaFileName = '.bundle-meta.json' + +interface Meta { + outputs: { + [fileName: string]: { + bytes: number + } + } +} + +async function checkBundleSize() { + rmSync(bundleMetaFileName, { force: true }) + + await exec('yarn', [ + 'esbuild', + entry, + '--bundle', + '--outfile=/dev/null', + '--minify', + '--external:cloudflare:workers', + '--metafile=' + bundleMetaFileName, + ]) + + console.log(kleur.cyan().bold('Checking bundle size'), 'of', resolve(entry) + '\n') + + const meta = JSON.parse(readFileSync(bundleMetaFileName).toString()) as Meta + const totalSize = Object.values(meta.outputs).reduce((acc, output) => acc + output.bytes, 0) + if (totalSize === 0) { + throw new Error('Invalid bundle meta in ' + process.cwd() + '/' + bundleMetaFileName) + } + + if (totalSize > sizeLimit) { + console.error( + `${kleur.red().bold('ERROR')} Bundle size exceeds limit: ${totalSize} > ${sizeLimit}` + ) + process.exit(1) + } + + console.log(`Bundle size is within limit: ${totalSize} < ${sizeLimit}`) +} + +checkBundleSize() diff --git a/yarn.lock b/yarn.lock index 6603188cb..26f71ae5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13344,6 +13344,7 @@ __metadata: "@tldraw/utils": "workspace:*" "@types/node": "npm:~20.11" discord-api-types: "npm:^0.37.67" + esbuild: "npm:^0.18.4" typescript: "npm:^5.3.3" wrangler: "npm:3.61.0" languageName: unknown