Loaders
A loader in Webpack is a translator that takes a file as input, and outputs the same file in a different format. Loaders are essential to Webpack because Webpack only speaks JavaScript. So if you need to perform actions on .jsx
files (which is technically not JavaScript), you need the react
loader; if you need to handle .css
files, you need the css-loader
; if you need to handle .scss
files, you need sass-loader
; etc. You get the picture.
Nearly every HTML, CSS, and JS preprocessor and transpiler you’re used to works with Webpack.
Task Runners vs Webpack
Task runners which usually have some kind of watch command for file types, followed by the pipe of commands those files should pass through.
Webpack does something similar with loaders, but handles a lot of the work for you.
CSS Loader
Let’s install
yarn --dev style-loader css-loader
Then by adding a module.loaders
property to webpack.config.js
:
module.export = {
// …
module: {
rules: [
// Loaders go here
],
},
// …
};
A loader needs 2 things:
- A
test
that tells Webpack which filetypes to apply this loader too (useful when we start letting Webpack handle all different types of files). - An array of loaders to
use
in reverse order that we want Webpack to run those files through (first in the array means it’s the last loader processed in the chain).
So for our CSS files, it should look something like this:
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
Hint: the name of the loader is the same as the NPM package name
Once we have that, we can include our CSS in our JavaScript like so:
import './path/to/my/css.file';
And our CSS will be loaded via css-loader
, and appended to the DOM via style-loader
.
Note: css-loader
simply loads the CSS but doesn’t attach it to the DOM. This is because you may have other intentions for your CSS, and Webpack doesn’t assume you want to apply the styles to the current page right away. For that reason, style-loader
exists separately and serves the sole purpose of taking the loaded CSS and inserting it in the DOM.
Chaining Loaders
If you wanted to take it further and add Sass, you’d simply repeat the process, first installing the required loader (and its dependency) as dev dependencies:
npm install --save-dev node-sass sass-loader
And then you simply append the loader name to the end of the loader array (since we want this to happen first before Webpack takes the compiled CSS:
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
],
},
We could then expand this to include other file types as well:
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
{
test: /\.(jpg|jpeg|png|svg)$/,
use: ['url-loader'],
},
],
},
Typically, you’ll see extensions used as the dominant test
in loaders. But because it’s a RegEx test, the possibilities are virtually unlimited—you could, for example, process .scss
files in one directory completely differently than .scss
files in another directory. In this way, Webpack can cover even pretty extreme scenarios all while sticking to convention.
Loader Options
Take the following loader example:
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
],
},
Say we wanted to install the normalize.css
npm module (yes, it’s available via NPM!). We can install it with npm install --save-dev normalize.css
. But if we need to import it into our CSS, simply putting
@import "normalize.css";
doesn’t work right away. That’s because we’re not scanning for Node Modules. To enable that, let’s replace css-loader
in the array above with an object:
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { modules: true } },
],
},
],
},
Now we’ve configured CSS Loader to look for Node Modules when importing.
The options
vary from loader to loader. Refer to each loader’s documentation to see what, if anything, is configurable. For example, PostCSS Loader allows options.plugins
:
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: function () {
return [require('precss'), require('autoprefixer')];
},
},
},
],
},
],
}