Guide 03 · Developer docs

The theme repo and the asset pipeline

Everything a developer changes on a Core dna site lives in its theme repository. This guide covers the repository and its build, printing records in templates, stylesheets and client-side code, and the parts of a site around the main content.

L1–L2
Unit 04 · Client-side code

Bundle budgets

A budget is a size limit per page type that fails the build when a change exceeds it. Real first-party weights measured on production sites for landing pages, content pages and a checkout, targets for a new build, and the webpack setting that turns a budget from a warning into an error.

Who this is for. The developer or lead who wants a site to stay fast after launch. Afterwards you can set a budget per page type from real numbers, and make the build refuse a change that breaks it, instead of finding out from a slow page months later.

What production sites weigh

First-party JavaScript and CSS loaded by a typical page of each type, measured gzipped (gzip -9) on the committed production files:

Site and page typeJavaScriptCSS
Twig, no jQuery: home page40 KB30 KB
New build, no jQuery: any pageunder 10 KB, plus shared chunks21 KB
Split bundles, jQuery as one global: content page64 KB (33 KB of bundles, 31 KB of jQuery)28 KB
The same site: checkout156 KB40 KB
One bundle each, jQuery bundled twice: any page136 to 139 KB on two sites, 310 KB on a third29 to 146 KB

The difference between the rows is not the features: it is whether heavy code is split by page type (Bundle boundaries), loaded on demand (Dynamic imports), and whether jQuery is shipped once or twice (jQuery, loaded once).

Targets for a new build

Page typeJavaScript, gzippedCSS, gzipped
Landing pageunder 60 KBunder 40 KB
Content pageunder 100 KBunder 50 KB
Checkoutunder 200 KB, provider SDKs loaded on the payment stepunder 60 KB

These are this guide's recommendation, set where the leaner production sites already are. Third-party scripts (analytics, chat, the payment provider's own SDK) are not in them: budget those separately, because they arrive from other hosts whatever your build does.

Make the build enforce it

webpack checks sizes itself. With hints: 'error' in the production config, an entry or file over its limit fails the build:

JavaScript webpack.config.js (from a production repository)
performance: {
  hints: isProd ? 'error' : 'warning',
  maxEntrypointSize: 150 * 1024,   // all files of one entry, JavaScript and CSS
  maxAssetSize: 100 * 1024,        // any single file
  // on-demand chunks are loaded only when needed: keep them out of the budget
  assetFilter: (file) => !/(?:receipt-pdf|stripe-pay|mock-pay)\.bundle\.js$/.test(file)
}

Three details decide whether it works:

  • webpack measures the files it writes, minified but not compressed, in bytes. Minified JavaScript usually gzips to about a third of its size, so 150 KiB per entry is roughly 45 to 50 KB gzipped.
  • An entry's size includes its CSS when the stylesheet is part of the entry.
  • Without hints: 'error' the limit is advice. One production repository sets maxEntrypointSize: 300000 and no hints; its home page entry is about 124 KB of JavaScript and 200 KB of CSS, over the limit on every build, and the warning scrolls past unread.

A gulp build has no such setting. Check the output instead, in the build or in CI, and fail when a file grows past its limit:

Shell bin/check-budgets.sh
#!/usr/bin/env bash
# fail when a built file is over its gzipped budget, in bytes
set -e
check() {
  size=$(gzip -9 -c "$1" | wc -c)
  if [ "$size" -gt "$2" ]; then echo "$1 is $size bytes gzipped, budget $2"; exit 1; fi
}
check static/js/components.bundle.js 30000
check static/js/checkout.bundle.js 100000
check static/css/styles.css 32000

Set each limit a little above today's size, so the check passes now and fails on the first regression. Raise a limit only on purpose, in a commit that says why.

Go deeper

Was this page helpful?

Your answer goes to the docs team.