DEV Community

Cover image for You'll be more productive learning webpack with these methods
Lee
Lee

Posted on • Edited on

You'll be more productive learning webpack with these methods

Preface

As explained in the previous article - Take your webpack to the next level by understanding these concepts, we have a general understanding:

  • Some of the concepts that arise in using webpack process
  • Combined with the concepts of the packaging process, we analyzed the webpack packaging process, so that we can have a general understanding of the packaging process.

We all know that in the actual development process, we use webpack only to finally output css, img, js, html and other front-end resources that the browser can run.

So, in order to be more close to the actual situation, in this article, we will learn how to configure webpack with the purpose of how to output css, img, js, html and other front-end resources.

Learning Outline

This article explains the following basic configuration:

  • Handling css, less files
  • Handling img, font, audio and other front-end resource files.
  • Compiling es6+ syntax and API.
  • Processing html files

The webpack documentation is pretty detailed, so I don't want to copy and paste it and write it all over again, so it's better to just read the documentation.

Learning can't be learned the hard way, there should be some methods and techniques. Therefore, I would like to summarize some methods in the process of explaining the configuration, so that we can better understand the configuration of webpack. In this way, some similar configurations, we can match them by looking at the documentation.

Remarks

The article has been uploaded to github:

  • For the sake of reading convenience, the article only posted the relevant code, it is recommended to fork it to see the complete code; or follow the article together with the side of the knock, so that the impression will be more profound!
  • It's not easy to create, if you think it's helpful, welcome to star๐ŸŒŸ!

Handling css, less files

Let's start with the learn-03 case to see how webpack handles style files.

We install the appropriate loader to parse them:

  • less-loader: parses less into css.
  • css-loader: parses css into valid modules recognized by webpack.
  • style-loader: parses css and inserts it into <header />.
npm install less less-loader css-loader style-loader -D
Enter fullscreen mode Exit fullscreen mode

Then configure it:

// webpack.config.js
module.exports = {
    ...,
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ],
            },
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

The parsing of loader is performed in reverse order (or right-to-left), so this configuration will be performed in the following order (less-loader โ†’ css-loader โ†’ style-loader):

  1. parses less into css.
  2. pass the result to css-loader, which parses it into a valid module recognized by webpack.
  3. passes the result to style-loader, which inserts the parsed styles into <header />) in the following order.

The less, css, and entry file code is:

// index.less
*{
    margin: 0;
    padding: 0;
}
h1{
    color: red;
    margin-top: 20px;
}

/* index.css */
h2{
    color: green;
}

// index.js
import './assets/index.less';
import './assets/index.css';
Enter fullscreen mode Exit fullscreen mode

Output:

compile_style

We'll see that the style we wrote was processed successfully and inserted into the <head/>.

Summary

We previous post said:

  • The resource files that we come in via import or require, or each file in our project, can be viewed as an individual module
  • The role of the Loader is to convert these modules into valid modules that webpack recognizes.

webpack humanely exposes the module configuration item, which is specifically designed to configure the relevant loader to parse the corresponding module. So if we want to parse some module used in our source code, we should:

  • download the appropriate loader first
  • Find the module configuration directly and configure it according to the loader usage.

So, we can try to configure our own .scss or .txt files according to the above summarized methods and ideas.


OK, we successfully got the styles (css) we need for our project, next we will see how to deal with images (img) and other front-end resource files.

Handling front-end resource files

There are a lot of front-end resource files, here, we roughly divide them into two categories first:

  • Common class: img, font, video and so on.
  • Special category: .csv, .xml and so on.

These resources are also modules as long as they are imported or required into our source code. Since they are modules, we need to install the appropriate loader to parse them, and then configure them in the module configuration.

Prior to wepack5, For resources of commonly used classes, we generally needed to install the following loader to parse them:

  • raw-loader: parses files into strings
  • file-loader: parses files coming in from import/require() into a fully referenced url and sends the file to the output directory
  • url-loader: can convert files to base64.

We often use file-loader and url-loader. This is because common resources are often introduced into our projects as url, or converted to base64 in order to reduce http requests.

But after webpack5, webpack has built-in the functions of the above several loaders, so we can no longer need to install the above loaders; we can directly use webpack's own asset module.

The resource module built in after webpack5:

  • asset/source: equivalent to raw-loader.
  • asset/resource: equivalent to file-loader.
  • asset/inline: equivalent to a url-loader.
  • asset: more flexible, has both asset/resource and asset/inline. If you set a file size limit, the file will be converted to base64 if it doesn't exceed the limit; if you don't set a size limit, it works the same as file-loader.

This is why I love webpack5 so much, because we don't have to install so many messy loaders.

Let's use the case of learn-04 to see how we can use the resource module to parse our front-end resources.

Let's add the configuration from the previous chapter on parsing styles together and use the image resources in less and js respectively.

We have two images:

  • preview.gif: size 349kb
  • ecj-cli.png: size 4kb.
// webpack.config.js
module.exports = {
 ...,
 module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ],
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                      maxSize: 1024 * 10 // // When the image size is < 10kb it will be converted to base64
                    }
                },
                generator: {
                    filename: '[name][ext]' // Set the name of the output file
                }
            }
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

Entry file:

// index.js
import './assets/index.less';

const img = new Image();
img.src = require('./assets/ecj-cli.png');
img.width = 500;
document.querySelector('#js_logo').append(img);
Enter fullscreen mode Exit fullscreen mode

Style:

.bg_logo{
    width: (1434/3px);
    height: (1212/3px);
    background-image: url('./preview.gif');
    background-size: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Output results:

compile_resource

We'll see that the style and js both process the image successfully:

  • preview.gif is larger than 10kb, so instead of being converted to base64, a full reference path is returned (equivalent to file-loader)
  • ejc-cli.png is smaller than 10kb so it was converted to base64 (equivalent to url-loader)

The gif above is a command line tool ejc-cli that I developed that is very useful in everyday projects. It can convert the Excel data collected by the docking staff into json data in a certain format which is needed by our code. It is very convenient for us to develop and maintain the data, and also to interface with other people.

If you are interested, you can check out ๐Ÿ‘‰๐Ÿป learn about ejc-cli

Summary

Resources that are imported into our source code via import or require are also modules. So you need to download the appropriate loader and configure it in the module configuration.

For common resources (img, font, video, audio, etc.):

  • Because they are commonly used, webpack5 has built-in functionality to handle them, so that we don't need to install an additional loader, and we use the asset module to manage them directly.
  • We generally use asset/resource, asset/inline, asset modules to manage common class resources. Because the resources of our common classes are often introduced in our projects, we need to parse them to introduce the full url, or convert them to base64 in order to reduce the number of http requests.

For special classes of resources (.csv, .xml, etc.):

  • We can understand that because they are not commonly used, webpack does not have their functionality built in.
  • Therefore, we need to install the appropriate loader to parse them. For example, if we want to parse a .csv file, we need to install the csv-loader to parse it.

We can try to configure ourselves to handle .video or font as summarized above.


OK, so far, we've got css, img. Let's see how we can get our js through webpack processing.

Compiling es6+

To this day, js is evolving rapidly, and every year some new syntax or new API appears in order to improve development efficiency and code quality.

For example, in terms of syntax appeared:

  • Arrow functions: ()=>
  • class syntactic sugar: class People {}
  • Deconstructed assignment: const [x, y] = [1, 2];
  • ...

On the API side again:

  • Promise
  • Array.prototype.includes()
  • Object.keys()
  • ...

But these new additions are not supported on some lower browsers, so we need to use webpack to compile our es6+ into a version that these lower browsers can support.

Let's start with the learn-05 case and see how we configure webpack to compile es6+.

We install the relevant dependencies:

...
"devDependencies": {
    "@babel/core": "^7.22.8",
    "@babel/plugin-transform-runtime": "^7.22.7",
    "@babel/preset-env": "^7.22.7",
    "babel-loader": "^9.1.3",
    "webpack": "^5.88.1",
    "webpack-cli": "^5.1.4"
},
"dependencies": {
    "core-js": "^3.31.1"
},
Enter fullscreen mode Exit fullscreen mode

Entry files. Uses es6+ syntax such as class, Promise, ()=>{} and API:

// index.js
class People {
    constructor(name) {
        this.name = name;
    }
    sayHi() {
        return Promise.resolve(this.name);
    }
}
const Lee = new People('Lee');
Lee.sayHi().then(name => console.log(`Hi, I am ${name}.`));
Enter fullscreen mode Exit fullscreen mode

Configure webpack:

// webpack.config.js
module.exports = {
    ...,
    module: {
        rules: [
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

Configure Babel. Create a new babel.config.js file in the project root directory:

// babel.config.js
const presets = [
    [
        '@babel/preset-env',
        {
            useBuiltIns: 'usage',
            corejs: {
                version: require('core-js/package.json').version,
                proposals: true
            }
        }
    ]
];
const plugins = [
    '@babel/plugin-transform-runtime',
];
module.exports = {presets, plugins}
Enter fullscreen mode Exit fullscreen mode

Set the target browser to be compatible with. Add the browserslist field to package.json:

"browserslist": [
    "ie 11"
]
Enter fullscreen mode Exit fullscreen mode

The result of running it in ie 11:

compile_es6

We will find:

  • The es6+ we wrote runs successfully in ie 11.
  • Promise, the es6+ API, has also been added to ie 11.

It means that our compilation of es6+ was successful.

About Babel

In the configuration above, you will notice that if we want to compile es6+ with webpack, we also need to add the babel.config.js file to the root directory, which is a much more complicated and troublesome step than dealing with other modules. This is because compiling the core of es6+ requires Babel to work with it. Babel is a tool for compiling es6+.

Since this post is mainly about webpack, we'll just give a general mention of Babel here. Here are some common configurations for Babel.

  • If the project we are developing is an application or a large project, we can configure it like this:
const presets = [
    [
        '@babel/preset-env',
        {
            modules: false,
            useBuiltIns: 'entry', // or useBuiltIns: 'usage',
            corejs: {
                version: '3.27.2',
                proposals: true
            }
        }
    ]
];
const plugins = [
    '@babel/plugin-transform-runtime'
];
module.exports = {plugins, presets};

// index.js
// If use useBuiltIns: 'entry'
import 'core-js/stable'
Enter fullscreen mode Exit fullscreen mode
  • If we are trying to develop a third party library, we can configure it like this:
// Babel้…็ฝฎ
const presets = [
    [
        '@babel/preset-env',
        {
            modules: false
        }
    ]
];
const plugins = [
    [
        '@babel/plugin-transform-runtime',
        {
            corejs: {
                version: 3,
                proposals: true
            }
        }
    ]
];
module.exports = {plugins, presets};
Enter fullscreen mode Exit fullscreen mode

Summary

  • If js is imported or required into our source code, then it is also a module. So we have to download the corresponding loader (babel-loader) and configure it in the module configuration.
  • In addition, we need to configure babel-loader and, most importantly, Babel (babel.config.js).

So, if we want to "compile es6+", we need to configure webapck, and most importantly we need to configure babel.config.js. If you don't want to just copy and paste the Babel configuration, you have to learn about Babel.


Remember what we use webpack for? To output css, img, js, html and other front-end resources that the browser can run.

OK, so far we have processed css, img, js through webpack. Let's take a look at how we can get our html through webpack processing.

Processing html files

In the above example, we want to see the effect in the browser, we need to:

  • Create a new html file in the root directory.
  • In the new html file, we need to bring in the packaged resource files manually.

This process is too troublesome, is there a way, we just provide a html template file, and then through the webpack compilation, it automatically help us to pack the packaged files into the good. This way, we can run html directly after packaging and see the effect in the browser.

webpack is so user-friendly, of course there is.

Let's start by using the learn-06 example here to see how we can utilize webpack to achieve the results we described above.

Install the relevant plugins:

npm i html-webpack-plugin -D
Enter fullscreen mode Exit fullscreen mode

This time, the webpack configuration is a little different:
We set the packaged js storage directory to be the js folder; and we add a hash value of 5 lengths to the packaged js name.

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: './js/[name]-[chunkhash:5].js',
        clean: true
    },

    plugins: [
        new HtmlWebpackPlugin({
            filename: path.resolve(__dirname, './dist/[name].html'),
            template: path.resolve(__dirname, './index.html'),
            title: 'HtmlWebpackPlugin',
        })
    ],
}
Enter fullscreen mode Exit fullscreen mode

The structure of the packaged file is:

dist
โ”œโ”€โ”€ index.html
โ””โ”€โ”€ js
    โ””โ”€โ”€ index-efbfd.js
Enter fullscreen mode Exit fullscreen mode

The packaged html is as follows:

compile_html

We will find:

  • Our html and js are packaged and exported to the dist folder, which is very convenient for us to deploy (before we created index.html in the root directory, so there are only img and js files in the dist folder after packaging).
  • The packaged html will automatically bring in our packaged js file for us.

Analyzing

As we can see from the above example, if we want webpack to process html files, we need to configure it in plugins provided by webpack. Some of you may wonder why html is a module and why it is configured in plugins and not in module. Let's analyze it.

All the files of our project can be considered as a module, but whether we configure them in module or plugins depends on what we want to use them for. Generally, if we use the module in our own source code, we need a Loader to parse it**.

When we explained how to deal with img and js above, our purpose was to parse these files in the source code:

  • img, which we need to convert to base64
  • js, we need to compile es6+ stuff into es5 and below

And, our files are introduced into our project by import or require(), so of course we need the appropriate Loader to convert these modules.

But when dealing with html files, our purpose is not to parse the html, we just want the packaged html to automatically reference our js and img, which is more like using the auto-introduction feature; moreover, we don't introduce our html into our project, so of course we don't need the appropriate Loader to parse it.

Remember from our previous post we explained that Loader is used to transform the modules, and Plugin is used to enhance the webpack package when compiling.

In this case, we are dealing with the html file, and our goal is to make the packaged html automatically reference our js and img. So we need to configure the plugins configuration item to enhance the webpack packaging and compilation functionality.

Similarly, suppose we want to parse an html file in our project (in our project, import html from '. /x.html'), then we have to install the appropriate loader (html-loader) and configure it in the module configuration item.

Summary

Whether to configure in the module or plugins configuration item depends on the purpose for which we are using these modules.


At this point, we have successfully configured webpack to get the css, img, js, and html we need for a project; this is also equivalent to learning the basic configuration of webpack.

You can use the methods summarized above to handle sass, font, video and other resources on your own to deepen your impression.

Learning Summary

From the above explanation of some configuration items, we can have the following summary:

  • To parse css, we need to install the loader and configure it in the module.
  • To parse img, font, video, etc., we don't need to install the loader (webpack has built-in functionality to parse them). We usually use asset/resource, asset/inline, asset in module configuration to parse them.
  • To parse js, we need to install the appropriate loader (babel-loader), configure it in the module configuration, and most importantly, learn about Babel.
  • To parse the html file, we need to configure the html-webpack-plugin plugin in the plugins configuration field.
  • Whether we configure it in the module or plugins configuration depends on what we want to do with the modules.

With the above learning, let's organize and output a complete webpack base configuration to make it more impressive:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: './js/[name]-[chunkhash:5].js',
        clean: true
    },
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ],
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 1024 * 10 // When the image size is < 10kb it will be converted to base64
                    }
                },
                generator: {
                    filename: '[name]-[hash:5][ext]' // Set the name of the output file
                }
            },
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: path.resolve(__dirname, './dist/[name].html'),
            template: path.resolve(__dirname, './src/index.html'),
            title: 'Webpack Basic Configuration',
        })
    ],
}
Enter fullscreen mode Exit fullscreen mode

The full base configuration is at learn-07, and we recommend that you take a look at the full version, only webpack.config.js is posted here.

Finally

  • I hope some of the methods summarized in this article for learning purposes will help you learn how to configure webapck better.
  • Later articles will be in-depth configuration. In real projects, most of them are divided into development and production environments, so we will learn how to configure webpack differently for different environments of development and production, which is closer to our real projects.
  • You can support me by following my github!

Regarding the content of the article, if you have similarities and differences, feel free to discuss them in the comments section!

Top comments (0)