Jekyll Webpack
This article is Part 1 in a 3-Part series.
- Part 1 - This Article
- Part 2 - Jekyll Webpack Part Two - Tailwind
- Part 3 - Jekyll Webpack Part Three - Diffing for partial reloads
I’ve made another Jekyll plugin jekyll-esm which works with the new standards compliant es6 module system if you are interested in using JS with no asset bundler.
I’d been following guides online and experimenting with integrating Webpack with Jekyll and I ultimately realised that there were certain aspects of the two tools that mean they need to be treated very specifically when used in combination.
Build order matters
In an earlier more naive Jekyll/Webpack hybrid Jamstack implementation I’d been building Webpack first and then piping the output to Jekyll as the second step. While this works to a point, it soon breaks down because some JS tools (Such as PurgeCSS) depend on your HTML in order to properly function. As a result the jekyll-webpack
gem was born.
Compile HTML first, assets second
With this plugin you only need the one command: jekyll build
or jekyll serve
and Webpacked assets are handled automatically as a step in the build pipeline. This neatly solves the problem of running webpack after your html has been rendered.
Installing jekyll-webpack
In your jekyll project add gem 'jekyll-webpack', group: [:jekyll_plugins]
to your Gemfile and then bundle install
.
Now add it as a plugin in _config.yml
:-
# _config.yml
plugins:
- jekyll/webpack
Preferably add this as the last plugin to ensure it happens last.
Webpack can get slow! Debounce!
If you’re using a tool such as tailwindcss, the bundle can get large, you don’t always want webpack to run every time jekyll does if you’re using jekyll serve
for example. As long as you’ve got your assets in a sub directory (such as ./src
) you can tell Jekyll Webpack to watch for changes and only run when you change a file in that folder. To do this, add a section to _config.yml
and restart jekyll serve
:-
# _config.yml
webpack:
debounce:
watch: src
Now, Jekyll Webpack will cache the last changed version of your bundle and will only rebuild it if a file in ./src
is changed (while serve
is running).
Building it for production
If you want webpack to build a production bundle you can pass the environment via NODE_ENV
. So to build your production bundle:-
NODE_ENV=production bundle exec jekyll build
Webpack can do a lot!
And so now you can have a webpack config in your Jekyll project such as:-
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require("path");
const glob = require("glob-all");
const PurgecssPlugin = require("purgecss-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", {
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
plugins: [
require('tailwindcss'),
require('autoprefixer'),
],
},
}]
}
]
},
plugins: [
new MiniCssExtractPlugin(),
new PurgecssPlugin({
paths: glob.sync([
path.join(__dirname, "**/*.html"),
path.join(__dirname, "dist/**/*.js")
]),
extractors: [
{
extractor: content => content.match(/[A-z0-9-:\/]+/g) || [],
extensions: ["html", "js"]
}
]
})
]
};
Note that PurgeCSS is bundled in to Webpack now. There’s no need to have it as a seperate build step handled by a Jekyll plugin or such. Personally I prefer this style of asset configuration as it keeps it all in one place.
Installation and Usage instructions are available in the README