Using Webpack 5 and SASS with WordPress
Published
A few years go I wrote an article on how to use Webpack to build JavaScript and CSS for a WordPress theme. Some time has passed, and I created an updated guide here. Hope its helpful!
Example Theme Published on GitHub
An example theme containing all of the code discussed in this post is available on GitHub, and includes a barebones WordPress theme with webpack 5, a SASS build, Babel JavaScript transpilation, and sample loaders for webfonts and images. The theme should be ready to download and drop into a running WordPress instance, simply follow the build instructions in the README.
Code Structure
How you organize you code is a matter of preference, and I don’t think there is really any wrong way to do it as long as things feel clean and organized. That being said, the code referenced in this post and the sample theme above follows this structure:
# some items removed for brevity
├── js
│ ├── build
│ └── src
│ ├── components
│ │ └── DisplayLabel.js
│ └── main.js
├── css
│ ├── build
│ └── src
│ ├── components
│ │ └── _content.scss
│ └── main.scss
├── img
│ └── background.jpg
├── font
│ └── open-sans
│ ├── opensans-regular-webfont.woff
│ └── opensans-regular-webfont.woff2
├── index.php
├── functions.php
├── package.json
├── package-lock.json
└── webpack.config.js
Webpack Config
Here is the final webpack 5 configuration file that builds JavaScript and CSS for a WordPress template (including SASS and Babel support):
const path = require('path');
// css extraction and minification
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// clean out build dir in-between builds
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = [
{
entry: {
'main': [
'./js/src/main.js',
'./css/src/main.scss'
]
},
output: {
filename: './js/build/[name].min.[fullhash].js',
path: path.resolve(__dirname)
},
module: {
rules: [
// js babelization
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
// sass compilation
{
test: /\.(sass|scss)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
},
// loader for webfonts (only required if loading custom fonts)
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: './css/build/font/[name][ext]',
}
},
// loader for images and icons (only required if css references image files)
{
test: /\.(png|jpg|gif)$/,
type: 'asset/resource',
generator: {
filename: './css/build/img/[name][ext]',
}
},
]
},
plugins: [
// clear out build directories on each build
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'./js/build/*',
'./css/build/*'
]
}),
// css extraction into dedicated file
new MiniCssExtractPlugin({
filename: './css/build/main.min.[fullhash].css'
}),
],
optimization: {
// minification - only performed when mode = production
minimizer: [
// js minification - special syntax enabling webpack 5 default terser-webpack-plugin
`...`,
// css minification
new CssMinimizerPlugin(),
]
},
}
];
CSS is extracted used the MiniCssExtractPlugin
plugin. Hashes are added to the output file names for caching (lines 19 and 63), and the CleanWebpackPlugin
plugin is used to clear build artifacts in-between builds. Minimization is included for the JavaScript and CSS (lines 66-74), and is only enabled during production builds (e.g. webpack --mode production
).
Incorporating Webpack Assets into the WordPress Theme
The JavaScript and CSS files produced by the webpack build are then loaded into the WordPress theme with an addition to the functions.php
:
// register webpack compiled js and css with theme
function enqueue_webpack_scripts() {
$cssFilePath = glob( get_template_directory() . '/css/build/main.min.*.css' );
$cssFileURI = get_template_directory_uri() . '/css/build/' . basename($cssFilePath[0]);
wp_enqueue_style( 'main_css', $cssFileURI );
$jsFilePath = glob( get_template_directory() . '/js/build/main.min.*.js' );
$jsFileURI = get_template_directory_uri() . '/js/build/' . basename($jsFilePath[0]);
wp_enqueue_script( 'main_js', $jsFileURI , null , null , true );
}
add_action( 'wp_enqueue_scripts', 'enqueue_webpack_scripts' );
The glob()
function is used to select the JavaScript and CSS files from the build directories, and accommodates the hash added to the filenames (notice the [fullhash]
on lines 19 and 63 of the webpack config above).
Once the WordPress theme is reading in the compiled JavaScript and CSS files, the theme is ready to go!
Lessons Learned when Migrating to Webpack 5
The overall approach for incorporating a webpack build into WordPress didn’t change, however there were a few subtleties I discovered when upgrading:
- Built-in Asset Modules can replace certain webpack loaders like
file-loader
andurl-loader
. - JavaScript minification is provided out of the box via the TerserPlugin.
-
process.env
is no longer polyfilled in webpack 5 and cannot be used in webpack config files without the use of something likedotenv-webpack
. - My actual blog website webpack build had multiple configurations (i.e. it exported multiple configuration objects). I had to enable parallelism in order for webpack to build more than the first entry..
Comments
No responses yet