We replaced thirty lines of Webpack config with one line of bash

We super-love Webpack for JavaScript code, but found it hard to use with CSS.

Webpack is designed to do lots of awesome to your JavaScript code: separate bundles, lazy-load stuff, hot-reloading, babelifying the world, hashing files, you name it. Webpack as a tool is quite broad and also allows to do extra stuff like processing CSS.

Webpack can be used to generate JS or CSS, between others

Our mistake was assuming that a tool that does one thing extremely well will also be awesome to use for everything else. Like using a hammer to eat soup.

How we wanted to compile CSS

Our CSS compilation process was super simple: use sass to compile our files, pass autoprefixer, minify, done. We wanted to create separate CSS files for many reasons (browser caching, start downloading from the clients asap, etc) and we were happy with having it separate from JavaScript. To make it clear, we wanted zero interaction between JavaScript and CSS (no JASS or import CSS from JavaScript).

We started working on integrating Sass and CSS into our shiny new Webpack 2 config. This is a list of the stuff that we ended up adding to webpack.config.js, one line at a time:

In the end, we had more than thirty lines of code (you can see an example of a similar config here). It didn’t look good and we could barely understand what half of the code was doing anyway. Apparently we were generating our CSS code, transform into JavaScript code, then extract and save into a CSS file.

At this point it was apparent to us that we were swimming against the expectations of Webpack. Webpack is super helpful for including CSS files from JavaScript, optionally processing any referenced resources. That’s a totally fine use case, but not something we were trying to achieve. We just wanted to create CSS from Sass, maybe minify, and call it a day.

The replacement

We challenged our approach and started searching for options out of the box. How about compiling the Sass code using the command line? We had already installed node-sass, so we could just launch this:

node-sass scss/styles.scss build/styles.css

We wanted to trigger this when we detect changes to the source files. There are JavaScript libraries for this, but most solutions depend on either Mac or Windows, and fall back to polling on Linux. We decided to roll with a native Linux solution using inotifywait, a tool that detects changes in the filesystem and triggers the associated command line.

A bit of StackOverflow search later, we added a line to package.json that detects any file being added, removed or updated:

"watch:css": "inotifywait -m -r -e modify,create,delete ./scss/ | while read NEWFILE; do node-sass scss/styles.scss build/styles.css; done"

One of the advantages of using a native tool is that it scales with the size of the folders to watch. The trigger is almost immediate, and the watch is reused between compilations.

There is one last problem, which is launching this watch:css script at the same time than webpack or our local web server. We used concurrently for that:

"scripts": {
"watch:js": "NODE_ENV=development webpack --watch --config webpack.config.js",
"watch:css": "inotifywait -m -r -e modify,create,delete ./scss/ | while read NEWFILE; do node-sass scss/styles.scss build/styles.css; done",
"watch": "concurrently \"npm run watch:js\" \"npm run watch:css\" \"http-server -s .\" \"xdg-open\"",

You may have noticed that we are just using http-server instead of webpack-dev-server. We also evaluated pros and cons in this case, and simplicity trumps for us, since most of our coding is done against Mocha tests.

We are way happier now and trust much more the maintainability of the solution (you can see the final package.json here). You could tell it’s the simplicity, but it’s also that these are ages-old tools. They are not going to change anytime soon, but it’s hard to get anything simpler than that.