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 01 · Anatomy of a theme repo

Webpack and gulp builds

Theme repositories build with webpack, or with gulp running webpack inside it. How to tell which one you have from its files, the commands each uses, why a watch task cannot be trusted until you have run it, and how to read package.json before anything else.

Who this is for. A developer about to run a theme's build for the first time, or the first time in a while. Afterwards you can identify the build in any repository, run the right command for development and for a commit, and know what a watch task will and will not do before you rely on it.

The two conventions

Nearly every theme repository compiles its SCSS and JavaScript in one of two ways, and you will meet both. Neither is the house standard; follow the one the repository already uses.

WebpackGulp
Recognise it bywebpack.common.js, webpack.dev.js, webpack.prod.js (and sometimes webpack.watch.js), in .build/ or at the root; webpack-cli in package.jsonconfig/gulp.js, usually with config/webpack.js, settings.js and utils.js beside it; gulp, gulp-dart-sass and gulp-sass-glob in package.json
SCSSAn entry in the webpack config, through sass-loader and mini-css-extract-pluginGulp compiles each SCSS entry listed in gulp.js
JavaScriptWebpackStill webpack, run from gulp through webpack-stream
Outputdist/static/
Production buildnpm run prod, often also npm run buildnpm run build or npm run prod
Development buildnpm run devnpm run dev

The gulp builds also assemble the SVG sprite and optimise images; the webpack builds copy images with copy-webpack-plugin.

Read package.json first

The scripts block is the only reliable account of what the commands do. Two real ones:

JSON package.json in a webpack repository
"scripts": {
  "dev": "webpack --config .build/webpack.dev.js --progress",
  "prod": "webpack --config .build/webpack.prod.js --progress",
  "build": "npm run prod",
  "watch": "webpack --config .build/webpack.watch.js"
}
JSON package.json in a gulp repository
"scripts": {
  "start": "gulp --gulpfile config/gulp.js",
  "dev": "cross-env NODE_ENV=development npm run start -- dev",
  "build": "cross-env NODE_ENV=production npm run start -- build",
  "css": "cross-env NODE_ENV=production npm run start -- css",
  "js": "cross-env NODE_ENV=production npm run start -- js",
  "prod": "cross-env NODE_ENV=production npm run start -- build"
}

Do not trust a README over this block. In the gulp repository above, css and js build half the output each: handy while you work, never enough for a commit.

Watch tasks vary: run one before you rely on it

Four production repositories, four different situations:

  • A watch that works: npm run watch runs .build/webpack.watch.js, which exists and rebuilds on save.
  • A watch pointing at nothing: npm run watch names webpack.watch.js, which is not in the repository, so the command fails at once.
  • A watch on the production config: webpack --config webpack.prod.js --watch works, slowly, with minification on every save.
  • A watch nobody can start: the gulp file defines a watch function, but no task registers it and no script calls it.

Run the command once and watch what it does before building a habit on it. Whatever you use while working, finish with the production build before you commit: Commit a production build.

Node and dependencies

Install with npm ci, which follows the lock file exactly, rather than npm install, which can move versions and rewrite the lock file in a change that has nothing to do with it. Older gulp repositories pin webpack 4 and Sass toolchains that need an older Node; if the build fails on a fresh machine, check the Node version the last committer used before changing dependencies.

After the build

How a build splits its output into bundles is on Bundle boundaries; how a template loads one is on Queueing a script from a template.

Go deeper

Was this page helpful?

Your answer goes to the docs team.