webpack for WordPress, Part 2: Compiling WordPress Theme Files

In a previous post, we talked about adding webpack to your WordPress theme and covered the basics of installing and including it in your theme’s dependencies. The next step for any webpack theme setup is to import your source files using an entry point file. In some cases (for example with CSS preprocessors or modern JS) you may need to include special instructions for how you want webpack to process the contents of these files. In this post we’ll take the existing JS and SCSS assets included with WordPress’s underscores starter theme, and compile them into minified assets that can be added to your WordPress front-end.

webpack and WordPress logos

1. Add File Loaders for Styles

The styles for the underscores theme are written using SCSS, or Sassy CSS syntax. These files need to be consumed by a preprocessor to be compiled into valid CSS. webpack lets us do this using a combination of loaders and module rules.

The first thing we’ll want to do is use npm to install the necessary packages and save them to our devDependencies in package.json:

npm i css-loader sass-loader node-sass mini-css-extract-plugin -D

The css-loader module handles CSS files for webpack, sass-loader does the same for SCSS files, and node-sass is a wrapper that essentially lets webpack compile SCSS files using the LibSass library. The final package is mini-css-extract-plugin which will let us extract the compiled CSS from the bundled JS file that webpack generates and place it in its own .css file.

We’ll add these tools to our project using our webpack.config.js file. First, require the Mini CSS Extract Plugin:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

We can then add a set of rules for how webpack should handle SCSS files to your module.exports. The test option tells webpack to look for files with a .scss extension and then use sass-loader to compile SCSS into CSS, css-loader to handle the results, and then pass them MiniCssExtractPlugin:

  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader'
        ]
      }
    ]
  },

And then next, we’ll configure the Mini CSS Extract Plugin and tell webpack to handle the extracted CSS by saving it in a file named after our entry point and placing it to the ./dist folder:

  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css'
    })
  ]

To view a Git diff of just the changes made in this step, check out this commit.

2. Add File Loaders for Scripts

Good news! You don’t need to do anything for this step because webpack compiles (and minifies!) javascript out of the box. That said, if you’re like most people and writing modern JS (ex: ES6) for your theme, you’ll want to add the babel-loader module to your webpack.config.js to transpile JS, just like your SASS loader. We’ll omit this step for now since underscores uses jQuery for their JavaScript files. This means we don’t need a transpiler, and in this case it would unnecessarily slow compile times. Maybe in a future post we can cover re-writing these files using modern JS.

3. Optimize and Minify Built Assets

Production mode in webpack 4 minifies javascript by default. Minifying CSS is optional of course, but here’s how to do it.

Just like compiling SASS, we’ll need to install an npm package to include CSS minification to our webpack toolchain:

npm i optimize-css-assets-webpack-plugin -D

For this operation, we’ll want to require the following two components in our webpack.config.js file.

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

Then we can configure how webpack optimizes our files using the optimization settings block inside module.exports:

  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: true
      }),
      new OptimizeCssAssetsPlugin({})
    ]
  },

These config options do two things. First, new OptimizeCssAssetsPlugin({}) adds CSS minification to our project using the default options. And second, because we’ve now customized the optimization settings in our config, the webpack defaults are overridden. So we need to explicitly include a JS minimizer, in this case using webpack’s default UglifyJsPlugin.

This guarantees that both our JS and CSS output will be minified. For a Git diff of the changes outlined in this step, have a look at this commit.

4. Move Theme Assets to Source Folder

Now webpack is ready to compile our different asset file types. It’s time to do some housekeeping and move our existing CSS and JS into our webpack project directories. In the case of underscores, there is a ./js/ and a ./sass/ folder in the project root. We want to move these files* into our ./src/, or webpack source, folder.

*Everything with the exception of ./js/customizer.js, which is enqueued conditionally by WordPress and should not be part of the global site bundled assets.

How you want to organize your files beyond this is completely up to you. However, there are some common conventions and general best practices to follow. For example, you’ll probably want to give each entry point its own component folder inside ./src/. For now we’re starting with just ./src/site/ for our global scripts and styles, but you may want to add things like ./src/home, ./src/single, or ./src/admin for other WordPress templates later on. What’s important is that you have a clear path to an entry point file (like ./src/site/index.js in this case) for each component, and that you don’t add anything manually to your ./dist/ build folder.

For this project, we can do the following:

  • Move and rename ./sass/ to ./src/site/scss/
  • Create a new folder at ./src/site/js/ and move ./js/navigation.js and ./js/skip-link-focus-fix.js into this directory.
  • In the ./src/site/scss directory, rename style.scss to index.scss

Your resulting webpack ./src/directories should look something like this:

project
├── src
│   └── site
│       ├── js
│       │   └── ..
│       ├── scss
│       │   └── ..
│       └── index.js
└── dist
    ├── site.css
    └── site.js
        

We could further optimize things by moving some of our variable and mixin style sheets into a directory at ./src/core/scss, but we can worry about that once we start including additional entry points in the theme.

And last but not least, we’ll want to clean up our ./style.css file. This file is required by WordPress because it contains theme meta information, but in our case we’ll be building and enqueueing our own stylesheet elsewhere. So in this case, we can remove basically everything except the theme meta information in the header comment section. (Basically delete everything after Line 21.) And likewise, we can also delete the theme meta information from our ./src/site/scss/index.scss file so its not included in our bundled assets.

For a visualization of the file changes in this step, you can look at this commit, or for specifics on what was deleted from ./style.css, check here.

5. Import Asset Files Via Site Entry Point

Now we can let webpack know there are files we want to include in this bundle by importing them in our ./src/site/index.js file:

// Global Javascript
import './js/navigation';
import './js/skip-link-focus-fix';

// Global Styles
import './scss/index.scss';

Note that JavaScript files don’t require an extension because webpack looks for them by default. For any other file type you’ll want to include one.

6. Run webpack Build

With the file loaders in place, the theme assets added to our source folder, and webpack set up to import the files, we’re ready to use the shortcut command we added to our package.json file in Part 1 to run our first production build of our webpack ready theme:

npm run build

This should update the contents of your ./dist folder to now include a minified site.js file which contains the starter theme scripts, and a minified site.css, which contains the theme’s global stylesheet.

Next Step, Enqueue Bundled webpack Assets With WordPress

Our theme’s global CSS & JS files are now concatenated, minified, and ready to be added to our WordPress front-end. For a Git diff of all the changes outlined here, take a look at this pull request.

Check back next week for Part 3 of adding webpack to WordPress: Importing and enqueueing your compiled theme assets.

ian.pvd

UX & WordPress developer currently based in Brooklyn, excited about open-source projects, improving journalism, web accessibly, and modern design. I write a lot of code, read a lot of news, listen to electronic music, and eat mostly tacos.