From 1b564052994d6aefbb2c091d7dbff6f1e11cebbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Mon, 21 Aug 2023 11:33:51 +0800 Subject: [PATCH] ci: improved size report (#8992) --- .eslintrc.cjs | 7 +- .github/contributing.md | 2 - .github/workflows/ci.yml | 20 ---- .github/workflows/size-report.yml | 61 +++++++++++ package.json | 12 ++- packages/size-check/README.md | 3 - packages/size-check/brotli.js | 6 -- packages/size-check/package.json | 11 -- packages/size-check/src/index.ts | 6 -- packages/size-check/vite.config.js | 15 --- pnpm-lock.yaml | 162 ++++++++++++++++++++++++----- scripts/aliases.js | 7 +- scripts/build.js | 50 ++++++--- scripts/size-report.ts | 105 +++++++++++++++++++ scripts/usage-size.ts | 99 ++++++++++++++++++ tsconfig.build.json | 1 - 16 files changed, 443 insertions(+), 124 deletions(-) create mode 100644 .github/workflows/size-report.yml delete mode 100644 packages/size-check/README.md delete mode 100644 packages/size-check/brotli.js delete mode 100644 packages/size-check/package.json delete mode 100644 packages/size-check/src/index.ts delete mode 100644 packages/size-check/vite.config.js create mode 100644 scripts/size-report.ts create mode 100644 scripts/usage-size.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index ec05a113113..04ecf049ca9 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -74,12 +74,7 @@ module.exports = { }, // Node scripts { - files: [ - 'scripts/**', - '*.{js,ts}', - 'packages/**/index.js', - 'packages/size-check/**' - ], + files: ['scripts/**', '*.{js,ts}', 'packages/**/index.js'], rules: { 'no-restricted-globals': 'off', 'no-restricted-syntax': 'off' diff --git a/.github/contributing.md b/.github/contributing.md index e728e4cc8eb..0c6771ca0b4 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -248,8 +248,6 @@ This repository employs a [monorepo](https://en.wikipedia.org/wiki/Monorepo) set - `template-explorer`: A development tool for debugging compiler output, continuously deployed at https://template-explorer.vuejs.org/. To run it locally, run [`nr dev-compiler`](#nr-dev-compiler). - - `size-check`: Used for checking built bundle sizes on CI. - ### Importing Packages The packages can import each other directly using their package names. Note that when importing a package, the name listed in its `package.json` should be used. Most of the time the `@vue/` prefix is needed: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 232c69b3b75..8c08c9a935a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,23 +114,3 @@ jobs: - name: Run type declaration tests run: pnpm run test-dts - - size: - runs-on: ubuntu-latest - if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository - env: - CI_JOB_NUMBER: 1 - steps: - - uses: actions/checkout@v3 - - - name: Install pnpm - uses: pnpm/action-setup@v2 - - - name: Set node version to 18 - uses: actions/setup-node@v3 - with: - node-version: 18 - cache: 'pnpm' - - - run: PUPPETEER_SKIP_DOWNLOAD=1 pnpm install - - run: pnpm run size diff --git a/.github/workflows/size-report.yml b/.github/workflows/size-report.yml new file mode 100644 index 00000000000..87c6865927b --- /dev/null +++ b/.github/workflows/size-report.yml @@ -0,0 +1,61 @@ +name: size report + +on: + pull_request: + branches: + - main + +permissions: + contents: read + pull-requests: write + +jobs: + size: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Install pnpm + uses: pnpm/action-setup@v2 + + - name: Set node version to LTS + uses: actions/setup-node@v3 + with: + node-version: lts/* + cache: pnpm + + - run: PUPPETEER_SKIP_DOWNLOAD=1 pnpm install + - run: pnpm run size + + - name: Download Previous Size Report + id: download-artifact + uses: dawidd6/action-download-artifact@v2 + with: + branch: main + name: size-report + path: temp/size-prev + if_no_artifact_found: warn + + - name: Upload Size Report + uses: actions/upload-artifact@v3 + with: + name: size-report + path: temp/size + + - name: Compare size + run: pnpm tsx scripts/size-report.ts > size.md + + - name: Read Size Markdown + id: size-markdown + uses: juliangruber/read-file-action@v1 + with: + path: ./size.md + + - name: Create Comment + uses: actions-cool/maintain-one-comment@v3 + with: + body: | + ${{steps.size-markdown.outputs.content}} + + body-include: '' diff --git a/package.json b/package.json index d514ccd9190..b4ee1b00082 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,10 @@ "dev": "node scripts/dev.js", "build": "node scripts/build.js", "build-dts": "tsc -p tsconfig.build.json && rollup -c rollup.dts.config.js", - "size": "run-s size-global size-baseline", - "size-global": "node scripts/build.js vue runtime-dom -f global -p", - "size-baseline": "node scripts/build.js vue -f esm-bundler-runtime && node scripts/build.js runtime-dom runtime-core reactivity shared -f esm-bundler && cd packages/size-check && vite build && node brotli", + "size": "run-s \"size-*\" && tsx scripts/usage-size.ts", + "size-global": "node scripts/build.js vue runtime-dom -f global -p --size", + "size-esm-runtime": "node scripts/build.js vue -f esm-bundler-runtime", + "size-esm": "node scripts/build.js runtime-dom runtime-core reactivity shared -f esm-bundler", "check": "tsc --incremental --noEmit", "lint": "eslint --cache --ext .ts packages/*/{src,__tests__}/**.ts", "format": "prettier --write --cache \"**/*.[tj]s?(x)\"", @@ -81,10 +82,12 @@ "lint-staged": "^10.2.10", "lodash": "^4.17.15", "magic-string": "^0.30.0", + "markdown-table": "^3.0.3", "marked": "^4.0.10", "minimist": "^1.2.0", "npm-run-all": "^4.1.5", "prettier": "^3.0.1", + "pretty-bytes": "^6.1.1", "pug": "^3.0.1", "puppeteer": "~19.6.0", "rollup": "^3.26.0", @@ -94,9 +97,10 @@ "semver": "^7.3.2", "serve": "^12.0.0", "simple-git-hooks": "^2.8.1", - "terser": "^5.15.1", + "terser": "^5.19.2", "todomvc-app-css": "^2.3.0", "tslib": "^2.5.0", + "tsx": "^3.12.7", "typescript": "^5.1.6", "vite": "^4.3.0", "vitest": "^0.30.1" diff --git a/packages/size-check/README.md b/packages/size-check/README.md deleted file mode 100644 index 23cf1899eaf..00000000000 --- a/packages/size-check/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Size Check - -This package is private and is used for checking the baseline runtime size after tree-shaking (with only the bare minimal code required to render something to the screen). diff --git a/packages/size-check/brotli.js b/packages/size-check/brotli.js deleted file mode 100644 index f9dedac0b1c..00000000000 --- a/packages/size-check/brotli.js +++ /dev/null @@ -1,6 +0,0 @@ -const { brotliCompressSync } = require('zlib') - -const file = require('fs').readFileSync('dist/index.js') -const compressed = brotliCompressSync(file) -const compressedSize = (compressed.length / 1024).toFixed(2) + 'kb' -console.log(`brotli: ${compressedSize}`) diff --git a/packages/size-check/package.json b/packages/size-check/package.json deleted file mode 100644 index 1f9fba88594..00000000000 --- a/packages/size-check/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@vue/size-check", - "version": "3.3.4", - "private": true, - "scripts": { - "build": "vite build" - }, - "dependencies": { - "vue": "workspace:*" - } -} diff --git a/packages/size-check/src/index.ts b/packages/size-check/src/index.ts deleted file mode 100644 index ad3b68a5cc1..00000000000 --- a/packages/size-check/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { h, createApp } from 'vue' - -// The bare minimum code required for rendering something to the screen -createApp({ - render: () => h('div', 'hello world!') -}).mount('#app') diff --git a/packages/size-check/vite.config.js b/packages/size-check/vite.config.js deleted file mode 100644 index 73721f95910..00000000000 --- a/packages/size-check/vite.config.js +++ /dev/null @@ -1,15 +0,0 @@ -export default { - define: { - __VUE_PROD_DEVTOOLS__: false, - __VUE_OPTIONS_API__: true - }, - build: { - rollupOptions: { - input: ['src/index.ts'], - output: { - entryFileNames: `[name].js` - } - }, - minify: 'terser' - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 378cc5749d4..7c6e2a198c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -86,6 +86,9 @@ importers: magic-string: specifier: ^0.30.0 version: 0.30.0 + markdown-table: + specifier: ^3.0.3 + version: 3.0.3 marked: specifier: ^4.0.10 version: 4.3.0 @@ -98,6 +101,9 @@ importers: prettier: specifier: ^3.0.1 version: 3.0.1 + pretty-bytes: + specifier: ^6.1.1 + version: 6.1.1 pug: specifier: ^3.0.1 version: 3.0.2 @@ -126,23 +132,26 @@ importers: specifier: ^2.8.1 version: 2.8.1 terser: - specifier: ^5.15.1 - version: 5.18.2 + specifier: ^5.19.2 + version: 5.19.2 todomvc-app-css: specifier: ^2.3.0 version: 2.4.2 tslib: specifier: ^2.5.0 version: 2.6.0 + tsx: + specifier: ^3.12.7 + version: 3.12.7 typescript: specifier: ^5.1.6 version: 5.1.6 vite: specifier: ^4.3.0 - version: 4.3.1(@types/node@16.18.38)(terser@5.18.2) + version: 4.3.1(@types/node@16.18.38)(terser@5.19.2) vitest: specifier: ^0.30.1 - version: 0.30.1(jsdom@21.1.0)(terser@5.18.2) + version: 0.30.1(jsdom@21.1.0)(terser@5.19.2) packages/compiler-core: dependencies: @@ -354,12 +363,6 @@ importers: packages/shared: {} - packages/size-check: - dependencies: - vue: - specifier: workspace:* - version: link:../vue - packages/template-explorer: dependencies: monaco-editor: @@ -422,11 +425,12 @@ packages: '@babel/highlight': 7.22.5 dev: true - /@babel/code-frame@7.22.5: - resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==} + /@babel/code-frame@7.22.10: + resolution: {integrity: sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.22.5 + '@babel/highlight': 7.22.10 + chalk: 2.4.2 dev: true /@babel/compat-data@7.21.0: @@ -567,6 +571,15 @@ packages: - supports-color dev: true + /@babel/highlight@7.22.10: + resolution: {integrity: sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.5 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + /@babel/highlight@7.22.5: resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==} engines: {node: '>=6.9.0'} @@ -587,7 +600,7 @@ packages: resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.22.10 '@babel/parser': 7.21.3 '@babel/types': 7.21.3 dev: true @@ -596,7 +609,7 @@ packages: resolution: {integrity: sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.22.5 + '@babel/code-frame': 7.22.10 '@babel/generator': 7.21.3 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.21.0 @@ -618,6 +631,27 @@ packages: '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 + /@esbuild-kit/cjs-loader@2.4.2: + resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==} + dependencies: + '@esbuild-kit/core-utils': 3.1.0 + get-tsconfig: 4.7.0 + dev: true + + /@esbuild-kit/core-utils@3.1.0: + resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} + dependencies: + esbuild: 0.17.19 + source-map-support: 0.5.21 + dev: true + + /@esbuild-kit/esm-loader@2.5.5: + resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} + dependencies: + '@esbuild-kit/core-utils': 3.1.0 + get-tsconfig: 4.7.0 + dev: true + /@esbuild/android-arm64@0.17.19: resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} engines: {node: '>=12'} @@ -1078,11 +1112,25 @@ packages: '@jridgewell/trace-mapping': 0.3.17 dev: true + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.19 + dev: true + /@jridgewell/resolve-uri@3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} dev: true + /@jridgewell/resolve-uri@3.1.1: + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + dev: true + /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} @@ -1091,13 +1139,17 @@ packages: /@jridgewell/source-map@0.3.5: resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} dependencies: - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.17 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.19 dev: true /@jridgewell/sourcemap-codec@1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + /@jridgewell/trace-mapping@0.3.17: resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} dependencies: @@ -1105,6 +1157,13 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true + /@jridgewell/trace-mapping@0.3.19: + resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + /@jspm/core@2.0.1: resolution: {integrity: sha512-Lg3PnLp0QXpxwLIAuuJboLeRaIhrgJjeuh797QADg3xz8wGLugQOS5DpsE8A6i6Adgzf+bacllkKZG3J0tGfDw==} dev: true @@ -1233,7 +1292,7 @@ packages: rollup: 3.26.2 serialize-javascript: 6.0.1 smob: 0.0.6 - terser: 5.18.2 + terser: 5.19.2 dev: true /@rollup/pluginutils@5.0.2(rollup@3.26.2): @@ -1464,7 +1523,7 @@ packages: istanbul-lib-source-maps: 4.0.1 istanbul-reports: 3.1.5 test-exclude: 6.0.0 - vitest: 0.30.1(jsdom@21.1.0)(terser@5.18.2) + vitest: 0.30.1(jsdom@21.1.0)(terser@5.19.2) transitivePeerDependencies: - supports-color dev: true @@ -1568,6 +1627,12 @@ packages: hasBin: true dev: true + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /acorn@8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} @@ -3066,6 +3131,12 @@ packages: get-intrinsic: 1.2.0 dev: true + /get-tsconfig@4.7.0: + resolution: {integrity: sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + /git-raw-commits@2.0.11: resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==} engines: {node: '>=10'} @@ -3991,6 +4062,10 @@ packages: engines: {node: '>=8'} dev: true + /markdown-table@3.0.3: + resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + dev: true + /marked@4.3.0: resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} engines: {node: '>= 12'} @@ -4414,7 +4489,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.22.5 + '@babel/code-frame': 7.22.10 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -4627,6 +4702,11 @@ packages: hasBin: true dev: true + /pretty-bytes@6.1.1: + resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} + engines: {node: ^14.13.1 || >=16.0.0} + dev: true + /pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -4963,6 +5043,10 @@ packages: engines: {node: '>=4'} dev: true + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + /resolve@1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true @@ -5007,7 +5091,7 @@ packages: rollup: 3.26.2 typescript: 5.1.6 optionalDependencies: - '@babel/code-frame': 7.22.5 + '@babel/code-frame': 7.22.10 dev: true /rollup-plugin-esbuild@5.0.0(esbuild@0.17.19)(rollup@3.26.2): @@ -5492,6 +5576,17 @@ packages: source-map-support: 0.5.21 dev: true + /terser@5.19.2: + resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.5 + acorn: 8.10.0 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -5609,6 +5704,17 @@ packages: typescript: 5.1.6 dev: true + /tsx@3.12.7: + resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==} + hasBin: true + dependencies: + '@esbuild-kit/cjs-loader': 2.4.2 + '@esbuild-kit/core-utils': 3.1.0 + '@esbuild-kit/esm-loader': 2.5.5 + optionalDependencies: + fsevents: 2.3.2 + dev: true + /type-check@0.3.2: resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} engines: {node: '>= 0.8.0'} @@ -5758,7 +5864,7 @@ packages: engines: {node: '>= 0.8'} dev: true - /vite-node@0.30.1(@types/node@16.18.38)(terser@5.18.2): + /vite-node@0.30.1(@types/node@16.18.38)(terser@5.19.2): resolution: {integrity: sha512-vTikpU/J7e6LU/8iM3dzBo8ZhEiKZEKRznEMm+mJh95XhWaPrJQraT/QsT2NWmuEf+zgAoMe64PKT7hfZ1Njmg==} engines: {node: '>=v14.18.0'} hasBin: true @@ -5768,7 +5874,7 @@ packages: mlly: 1.2.0 pathe: 1.1.0 picocolors: 1.0.0 - vite: 4.3.1(@types/node@16.18.38)(terser@5.18.2) + vite: 4.3.1(@types/node@16.18.38)(terser@5.19.2) transitivePeerDependencies: - '@types/node' - less @@ -5779,7 +5885,7 @@ packages: - terser dev: true - /vite@4.3.1(@types/node@16.18.38)(terser@5.18.2): + /vite@4.3.1(@types/node@16.18.38)(terser@5.19.2): resolution: {integrity: sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -5808,7 +5914,7 @@ packages: esbuild: 0.17.19 postcss: 8.4.21 rollup: 3.26.2 - terser: 5.18.2 + terser: 5.19.2 optionalDependencies: fsevents: 2.3.2 dev: true @@ -5850,7 +5956,7 @@ packages: fsevents: 2.3.2 dev: true - /vitest@0.30.1(jsdom@21.1.0)(terser@5.18.2): + /vitest@0.30.1(jsdom@21.1.0)(terser@5.19.2): resolution: {integrity: sha512-y35WTrSTlTxfMLttgQk4rHcaDkbHQwDP++SNwPb+7H8yb13Q3cu2EixrtHzF27iZ8v0XCciSsLg00RkPAzB/aA==} engines: {node: '>=v14.18.0'} hasBin: true @@ -5905,8 +6011,8 @@ packages: strip-literal: 1.0.1 tinybench: 2.4.0 tinypool: 0.4.0 - vite: 4.3.1(@types/node@16.18.38)(terser@5.18.2) - vite-node: 0.30.1(@types/node@16.18.38)(terser@5.18.2) + vite: 4.3.1(@types/node@16.18.38)(terser@5.19.2) + vite-node: 0.30.1(@types/node@16.18.38)(terser@5.19.2) why-is-node-running: 2.2.2 transitivePeerDependencies: - less diff --git a/scripts/aliases.js b/scripts/aliases.js index 95e3016322c..34a7c643557 100644 --- a/scripts/aliases.js +++ b/scripts/aliases.js @@ -19,12 +19,7 @@ const entries = { '@vue/compat': resolveEntryForPkg('vue-compat') } -const nonSrcPackages = [ - 'sfc-playground', - 'size-check', - 'template-explorer', - 'dts-test' -] +const nonSrcPackages = ['sfc-playground', 'template-explorer', 'dts-test'] for (const dir of dirs) { const key = `@vue/${dir}` diff --git a/scripts/build.js b/scripts/build.js index 75a619046be..1f8af65017d 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -27,6 +27,7 @@ import { cpus } from 'node:os' import { createRequire } from 'node:module' import { targets as allTargets, fuzzyMatchTarget } from './utils.js' import { scanEnums } from './const-enum.js' +import prettyBytes from 'pretty-bytes' const require = createRequire(import.meta.url) const args = minimist(process.argv.slice(2)) @@ -38,18 +39,22 @@ const buildTypes = args.withTypes || args.t const sourceMap = args.sourcemap || args.s const isRelease = args.release const buildAllMatching = args.all || args.a +const writeSize = args.size const commit = execa.sync('git', ['rev-parse', 'HEAD']).stdout.slice(0, 7) +const sizeDir = path.resolve('temp/size') + run() async function run() { + if (writeSize) await fs.mkdir(sizeDir, { recursive: true }) const removeCache = scanEnums() try { const resolvedTargets = targets.length ? fuzzyMatchTarget(targets, buildAllMatching) : allTargets await buildAll(resolvedTargets) - checkAllSizes(resolvedTargets) + await checkAllSizes(resolvedTargets) if (buildTypes) { await execa( 'pnpm', @@ -129,39 +134,52 @@ async function build(target) { ) } -function checkAllSizes(targets) { +async function checkAllSizes(targets) { if (devOnly || (formats && !formats.includes('global'))) { return } console.log() for (const target of targets) { - checkSize(target) + await checkSize(target) } console.log() } -function checkSize(target) { +async function checkSize(target) { const pkgDir = path.resolve(`packages/${target}`) - checkFileSize(`${pkgDir}/dist/${target}.global.prod.js`) + await checkFileSize(`${pkgDir}/dist/${target}.global.prod.js`) if (!formats || formats.includes('global-runtime')) { - checkFileSize(`${pkgDir}/dist/${target}.runtime.global.prod.js`) + await checkFileSize(`${pkgDir}/dist/${target}.runtime.global.prod.js`) } } -function checkFileSize(filePath) { +async function checkFileSize(filePath) { if (!existsSync(filePath)) { return } - const file = readFileSync(filePath) - const minSize = (file.length / 1024).toFixed(2) + 'kb' + const file = await fs.readFile(filePath) + const fileName = path.basename(filePath) + const gzipped = gzipSync(file) - const gzippedSize = (gzipped.length / 1024).toFixed(2) + 'kb' - const compressed = brotliCompressSync(file) - // @ts-ignore - const compressedSize = (compressed.length / 1024).toFixed(2) + 'kb' + const brotli = brotliCompressSync(file) + console.log( - `${chalk.gray( - chalk.bold(path.basename(filePath)) - )} min:${minSize} / gzip:${gzippedSize} / brotli:${compressedSize}` + `${chalk.gray(chalk.bold(fileName))} min:${prettyBytes( + file.length + )} / gzip:${prettyBytes(gzipped.length)} / brotli:${prettyBytes( + brotli.length + )}` ) + + if (writeSize) + await fs.writeFile( + path.resolve(sizeDir, `${fileName}.json`), + JSON.stringify({ + file: fileName, + size: file.length, + gzip: gzipped.length, + brotli: brotli.length + }), + 'utf-8' + ) } diff --git a/scripts/size-report.ts b/scripts/size-report.ts new file mode 100644 index 00000000000..56e4491a19c --- /dev/null +++ b/scripts/size-report.ts @@ -0,0 +1,105 @@ +import path from 'node:path' +import { markdownTable } from 'markdown-table' +import prettyBytes from 'pretty-bytes' +import { readdir } from 'node:fs/promises' +import { existsSync } from 'node:fs' + +interface SizeResult { + size: number + gzip: number + brotli: number +} + +interface BundleResult extends SizeResult { + file: string +} + +type UsageResult = Record + +const currDir = path.resolve('temp/size') +const prevDir = path.resolve('temp/size-prev') +let output = '## Size Report\n\n' +const sizeHeaders = ['Size', 'Gzip', 'Brotli'] + +run() + +async function run() { + await renderFiles() + await renderUsages() + + process.stdout.write(output) +} + +async function renderFiles() { + const filterFiles = (files: string[]) => + files.filter(file => !file.startsWith('_')) + + const curr = filterFiles(await readdir(currDir)) + const prev = existsSync(prevDir) ? filterFiles(await readdir(prevDir)) : [] + const fileList = new Set([...curr, ...prev]) + + const rows: string[][] = [] + for (const file of fileList) { + const currPath = path.resolve(currDir, file) + const prevPath = path.resolve(prevDir, file) + + const curr = await importJSON(currPath) + const prev = await importJSON(prevPath) + const fileName = curr?.file || prev?.file || '' + + if (!curr) { + rows.push([`~~${fileName}~~`]) + } else + rows.push([ + fileName, + `${prettyBytes(curr.size)}${getDiff(curr.size, prev?.size)}`, + `${prettyBytes(curr.gzip)}${getDiff(curr.gzip, prev?.gzip)}`, + `${prettyBytes(curr.brotli)}${getDiff(curr.brotli, prev?.brotli)}` + ]) + } + + output += '### Bundles\n\n' + output += markdownTable([['File', ...sizeHeaders], ...rows]) + output += '\n\n' +} + +async function renderUsages() { + const curr = (await importJSON( + path.resolve(currDir, '_usages.json') + ))! + const prev = await importJSON( + path.resolve(prevDir, '_usages.json') + ) + output += '\n### Usages\n\n' + + const data = Object.values(curr) + .map(usage => { + const prevUsage = prev?.[usage.name] + const diffSize = getDiff(usage.size, prevUsage?.size) + const diffGzipped = getDiff(usage.gzip, prevUsage?.gzip) + const diffBrotli = getDiff(usage.brotli, prevUsage?.brotli) + + return [ + usage.name, + `${prettyBytes(usage.size)}${diffSize}`, + `${prettyBytes(usage.gzip)}${diffGzipped}`, + `${prettyBytes(usage.brotli)}${diffBrotli}` + ] + }) + .filter((usage): usage is string[] => !!usage) + + output += `${markdownTable([['Name', ...sizeHeaders], ...data])}\n\n` +} + +async function importJSON(path: string): Promise { + if (!existsSync(path)) return undefined + return (await import(path, { assert: { type: 'json' } })).default +} + +function getDiff(curr: number, prev?: number) { + if (prev === undefined) return '' + const diff = curr - prev + if (diff === 0) return '' + const sign = diff > 0 ? '+' : '' + return ` (**${sign}${prettyBytes(diff)}**)` +} diff --git a/scripts/usage-size.ts b/scripts/usage-size.ts new file mode 100644 index 00000000000..1a1013b7847 --- /dev/null +++ b/scripts/usage-size.ts @@ -0,0 +1,99 @@ +import { mkdir, writeFile } from 'fs/promises' +import path from 'node:path' +import { rollup } from 'rollup' +import nodeResolve from '@rollup/plugin-node-resolve' +import { minify } from 'terser' +import replace from '@rollup/plugin-replace' +import { brotliCompressSync, gzipSync } from 'node:zlib' + +const sizeDir = path.resolve('temp/size') +const entry = path.resolve('./packages/vue/dist/vue.runtime.esm-bundler.js') + +interface Preset { + name: string + imports: string[] +} + +const presets: Preset[] = [ + { name: 'createApp', imports: ['createApp'] }, + { name: 'createSSRApp', imports: ['createSSRApp'] }, + { name: 'defineCustomElement', imports: ['defineCustomElement'] }, + { + name: 'overall', + imports: [ + 'createApp', + 'ref', + 'watch', + 'Transition', + 'KeepAlive', + 'Suspense' + ] + } +] + +main() + +async function main() { + const tasks: ReturnType[] = [] + for (const preset of presets) { + tasks.push(generateBundle(preset)) + } + + const results = Object.fromEntries( + (await Promise.all(tasks)).map(r => [r.name, r]) + ) + + await mkdir(sizeDir, { recursive: true }) + await writeFile( + path.resolve(sizeDir, '_usages.json'), + JSON.stringify(results), + 'utf-8' + ) +} + +async function generateBundle(preset: Preset) { + const id = 'virtual:entry' + const content = `export { ${preset.imports.join(', ')} } from '${entry}'` + const result = await rollup({ + input: id, + plugins: [ + { + name: 'usage-size-plugin', + resolveId(_id) { + if (_id === id) return id + return null + }, + load(_id) { + if (_id === id) return content + } + }, + nodeResolve(), + replace({ + 'process.env.NODE_ENV': '"production"', + __VUE_PROD_DEVTOOLS__: 'false', + __VUE_OPTIONS_API__: 'true', + preventAssignment: true + }) + ] + }) + + const generated = await result.generate({}) + const bundled = generated.output[0].code + const minified = ( + await minify(bundled, { + module: true, + toplevel: true + }) + ).code! + + const size = minified.length + const gzip = gzipSync(minified).length + const brotli = brotliCompressSync(minified).length + + return { + name: preset.name, + size, + gzip, + brotli + } +} diff --git a/tsconfig.build.json b/tsconfig.build.json index 8b7749b858b..89aaa2278f4 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -9,7 +9,6 @@ "packages/runtime-test", "packages/template-explorer", "packages/sfc-playground", - "packages/size-check", "packages/dts-test" ] }