Webpack: Loader development sharing

Keywords: Webpack plugin loader Module

Webpack: Loader development sharing

text

1. Concept concept

The concept of Webpack tells us that everything is a Module. However, a complete front-end web page is not only JavaScript, but also other types of files (CSS, HTML, static resources)

Therefore, as a Module Bundler, Webpack divides the whole packaging process into different modules, which are responsible for different tasks. I won't expand it in detail.

What we're going to do today is the so-called Loader. In a word:

Loader is responsible for converting non JS files into JS modules and importing them

For example, we often use it

import './xxx.css'

In fact, such import is not a category that standard JavaScript can understand. Therefore, it is necessary to convert it into a JS module with the help of the ability of Loader and then import it

2. Configuration instance

The official method of configuring Loader in Wwebpack is also written in detail. In short, it is written in the module.rules item of the configuration file

  • webpack.config.js
module.exports = {
  module: {
    rules: [
      // ...
    ]
  }
}

The first method is to configure only a single loader

module.exports = {
  module: {
    rules: [
      {
        test: /\.html$/,
        use: 'html-loader'
      }
    ]
  }
}

To use multiple loader s, you can pass in an array, and the effective order is back to front

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
}

In addition, if you want to pass in configuration parameters for a loader, change the name to an object

module.exports = {
  module: {
    rules: [
      {
        test: /\.module.(sass|scss)$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: {
                localIdentName: '[path][name]__[local]--[hash:base64:5]',
              },
              sourceMap: true,
            },
          },
          'sass-loader',
        ],
      },
    ]
  }
}

As in the last example above, a CSS Module and Sass syntax enabled parsing is configured. It passes through Sass loader, CSS loader and style loader, and is finally introduced into the code

The parameters of modularization scheme are specially configured for CSS loader

3. Custom Loader

So how can we write a loader ourselves? Just like vue wrote a loader to support the parsing of. vue files, it looks like a loser

3.1 configuring a custom Loader

There are many ways to configure a custom loader

  1. The first one: introducing relative paths (when used only once)
const path = require('path');

module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: path.resolve('path/to/loader.js'),
            options: {
              /* ... */
            },
          },
        ],
      },
    ],
  },
};
  1. Second: configure the loader search range (recommended)
const path = require('path');

module.exports = {
  //...
  resolveLoader: {
    modules: ['node_modules', path.resolve(__dirname, 'loaders')],
  },
};

Using the second method, you can write the name directly in the loader attribute

3.2 embedded loader (path assignment)

Of course, the second method must be used when using an inline loader

require('./loader!./lib');

If you write webpack like this, you will know that after loading. / lib, you must first go through the loader conversion

When embedded, you can even configure parameters for the loader

require('./loader1?xyz!loader2!./resource?rrr');

To be honest, the readability is still very poor, so it is usually common in the runtime writing method of loader. It is better to avoid embedding into the path when using it normally

3.3 Loader writing

Next, let's get to the point. How should loader be written.

First look at the module structure

module.exports = function (source) {
  // loader
};

A loader must export a funciton function (the arrow function should not be used here, because webpack will inject the context through this, but I'm not sure hh, this still needs to be learned hh)

There are many kinds of loader returns

  • Synchronize a return value: return output directly
  • Synchronize multiple return values: use this.callback
  • Asynchronous: use callback = this.async()

It's better to check the documents for detailed use. It's boring to write here

4. Actual combat: jsonc loader

Finally, we give an actual operation of loader for parsing jsonc format files

Node supports importing. json files by default, but it is unexpectedly found that jsonc cannot be used, so you can try it. The main task is to delete the comments

  • /loaders/jsonc-loader
const removeComment = (s) => {
  return s.replace(/\/\/.*$/gm, '');
};

const removeWhiteSpace = (s) => {
  return s.replace(/[ \n\t]*/g, '');
};

module.exports = function (source) {
  console.log(`Solve jsonc: '${source}'`);

  const noComment = removeComment(source);
  console.log(`noComment: '${noComment}'`);

  const noWhiteSpace = removeWhiteSpace(noComment);
  console.log(`noWhiteSpace: '${noWhiteSpace}'`);

  const data = JSON.parse(noWhiteSpace);
  console.log(`Parsed data:`, data);

  const res = JSON.stringify(data);
  console.log(`res: ${res}`);

  return `module.exports = ${res}`;
}

It is relatively simple to use regular expressions to delete comments, clean up whitespace, use parse deserialization to ensure correct json format, and finally deserialize and add module.exports as the default export object of the module

After writing the loader, configure it in the configuration file

  • webpack.config.js
const path = require('path');

const config = {
  // ...
  resolveLoader: {
    modules: [path.resolve(__dirname, 'loaders'), 'node_modules'],
  },
  module: {
    rules: [
      {
        test: /\.jsonc/,
        use: 'jsonc-loader',
      },
    ],
  },
};

module.exports = config;

First, the resolveLoader is used to configure the loader directory, and then a rule is added

The final test code is posted a little

  • /src/index.js
console.log('sample', require('./sample.jsonc'));

Then run directly using Node & the result of running after compiling with webpack

  • Node runs the script directly
$ node src/index.js
Hello world
~/webpack_loader_custom_json_parse/src/sample.jsonc:3
  "name": "superfree",
        ^

SyntaxError: Unexpected token ':'
  • Run Webpack after compilation
$ webpack && node dist/main.js

✔ Webpack
  Compiled successfully in 124.86ms

asset main.js 283 bytes [emitted] [minimized] (name: main)
./src/index.js 103 bytes [built] [code generated]
./src/sample.jsonc 70 bytes [built] [code generated]
webpack 5.64.3 compiled successfully in 127 ms
Hello world
sample { name: 'superfree', age: 22, courses: [ 'math', 'cs' ] }

Other resources

Reference connection

TitleLink
Writing a Loader - Webpackhttps://webpack.js.org/contribute/writing-a-loader/
Loader Interface - Webpackhttps://webpack.js.org/api/loaders/
require(id) - Nodehttps://nodejs.org/dist/latest-v16.x/docs/api/modules.html#requireid
JSON Loader - npmhttps://www.npmjs.com/package/json-loader
webpack-contrib/json-loader - Githubhttps://github.com/webpack-contrib/json-loader
Teach you a Webpack Loaderhttps://blog.csdn.net/lszy16/article/details/79162960
Simple and practical webpack HTML include loader (with detailed development explanation)https://cloud.tencent.com/developer/article/1607507

Complete code example

https://github.com/superfreeeee/Blog-code/tree/main/front_end/webpack/webpack_loader_custom_json_parse

Posted by OttoBufonto on Thu, 25 Nov 2021 14:27:53 -0800