“This is the fifth day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

In the last article “WebPack 5 tutorial 1: Introduction to Webpack”, we explained the simple use of Webpack, and successfully loaded and compiled JS module. This article will use the asset Module and Loader to realize the loading and compilation of other types of modules.

By default, Webpack only supports loading js modules. If other modules are loaded without additional configuration, an error will be reported during the runtime.

    // index.js
    import logoUrl from './assets/logo.png'
    const logo = new Image();
    logo.src = logoUrl
    document.body.appendChild(logo)
Copy the code

The console reports the following error when running Webpack directly because webPack does not recognize the image resource

Webpack treats all resource files as one module, and all modules except JS need to set the corresponding Rule to handle them properly. So let’s have a general idea of how to write each Rule:

    {
        module: {rules:[
                {
                    // Module loading rules}}}]Copy the code

The common attributes of each Rule are as follows:

  • test: matches the regular expression of the resource file, the above code is matchpngThe picture
  • type: Sets the resource module type
  • use/loader: Sets the loader. The type can beString | Object | Array
  • generator: Sets the resource generation information
    • filename: Sets the output name of the resource file and the path to save itasset 和 asset/resourceScenarios)
  • include/exclude: Manually add files (folders) that must be processed or mask files (folders) that do not need to be processed.

Let’s use the simplest way to solve this problem — asset Module

Asset Module

Asset Module is a module type that allows you to introduce other resource files (fonts, images, styles, etc.) into YOUR JS code, which previously could only be implemented through the loader. In Webpackage 5, asset Module is easily implemented.

Webpack5 implements four new module types via the Rule’s type attribute:

  • asset/resourceOutput a single file and export the URL. Previously by usingfile-loaderThe implementation.
  • asset/inlineExport the data URI of a resource. Previously by usingurl-loaderThe implementation.
  • asset/sourceExport the source code of the resource. Previously by usingraw-loaderThe implementation.
  • assetAutomatically choose between exporting a dataURI and sending a separate file. Previously by usingurl-loaderAnd configure the resource volume limitation implementation.

Next we fix the problem with the resource module, adding a Rule: match PNG images and output individual files

    // webpack.config.js
    module.exports = {
        // ...
        module: {rules:[
                {
                    test:/\.png$/,
                    type:'asset/resource'}}}]Copy the code

Run WebPack based on the above configuration, the console compits successfully, and you get an image file in the output directory dist

If set to Asset /inline, the image’s dataURI (base64 encoding) will be written to the packaged JS file, which will reduce the number of HTTP requests for the page and speed up page rendering

However, not all images are suitable for this method, because the more complex the image, the more base64 encoding is generated, and the overall size of the image can even exceed the size of the image itself (72.7KB compared to 52kB), so sometimes we want Webpack to help us adjust automatically. This is where the type:”asset” configuration is used.

If set to asset, it is automatically selected between Asset/Inline and Asset/Resource depending on the size of the image

Default is greater than 8 KB export file alone, less than or equal to 8 KB export dataURI (by Rule of the parser. DataUrlCondition. MaxSize to set, the unit is: Byte bytes)

     module: {rules:[
            {
                test:/\.png$/,
                type:'asset'.parser: {dataUrlCondition: {maxSize:1024*20.// 20KB
                    }
                `} `}}]Copy the code

Other types of effect you can test your own friends, how about, is not cool to no friends?

Modify the output file name and path of the resource module

If you want to change a specific filename, you can use generator.filename to set the filename and save path of the resource, similar to output.filename. File names can also be controlled by variables such as the [name] original file name, the [hash] hash character, and the [ext] extension

The property and the output. The assetModuleFilename identical, but the generator. The filename of the higher priority

    module: {rules:[
            {
                test:/\.png$/,
                type:'asset/resource'.generator: {filename:'img/[name]-[hash][ext]'}}}]Copy the code

Loader

In addition to the resource module mode, you can also use Loader to implement other types of resources, different resources apply different Loader (Loader needs to be installed separately), and then in the Webpack configuration file through the module.rules. Rule set the use or loader attribute (loader is short for use)

Using the loader generally requires two steps, as follows:

  1. Install the loader

    If the loader depends on other modules, install them as well

  2. Write the Rule and configure the Loader

    If you need to configure the loader in some detail, add options

1. CSS loader

css-loader

Take the CSS file module as an example. Assume that the CSS file style needs to be introduced into the code as follows:

    // index.js
    import './css/home.css'
Copy the code

Add a few simple CSS properties to the style:

    /*./css/home.css*/ 
    body {
      padding: 20px;
      margin: 0;
      color:#f00;
    }
Copy the code

To properly process the style file, install the csS-loader module:

    npm install css-loader
Copy the code

To configure the style loader in webpack.config.js, the file code is as follows:

     module.exports = {
        // ...
        module: {rules:[
                {
                    test:/\.css$/,
                    use:'css-loader'./ / or loader: 'CSS - loader'}}}]Copy the code

After webpack is executed, the style code is eventually packaged into a JS file

style-loader

But in the actual development, if we only such configuration, we are unable to see the final page style effect, the reason is very simple, style, now just write js file, and not used in the page, style to take effect in the page, we have to use the style – loader loader label the CSS code into the page style, in the same way, Install the module first

    npm install style-loader
Copy the code

Since there are two loaders, we need to use the array, pay attention to the order of use: Webpack uses the loader from back to front, the final configuration code is as follows:

     module.exports = {
        // ...
        module: {rules:[
                {
                    test:/\.css$/,
                    use:['style-loader'.'css-loader'].// use csS-loader first and then style-loader}}}]Copy the code

We can see the effect by importing the packaged main.js file with an HTML file and writing the style to the page’s style tag

CSS Module

If you need to implement some advanced functions, you also need to configure the corresponding parameters for these loaders. At this time, the loaders need to be set using objects. For example, to implement the CSS module, you can use the following Settings

    rules:[
        {
            test:/\.css$/,
            use:[
                'style-loader',
                {
                    loader:'css-loader'.options: {modules:true}}]}]Copy the code

To see the CSS module effect, add a few styles to the home.css file

    body {
      padding: 20px;
      margin: 0;
      color:#f00;
    }
    .box{color:#58bc58; }.msg{background-color:#efefef; }Copy the code

Once set, we can use the following code to load the style and use it when introducing styles

    import homeStyle from './css/home.css console.log(homeStyle)Copy the code

The output effect is as follows:

With these advanced Settings in the loader, we can apply styles to the page in JS via homestyle.msg to achieve a local style effect

PS: css-loaderThe default support*.module.cssThe format of the style file implements modularity, which means that if your file is named that way, which is not configuredmodules:true, can also realize the CSS modularization

2, postcss – loader

Work with autopreFixer and Browserslist to automatically add browser kernel prefixes for style-compatible writing. Click here)

  1. Start by installing the loader and dependencies
    npm install postcss-loader autoprefixer
Copy the code
  1. configurationbrowserslist(can be inpackage.jsonor.browserslistrcIn the configuration)
    // package.json
    {
        "browserslist": [
            "last 2 versions"."1%" >."not IE 11"]}Copy the code
    # .browserslistrc
    last 2 versions
    > 1%
    not IE 11
Copy the code
  1. Webpack configuration
    rules:[
        {
            test:/\.css$/,
            use:[
               'style-loader'.'css-loader',
               {
                   loader:'postcss-loader'.options: {postcssOptions: { 
                           plugins: ['autoprefixer'}}}]}Copy the code
  1. Writing style
    .box{display:flex;color:#58bc58;border-radius: 5px; }Copy the code

The compiled effect is automatically prefixed, as shown below:

3. Sass loader

If you use SASS to write styles, you need to configure the Sass-loader, which depends on the SASS module, so you need to install it as well

    npm install sass-loader sass
Copy the code

The Webpack configuration is as follows:

    rules:[
        {
            test:/\.scss$/,
            use:['sass-loader']}]Copy the code

Running the Webpack console throws an error

As the error message says, the reason is simple, we need a loader to process the SASS result, that is, sASS is compiled to CSS without adding a CSS loader to process it, so the solution is also simple: add csS-Loader

    rules:[
        {
            test:/\.scss$/,
            use:['css-loader','sass-loader']
        }
    ]
Copy the code

If you need to export CSS to a page style tag, go ahead and add style-loader

    rules:[
        {
            test:/\.scss$/,
            use:['style-loader','css-loader','sass-loader']
        }
    ]
Copy the code

This solves the problem of compiling sASS code, as well as less (requiring less-loader and less), which will not be described here

4, Babel – loader

For handling JS modules, Webpack already supports loading JS modules by default, so why do we need to configure additional JS loaders? The reason for this is simple: we may use some new ES6+ features when we write JS code. These new features may not be supported by browsers, so we need to use Babel to convert this code, usually to ES5 code.

The first step is to install the babel-loader, which relies on @babel/core

    npm install babel-loader @babel/core
Copy the code

The next step is to configure the loader, but specifying the loader name is meaningless because Webpack already defaults to loading js modules, so we use objects to control the loader details (options properties).

    rules:[
        {
            test:/\.js$/.// use:'babel-loader', 
            use:{
                loader:'babel-loader'.options: {/ / the Babel - loader option}}}]Copy the code

For example, if you want to convert ES6+ code into ES5 code supported by all browsers, you need Babel. However, there are many new ES6+ features, and each new feature requires a Babel plug-in to convert. So Babel releases preset to fix this problem. Preset is actually a set of plug-ins (including multiple plug-ins internally), and @babel/preset-env is a preset to fix browser compatibility issues. It’s easy to use, preset is installed first

    npm install @babel/preset-env
Copy the code
  • What is a plugin? Babel is built on top of plug-ins. A transformation pipeline can be formed using existing or self-written plug-ins. A set of plug-ins can be easily used by using a preset
  • What is preset? You can think of it as a collection of Babel plug-ins;

Configure the Babel option and set env default, which will convert all new ES6+ (ES2015 to ES2022) features by default

    rules:[
        {
            test:/\.js$/,
            use:{
                loader:'babel-loader'.options: {presets: ['@babel/preset-env'}}}]Copy the code

Here is the output effect of setting @babel/preset-env and preset not set

We can also compile according to the specified environment, which would use the options of @babel/preset-env (the second parameter of the array is needed).

    rules:[
        {
            test:/\.js$/,
            use:{
                loader:'babel-loader'.options: {presets: [// Use arrays
                        [
                            '@babel/preset-env',
                            {
                                // The second element of the array is the env option},]}}}]Copy the code

The common options for @babel/preset-env are as follows:

  • targets: Specify the target environment (String | Object | Array), when not specified according tobrowserlistConfiguration (.browserlistrcorpackage.jsonTo be compatible with the target environment

    If the Object type is specified, the browser or other environment can be specified, such as Chrome, Opera, Edge, Firefox, Safari, Ie, ios, Android, Node, electron

        {
            // Specify browsers with more than 0.25% market share (not recommended, will result in IE6 support)
            targets:"> 0.25%, not dead." ".// Recommended: compatible with the last two versions of all browsers
            targets:"last 2 versions"
            
            // Object notation
            targets: {// Specify the browser version
                "chrome": "58"."ie":"11"."edge":"last 2 versions"."firefox":"5%" >.// Specify nodejs version. Current is the current running node version
                "node":"current"}},Copy the code
  • spec: Enables more canonical conversions, but slower, and defaults to false
  • loose: Whether to enable loose mode (default: false)

    For example, whether to make attributes in the stereotype enumerable, add attributes in loose mode using dot syntax, and add attributes in normal mode through Object.defineProperty() to ensure that attributes are not enumerable

  • modulesConvert ES Modules to other module specifications,

    Values can be as follows: adm | umd | systemjs | commonjs | CJS | false (the default)

  • debug: Indicates whether to enable the debug mode. The default value is false
  • useBuiltInsConfiguration:@babel/preset-envHow to deal withpolyfills, there are three options

    By default, @babel/preset-env cannot compile some built-in objects (such as: Promise, Map, Set, etc.), the result is the same as the output, but some of the code does not support Promise, Map, Set environment will throw an error, so you need to use core-js library for processing ([email protected] before using @babel/polyifll, Core-js is now recommended.)

    • entry: Introduces incompatibilities based on the configured browser compatibilitypolyfill. It needs to be added manually in the entry fileimport '@babel/polyfill', will automatically based onbrowserslistReplace it with anything the browser isn’t compatible withpolyfill
          // If 'corejs: 3' is specified, 'import '@babel/polyfill' in the import file needs to be changed
          import 'core-js/stable';
          import 'regenerator-runtime/runtime';
      Copy the code
    • usageThis will depend on the browser compatibility configured and the API used in your codepolyfillTo implement on-demand add-ons, the benefit is that the final package will be smaller
    • false(Default) : Incorrect at this timepolyfillDo the operation. If the introduction of@babel/polyfill, ignore configured browser compatibility and import allpolyfill
  • corejs: Specifies the corejs version (default:2.0), currently in usecore-js@2orcore-js@3Version requires manual installation
    {
        / /...
        corejs:'3.8'.// or object form: {version:'3.8'}
    }
    Copy the code

Use the code

If I now want to be compatible with the last 2 versions of the browser, and with built-in objects like Promise as needed, the steps are as follows:

  1. Install the core – js @ 3

        npm install core-js@3
    Copy the code
  2. Webpack configuration: Only the babel-Loader configuration is listed here

    {
        test:/\.js$/,
        use:{
            loader:'babel-loader'.options: {presets:[
                    [
                        '@babel/preset-env',
                        {
                            targets:'last 2 versions'.useBuiltIns:'usage'.corejs:3}]}}Copy the code
  1. Add the following code to the entry file

        import 'core-js/stable';
        import 'regenerator-runtime/runtime';
    Copy the code
  2. Compile the code

    The final code can then be printed by executing the following command from the command line (the screenshots will not be taken because there is too much code)

        npx webpack
    Copy the code

There are many plug-ins and presets for Babel (@babel/preset- React, @babel/preset-typescript, etc.) that can help us realize even more needs. Check out Babel’s official website and follow my other articles about Babel.

5. Other loaders

In the Webpack ecosystem, there are many such resource loaders, here I just do a starting point, the use of other loaders is similar to CSS-loader, style-loader, sass-loader, babel-loader, the following list of common loaders. Friends can search according to their own needs

  • Url-loader: optimized loader for resource files. It can solve the problem of reference path of resource files such as images, and can save small images as a dataURI according to limit Settingsfile-loader
  • Ts-loader: Loads and compiles typescripttypescript
  • Less-loader: loads and compiles less and relies on itless
  • Vue-loader: loads and compiles.vueSingle file component
  • .

conclusion

In this article, we learned how to use resource module and loader solve the problems of the resource file is loaded and compilation, you can see from the article, resources module is Webpack out-of-the-box way, is a way of dealing with resource file is simple, but if you need a resource file for more specific treatment is recommended way of loader.

So far, we have only been able to compile and package resource modules into a JS file. How to show the packaging effect will be explained in the next article, please pay attention to it