Enforcing a JavaScript budget in CI

Performance budgets only help if they're actually enforced. Wiring bundlesize into Travis CI gives you automated size checks on every pull request with almost no configuration. Travis runs the checks in the cloud whenever code is pushed to GitHub, and you can make passing status checks mandatory before a PR can be merged.

Bundlesize reports a size comparison against the main branch and flags unexpectedly large jumps. For a practical walkthrough, consider a small webpack-bundled app that lets users vote for their favorite kitty.

Cat voting app

Defining the budget

The sample app already includes bundlesize. To work with the code, click Remix to Edit on the Glitch project. The main bundle lives in the public folder. Add a bundlesize section to package.json to test its size:

"bundlesize": [
  {
    "path": "./public/*.bundle.js",
    "maxSize": "170 kB"
  }
]

Set the compressed JavaScript budget in the maxSize field. For this project, the recommended limit is 170KB. The public/*.js path uses a glob wildcard so any bundle name in that folder is matched.

Travis needs a test command to run, so add a test script to package.json:

"scripts": {
  "start": "webpack && http-server -c-1",
  "test": "bundlesize"
}

Connecting Travis and GitHub

  1. Create a new GitHub repository for the project, initialized with a README.md.
  2. Register with Travis and activate the GitHub Apps integration from your profile Settings.
  3. Under Settings, click Sync account and confirm your new repo appears in your Travis account.

GitHub Apps integration on Travis CI

Travis CI Sync button

Authorizing bundlesize for PR comments

Bundlesize needs permission to post status updates on pull requests. This link issues the bundlesize token, which gets stored in the Travis configuration.

bundlesize token

In the Travis dashboard for your project, go to More options > Settings > Environment variables.

Adding environment variables on Travis CI

Add the token as an environment variable named BUNDLESIZE_GITHUB_TOKEN, with the token value in the value field.

The final piece is a .travis.yml file, which directs Travis to run the project as a NodeJS app. The Glitch project already includes one, and with that in place bundlesize will flag any JavaScript that exceeds the budget going forward.

Running the first check

Push the app code to GitHub to see how it measures up.

  1. In Glitch, select Tools > Git, Import, and Export > Export to GitHub.
  2. Enter your username and repo as username/repo. Glitch exports the app to a branch named "glitch".
  3. Open the repository homepage and create a new pull request with the New pull request button.

Status checks appear on the PR page while Travis runs.

GitHub checks in progress

The first run is a reality check: the cat voting app misses the budget. The main bundle weighs 266 KB against the 170 KB limit.

Failed bundlesize check

Cutting the excess

The fix is removing unused code. The imports in src/index.js are the problem:

import firebase from "firebase";
import * as moment from 'moment';

The app only uses Firebase Realtime Database for storage, but importing the full firebase package pulls in auth, storage, messaging and more. Limit the import to what the app actually needs in src/index.js:

import firebase from "firebase";
import firebase from 'firebase/app';
import 'firebase/database';

With the source changed, rebuild the bundle with webpack:

  1. Click the Tools button, then Console to open a terminal in a new tab.
  2. Type webpack and let the build finish.
  3. Export the code again from Tools > Git, Import, and Export > Export to GitHub.
  4. Return to the pull request page and wait for the checks to complete.

Passed bundlesize check

The bundle drops to 125.5 KB and all checks pass. The moment library can't be trimmed the same way as Firebase, but a Remove unused code codelab shows further optimization options for this app. With Travis and bundlesize in place, the budget is now monitored on every future change.