- 1. Webpack 4 course – part one. Entry, output and ES6 modules
- 2. Webpack 4 course – part two. Using loaders to handle scss, image files and transpile JS
- 3. Webpack 4 course – part three. Working with plugins
- 4. Webpack 4 course – part four. Code splitting with SplitChunksPlugin
- 5. Webpack 4 course – part five. Built-in optimization for production
- 6. Webpack 4 course – part six. Increasing development experience
- 7. Webpack 4 course – part seven. Decreasing the bundle size with tree shaking
- 8. Webpack 4 course – part eight. Dynamic imports with prefetch and preload
Today we continue our webpack 4 tutorial. After walking through the basic concepts of webpack, it is time to go deeper. This time we will cover something that is a great strength of webpack: loaders. First, we will learn how to use loaders that are available. This will include handling css, scss, image files and transpiling JavaScript to the older versions of the language. Let’s go!
Webpack 4 tutorial continued – what are loaders?
In the previous part of the course, I’ve said that webpack is a module bundler. But this is not its only purpose. Even though webpack understands only JavaScript files out of the box, it can be changed with the usage of loaders. Aside from just handling many types of files, it can modify them.
Adding loaders
The best way to use loaders is to specify them in the webpack.config.js file. To do that, you need to add a module.rules property.
css-loader
The css-loader interprets imported css files.
1 |
npm install css-loader |
Consider the configuration below:
webpack.config.js
1 2 3 4 5 6 7 8 9 10 |
module.exports = { module: { rules: [ { test: /\.css$/, use: 'css-loader' } ] } } |
rules
The property rules is an array of all of your loaders. These rules will be applied to every file, that matches the test property of the rule. This is, in fact, a regular expression.
If you would like to know more about regular expressions, check out my regex course.
use
The property use is an indicator of which loader should be used for matching files.
Chaining loaders
With the code above, you are able to import css files through your JavaScript code (for example using ES6 modules that we covered in the previous part of the course).
But this is not enough to actually put that css to work. We need a way to serve that code to the browser. Here, the style-loader will be useful.
1 |
npm install style-loader |
But that would mean using two loaders for the css files. You can do that by chaining loaders.
webpack.config.js
1 2 3 4 5 6 7 8 9 10 |
module.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] } ] }, } |
As you can see, now we are assigning an array to the use property. A very important thing to note is that the chain is executed in reverse order.
style.css
1 2 3 |
body { background-color:black; } |
index.js
1 |
import './style.css'; |
Using the configuration above will work like that:
- Webpack will try to resolve the style.css file
- The filename will match the /\.css$/ regular expression
- The file will be interpreted by the css-loader
- The result of the css-loader will be passed to the style-loader
- Finally, the style-loader will return a JavaScript code
By default, the output bundle is ./dist/bundle.js. Now, this file will contain code that will attach all the styles into the <style> tag. If you link the bundle.js file in the HTML, the output after running the script will be like that:
1 2 3 4 5 6 7 8 9 10 11 12 |
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Webpack App</title> <style type="text/css">body { background-color:black; }</style></head> <body> <script type="text/javascript" src="bundle.js"></script> </body> </html> |
sass-loader
With all that knowledge, you can easily add sass/scss support to your project. We will use sass-loader here.
1 |
npm install node-sass sass-loader |
Sass-loader needs node-sass to work. Now you just need to add it to the loader chain:
webpack.config.js
1 2 3 4 5 6 7 8 9 10 |
module.exports = { module: { rules: [ { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] } ] }, } |
And there you go, now you can import scss files! Files, before being interpreted by the css-loader, will be transpiled from the scss to pure css.
Passing options to loaders
Loaders can, in fact, accept additional options. Let’s explain it with the example of url-loader
1 |
npm install url-loader file-loader |
webpack.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
module.exports = { module: { rules: [ { test: /\.scss$/, use: ['style-loader', 'css-loader','sass-loader'] }, { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 5000 } } ] } ] } }; |
Note, that if you wish to pass options to the loader, you no longer add loaders to the use property as a string. Now it is an object with two properties: loader (the name of the loader) and options.
The url-loader will transform your images into base64 URIs. If your images are very small, it might be better for your performance to include them straight into your code. This will cause your browser to make fewer requests. If your images are big though, it might be beneficial to include them as separate files so that the browser might fetch them in parallel.
This is why the url-loader has the limit property. It is a size (in bytes) that will determine, that the file is too big to serve it as a base64 URI. Instead, the file-loader will be used that will just copy your files.
1 2 3 4 5 6 |
body { background-image: url('./big-background.png'); } .icon { background-image: url('./icon.png'); } |
The above configuration will result in:
1 2 3 4 5 6 |
<style type="text/css">body { background-image: url(ca3ebe0891c7823ff1e137d8eb5b4609.png); } .icon { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAALElEQVR4AWMYIWAU1FPLoP9AXEFI0QEi8H+YYdQyqIEaXuumRhh1DZdUMwoATlYWfwh9eYkAAAAASUVORK5CYII=); } </style> |
Since the big-background.png was bigger than the defined limit, it was copied to the dist directory with a random filename. The icon.png file was converted to the base64 URI instead.
Using babel to transpile JavaScript
Another popular loader is babel-loader. It allows transpiling JavaScript files using Babel. It is a solution for writing code in the latest versions of JavaScript. This might be useful if you want to support older browsers, or if you want to use some feature that even modern browsers don’t implement yet.
1 |
npm install babel-loader babel-core babel-preset-env |
webpack.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
module.exports = { module: { rules: [ { test: /\.js$/, exclude: /(node_modules)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] } }; |
Note, that we used exclude property here, which is also a regular expression. If the path of any file will match this expression, the file will not be transpiled.
There are many presets that you can use to fit your needs. Read the official babel documentation for a list of them and try to experiment with an online transpiler.
Summary
This time we’ve learned a very useful feature of webpack: loaders. We’ve covered some of the loaders that are available to us. Using them, we’ve managed to add a scss support to our project. Besides that, we’ve learned how to handle images using url-loader. Another common usage of loaders that we’ve discussed is transpiling JavaScript using Babel. In the future parts of the course, we will dig deeper into loaders, including writing our own loader.
sass-loader needs node-sass to be installed as well to work.
I confirm Aishwarya’s comment. It would be nice if you could updated that command line by appending “node-sass” to it. It would come in handy for others trying the tutorial.
Thank you! 😀
Thank you for contributing. I added it 🙂
Isn’t the default output .js file main.js, as stated in part one of this tutorial? Or is there something here that changes that default to “bundle.js”?