WittCode💻

Webpack Loaders

By

Learn what webpack loaders are and how to use them. We will be using the webpack css-loader and style-loader as a demonstration.

Table of Contents 📖

What are webpack Loaders?

A webpack loader is simply a function that transforms source code. For example, there are webpack loaders to transform TypeScript to JavaScript, SCSS to CSS, etc. We do not need a loader for JavaScript as webpack knows JavaScript code out of the box. However, for other resources like TypeScript files and stylesheets we need to install a loader for them. Webpack loaders are available on npm such as ts-loader for TypeScript and css-loader for CSS.

CSS Loader

To demonstrate loaders in action, lets work with a CSS loader. A CSS loader transforms CSS into a string and loads it into a JavaScript file. Lets install the CSS loader called css-loader from npm as a development dependency.

npm i css-loader -D

Now lets configure webpack to use the css-loader package. To do this, inside webpack.config.js we first need to add the module key.

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'my-bundle.js',
        path: `${__dirname}/my-output`
    },
    module: {}
}

The module key tells webpack how different module types should be handled. A module is essentially a discrete chunk of code. We can tell webpack how it should handle different module types by using rules.

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'my-bundle.js',
        path: `${__dirname}/my-output`
    },
    module: {
        rules: [{}]
    }
}

The rules key accepts an array of rule objects. A rule object tells webpack how to handle a certain module. Lets tell webpack to handle CSS files with the css-loader.

module.exports = {
    module: {
        entry: './src/index.js',
        output: {
            filename: 'my-bundle.js',
            path: `${__dirname}/my-output`
        },
        rules: [
            {
                test: /\.css$/,
                use: 'css-loader'
            }
        ]
    }
}

This tells webpack that for any file ending in .css (the $ sign means end of the string and the . is escaped because we mean . and not wildcard character) run the css-loader against it. Specifically, the test key is a test that must be passed for the loader to be ran. Here, the test says that the file must be a CSS file to be transformed by the CSS loader. The use key accepts loader(s) to be applied to the files that pass the test. Now create a CSS file called my-css.css inside src/styles and add some CSS to it.

h1 {
    color: #FFFFFF;
}

body {
    background-color: #272727;
}

Now create an index.js file inside src and import the css file.

import styles from './styles/my-css.css';

Now build the bundle using webpack --config webpack.config.js.

webpack --config webpack.config.js

Now if we inspect the output file inside webpack's output directory we will see a lot of webpack magic, but we can also see our CSS outputted as a string.

c.push([e.id,"h1 {\n    color: #FFFFFF;\n}\n\nbody {\n    background-color: #272727;\n}",""]);

Style Loader

This is cool and all but not very useful at the moment. We need a way to get these styles to be displayed inside an HTML page. We can do this using another loader called style-loader. Install it from npm with npm i style-loader -D.

npm i style-loader -D

The style-loader takes the output from the css-loader and applies it to the DOM. Specifically, it takes the output from the css-loader and places it inside a <!-- webpack.config.js -->

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'my-bundle.js',
        path: `${__dirname}/my-output`
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
}

Note that the order in the array supplied to use is very important. We want our css-loader to be ran before our style-loader because first our CSS is transformed into a string and placed inside the JavaScript bundle file by the css-loader. This output is then placed into a style tag by the style-loader. Loaders proivded to use are executed from last to first, so here the css-loader will be ran on the CSS files and then the style-loader will be ran next. Now lets create an HTML file called index.html inside webpack's output directory to house our bundle file.

touch my-output/index.html

Now lets add an

tag and our output bundle script.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>WittCode is Cool!</h1>
    <script src="./my-bundle.js"></ script>
</body>
</html>

Now serve up the file such as with VS Code's live server extension and look at the styles applied to the webpage. We can see that the style-loader applied our styles inside a

Image

Further Customize CSS Loader

Webpack loaders are also configurable. To demonstrate, lets use our imported CSS like a module. We can do this by providing an object as opposed to the name of the loader to the use key.

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'my-bundle.js',
        path: `${__dirname}/my-output`
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            modules: true
                        }
                    }
                ]
            }
        ]
    }
}

Here we are enabling CSS modules for all files. To demonstrate, add a class to my-css.css.

.cheese {
    background-color: orange;
    height: 50px;
    width: 50px;
}

Next, inside index.js, access this class, apply it to an element, and then add that element to the DOM body.

import styles from './styles/my-css.css';

const myDiv = document.createElement('div');
myDiv.className = styles['cheese'];
document.body.appendChild(myDiv);

So, thanks to webpack loader customization, we can now access the cheese class from our CSS file in our JavaScript file. Re-run the program and look for the new square of cheese.

Image