This article is part of the Webpack from Zero to Hero series, for more background or for the index you can check the Chapter 0: History.
Previous - Chapter 2: Tidying Up Webpack
Next - Chapter 4: Dynamic Imports and Code Splitting (coming soon)
Right now we achieved a really simple application using Webpack and ES2015+ transpilation, but real apps are more than that, they have CSS, Images, custom Fonts and all sorts of different assets. The good thing is, in your code Webpack will treat then equally as ES Modules, as long you have the proper loader to them.
But calm down, we started with keeping Webpack config simple, and we’re going to stick to that! We’re going to learn how to setup more loaders, combine and pass options to them.
Now is the time to load assets. So, create a directory called assets in the root of the project and save any image you like there, and then you can follow the examples.
The file-loader treats your image as any asset and gives it a url path when importing it:
If you run this without installing the file loader first though, Webpack will complain:
Let’s install it then and add to our configuration file:
yarn add file-loader --dev
Append this snippet to your
webpack.config.js in the module.rules section:
Translating the regex: we are searching for any file ending with .gif, .png, .jpg/.jpeg or .svg, all being case insensitive (the
/i flag in the end).
Now if you run it again, webpack will successfully execute the build.
Using image-webpack-loader + file-loader will provide us with some nice optimization to our image files. It’s also easy to add:
yarn add image-webpack-loader --dev
And add the rule after the
It has some image compressors already enabled by default:
mozjpeg — Compress JPEG images
optipng — Compress PNG images
pngquant — Compress PNG images
svgo — Compress SVG images
gifsicle — Compress GIF images
Similar to images, we can set a rule for video and audio to be processed by the file-loader.
Just add the rule to the
webpack.config.js in the config.rules section:
😕 — “Wait there’s already a rule for file-loader, how this is going to work?”
That’s true, but we can add many config rules for different kinds of files. We’re just not adding the media files together with the rule that matches images because, on the last section, we chained it with the webpack-image-loader and it will probably break when reading an audio/video file.
Now you can import audio files, same as you do with images (file-loader will behave the same, providing the source url for you):
import andHisNameIs from "./assets/and-his-name-is.mp3";
Let’s play with that and add the following to the end of the
You can use any audio file, I’m using this one, but beware, the audio is quite loud 😆. Don’t play it at work!
Let’s add Sass support to our app! Same as before, we need the proper loaders and the sass parser:
yarn add node-sass sass-loader css-loader style-loader --dev
😱 — “Whawhawhaaaat? Why so many dependencies?”
Each one of this dependencies has a role to play:
- sass-loader + node-sass: receive your Sass files and output CSS
- css-loader: turns it into a JS module
- style-loader: gets the CSS module and inserts it into the page inside a
Adding this to the config:
Now let’s play around. Create a
style.scss file and paste this code into it:
Now add an import in
Each import you do will create a new
<style></style> entry in the header of the file. This can quickly go out of control, so you may want just to join all the files together, minify and provide as a single optimized file. For this we have a solution, which is the mini-css-extract-plugin.
To install is simple:
yarn add mini-css-extract-plugin — dev
Let’s add it to our production builds, in the
webpack.config.js, on top of it add the require call:
const MiniCssExtractPlugin = require(“mini-css-extract-plugin”);
Then add the loader to the scss rule, but only for mode production, otherwise let’s stay with the style-loader (and let’s take this opportunity to add source-map support too):
And finally, we do the same for the plugins section:
Running the build, we’ll see the style bundle being output:
As you see, the config already started to grow. But the advantage is, it’s a Node.js file and we can split it into functions!
And require it in
Now you can see that is way cleaner, and you know where the module rules are because the filename follows the same name of the config schema.
Remember what we learned in Chapter 2, a clean config sparks joy ✨!
Basically Webpack loaders and plugins mostly follow the format we saw in this chapter. There are many loaders out there, some from the Webpack core team, some created by the open source community ❤️, and even one that’s developed by me, webpack-chrome-extension-reloader (check it out 😉).
Let’s end here and go deeper in the next chapter. We will learn not only how to setup dynamic imports on our application, but play around with all Webpack code splitting strategies. See you in the next chapter!