From a7c6ce499d7a9e933e70d6b8e9829acade23a2ae Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 7 Mar 2023 09:27:20 -0800 Subject: [PATCH] test: enforce package size (#4098) * build: use fewer babel versions * build: dedup * test: test deps dedups * fix: test.yml * fix: typo * test: failing * fix: dedup * fix: dedup * test: comment dedup tests * chore: whitespace * test: package size * build: scripts * test: update test-size * docs: CONTRIBUTING --- .github/workflows/test.yml | 25 ++++++-- CONTRIBUTING.md | 8 +++ package.json | 5 +- fetch-schema.js => scripts/fetch-schema.js | 4 +- .../prei18n-extract.js | 0 scripts/test-size.js | 58 +++++++++++++++++++ 6 files changed, 92 insertions(+), 8 deletions(-) rename fetch-schema.js => scripts/fetch-schema.js (85%) rename prei18n-extract.js => scripts/prei18n-extract.js (100%) create mode 100644 scripts/test-size.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 361c5848f0..85d576e81b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,13 +36,12 @@ jobs: fail_ci_if_error: false verbose: true - cypress-build: + build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ./.github/actions/setup - run: yarn prepare - - run: yarn build - uses: actions/upload-artifact@v2 with: @@ -50,6 +49,24 @@ jobs: path: build if-no-files-found: error + size-tests: + needs: [build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/setup + - uses: actions/download-artifact@v2 + with: + name: build + path: build + - run: yarn test:size + + + cypress-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/setup - uses: actions/cache@v3 id: cypress-cache with: @@ -59,7 +76,7 @@ jobs: run: yarn cypress install cypress-test-matrix: - needs: cypress-build + needs: [build, cypress-build] runs-on: ubuntu-latest strategy: fail-fast: false @@ -96,7 +113,7 @@ jobs: # Included as a single job to check against for cypress test success, as cypress runs in a matrix. cypress-tests: - needs: cypress-test-matrix + needs: [cypress-test-matrix] runs-on: ubuntu-latest steps: - run: echo 'Finished cypress tests https\://dashboard.cypress.io/projects/yp82ef' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a1455bc422..0d2b3d95c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,6 +64,14 @@ To run _all_ cypress integration tests _from the command line_: yarn cypress:run ``` +## Adding a new dependency + +Adding many new dependencies would cause bloat, so we have a test to guard against this: `scripts/test-size.js`. This will run as part of CI with every PR. + +If you *need* to add a new dependency, and it causes the generated build to exceed its size quota, you'll need to increase the quota. Do so in `scripts/test-size.js`. + +You can also run the test on your last build using `yarn build && yarn test:size`. If you exceed the size quota, it will let you know what to do :). + ## Engineering standards Code merged into the `main` branch of this repository should adhere to high standards of correctness and maintainability. diff --git a/package.json b/package.json index 1812488b7b..51e6014314 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,11 @@ "contracts:compile:abi": "typechain --target ethers-v5 --out-dir src/abis/types \"./src/abis/**/*.json\"", "contracts:compile:v3": "typechain --target ethers-v5 --out-dir src/types/v3 \"./node_modules/@uniswap/**/artifacts/contracts/**/*[!dbg].json\"", "contracts:compile": "yarn contracts:compile:abi && yarn contracts:compile:v3", - "graphql:fetch": "node fetch-schema.js", + "graphql:fetch": "node scripts/fetch-schema.js", "graphql:generate:data": "graphql-codegen --config apollo-codegen.ts", "graphql:generate:thegraph": "graphql-codegen --config apollo-codegen_thegraph.ts", "graphql:generate": "yarn graphql:generate:data && yarn graphql:generate:thegraph", - "prei18n:extract": "node prei18n-extract.js", + "prei18n:extract": "node scripts/prei18n-extract.js", "i18n:extract": "lingui extract --locale en-US", "i18n:compile": "yarn i18n:extract && lingui compile", "i18n:pseudo": "lingui extract --locale pseudo && lingui compile", @@ -23,6 +23,7 @@ "deduplicate": "yarn-deduplicate --strategy=highest", "lint": "yarn eslint .", "test": "craco test --coverage", + "test:size": "node scripts/test-size.js", "cypress:open": "cypress open --browser chrome --e2e", "cypress:run": "cypress run --browser chrome --e2e", "postinstall": "patch-package" diff --git a/fetch-schema.js b/scripts/fetch-schema.js similarity index 85% rename from fetch-schema.js rename to scripts/fetch-schema.js index 229ea8428d..987f5ff7c9 100644 --- a/fetch-schema.js +++ b/scripts/fetch-schema.js @@ -3,8 +3,8 @@ require('dotenv').config({ path: '.env.production' }) const { exec } = require('child_process') -const dataConfig = require('./graphql.config') -const thegraphConfig = require('./graphql_thegraph.config') +const dataConfig = require('../graphql.config') +const thegraphConfig = require('../graphql_thegraph.config') function fetchSchema(url, outputFile) { exec( diff --git a/prei18n-extract.js b/scripts/prei18n-extract.js similarity index 100% rename from prei18n-extract.js rename to scripts/prei18n-extract.js diff --git a/scripts/test-size.js b/scripts/test-size.js new file mode 100644 index 0000000000..f2f09e2f14 --- /dev/null +++ b/scripts/test-size.js @@ -0,0 +1,58 @@ +/* eslint-disable no-undef */ +const assert = require('assert') +const chalk = require('chalk') +const fs = require('fs') +const gzipSize = require('gzip-size').sync +const path = require('path') + +const buildDir = path.join(__dirname, '../build') + +let entrypoints +try { + entrypoints = require(path.join(buildDir, 'asset-manifest.json')).entrypoints +} catch (e) { + console.log(chalk.yellow('You must build first: `yarn build`')) + process.exit(1) +} + +// The last recorded size for these assets, as reported by `yarn build`. +const MAX_SIZE_MAIN_KB = 361.36 + +// This is the async-loaded js, called ..js, with a matching css file. +const MAX_SIZE_ENTRY_MB = 1.38 + +const SIZE_TOLERANCE_KB = 5 + +const jsEntrypoints = entrypoints.filter((entrypoint) => entrypoint.endsWith('js')) +assert(jsEntrypoints.length === 3) + +let fail = false +console.log('File sizes after gzip:\n') +jsEntrypoints.forEach((entrypoint) => { + const name = entrypoint.match(/\/([\w\d-]*)\./)[1] + const size = gzipSize(fs.readFileSync(path.join(buildDir, entrypoint))) + + let maxSize = MAX_SIZE_ENTRY_MB * 1024 * 1024 + if (name === 'runtime-main') { + return + } else if (name === 'main') { + maxSize = MAX_SIZE_MAIN_KB * 1024 + } + maxSize += SIZE_TOLERANCE_KB * 1024 + + if (maxSize > size) { + console.log(chalk.green(`\t${toKb(maxSize)}\t${entrypoint}`)) + } else { + console.log(chalk.red(`\t${toKb(maxSize)}\t${entrypoint}`), '\tdid you import an unnecessary dependency?') + fail = true + } +}) +if (fail) { + console.log(chalk.yellow('\nOne or more of your files has grown too large.')) + console.log(chalk.yellow('Reduce the file size or update the size limit (in scripts/test-size.js)')) + process.exit(1) +} + +function toKb(bytes) { + return ((bytes / 1024).toFixed(2) + ' kB').padEnd(8) +}