Since Github Actions became a thing, I became interested in saving precious seconds in our plan by optimizing assets build time. As long as it didn't exceed 60 seconds, there was little motivation, but once it did, I said enough is enough.
Our build step runs two commands:
npm ci
npm run build
We use babel and TailwindCSS. Using simple methods, I discovered that CSS and JS take about the same time to build.
Benchmark: Webpack build took 64 seconds, whole build took 91 seconds.
Replacing babel-loader + terser with esbuild loader
The first thing I did was replace babel-loader
and Terser (minification tool) with esbuild-loader. This made our JS compile around 12 times faster, it went down to 1.4 seconds. It was a good start.
Result: Webpack build took 40 seconds (down from 64), whole build took 65 seconds.
Configuring Tailwind
The second optimization had to do something with CSS because that's where most of the build time now lay. I visited the TailwindCSS documentation to find out how to decrease build size.
The template we base our projects on uses a style guide with predefined colors, sizes, etc., so we don't need some of the configuration from TailwindCSS. Knowing this, here's what I did:
- Moved
colors
configuration outsideextend
, which disabled all the built-in colors from the build. This made a huge difference in development file size (10.5MB → 4MB). - Moved
spacing
configuration outsideextend
- Disabled corePlugins
I had to bring some of these back because we used them in a couple of places. After these changes, I considered TailwindCSS optimization done.
The file size of development CSS went down from 10.5MB to 3.9MB, which is a big deal (depending on the developer's connection speed) if you are sending your CSS on every CSS change. It does not happen often when working with TailwindCSS, but it was still a welcome improvement for everyone using our pos-cli sync
command.
Result: Webpack build took 26 seconds (down from 40), whole build took 49 seconds.
Read about TailwindCSS optimization in their documentation:
Disabling PostCSS processing
The last step was to disable PostCSS processing of CSS pulled in from node_modules
.
Before, it was pretty naive — everything went through all the CSS loaders:
{
test: /(\.css)$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { url: false } },
'postcss-loader',
],
},
I split it into two so that node_modules
are processed only by css-loader
, and application CSS is processed by PostCSS first.
{
test: /(\.css)$/,
include: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { url: false } }
],
},
{
test: /(\.css)$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { url: false } },
'postcss-loader',
],
},
Result: Webpack build took 17 seconds (down from 26), whole build took 39 seconds.
That's all :)
This journey was one of those creative ones where you fiddle around, find gains in various places, and they add up. In this case, they added up to 52 seconds of savings for every build. And we build a lot, so this improves our developer experience and lowers the cost of CI.
Action | Webpack build time (seconds) | Whole build time (seconds) |
---|---|---|
At the start | 64 | 91 |
Using esbuild loader | 40 | 65 |
Configuring Tailwind | 26 | 49 |
Disabling PostCSS processing | 17 | 39 |
In the following article, I will report how development speedup is going because the TailwindCSS team just released the experimental TailwindCSS JIT, which might improve live development even further.
Read more
If you are interested in more performance oriented content, follow me and I promise to deliver original, or at least effective methods of improving your website.
Top comments (0)