Follow the public account “Kite Bearer” for learning resources.

Loader assumes the responsibility of translator, which makes up for the problem that WebPack can only understand JavaScript and JSON files, so that it can process other types of files. Therefore, Loader’s importance to WebPack is self-evident. So learning to build a loader is the only way to learn Webpack. Before learning to write a Loader, it’s important to clarify the loader’s responsibilities: Its responsibilities are single, and only one transformation is required. The following steps illustrate several key points in selecting a Loader for development and implementing one.

I. Loader classification

Loader is a CommonJs-style function. After receiving the input source, loader can process it synchronously or asynchronously and then output the content.

1.1 synchronous Loader

Synchronous loader refers to the synchronized return of converted content. In a single-threaded environment such as Node.js, the conversion process blocks the entire build, making it slow and not suitable for a long environment. For synchronous loaders, there are two main methods to return the converted content: return and this.callback.

  1. Return Use return to directly return the converted result.
module.exports = function(source, map, meta){ // ... // output is the result after processingreturnThe output; }Copy the code
  1. This. Callback this. Callback is more flexible than return and has four main parameters:
this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap? : SourceMap, meta? : any );Copy the code

(1) The first argument is unable to convert the original content, so Webpack will return an Error. (2) The second parameter is the converted content (output content). (3) refers to the source code mapped to the compiled code for easy debugging. In order to obtain the sourceMap in this loader, you need to configure the webpack to be created (for example, babel-loader converts the base ES6 syntax to ES5, using devtool to enable sourceMap) :

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    'test-loader'// the loader is the own loader {loader:'babel-loader',
                        options: {
                            presets: [
                                '@babel/preset-env'
                            ]
                        }
                    }
                ]
            }
        ]
    },
    devtool: 'eval-source-map',}Copy the code

(4) It can be anything. If this parameter is output, it can be obtained and used in the next loader. For example, the AST can be shared among loaders to accelerate compilation time.

Callback returns the result of passing multiple arguments using this.callback.

module.exports = function(source, map, meta) {// Output const output = dealOperation(source);
    this.callback(null, output, map, meta);
}
Copy the code

1.2 the asynchronous Loader

A synchronous Loader is only suitable for scenarios with small computing load and high speed. However, for scenarios (such as network requests) with large computing load and high time consumption, a synchronous Loader blocks the entire construction process and slows down the construction speed. This problem can be avoided by using an asynchronous Loader. For asynchronous loaders, use this.async() to get a callback function that takes the same arguments as this.callback.

module.exports = function(content, map, meta) {// Get callback function const callback = this.async(); / / usesetTimeout simulates the asynchronous processsetOutput const output = dealOperation() const output = dealOperation()source); callback(null, output, map, meta); }}, 100)Copy the code

Type of file after conversion

By default, the converted resource files are all strings encoded in UTF-8 format. However, the converted image files are in binary format. To enable the Loader to accept binary resources, set raw (using image resources as an example).

// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    'url-loader'.'raw-test-loader',// own loader]}]}}Copy the code
// raw-test-loader.js
module.exports = function(source, map, meta) {// Process input resources const output = dealOperation(source);
    returnoutput; } // This property tells Webpack whether the loader needs binary data module.exports.raw =true;
Copy the code

A. options B. options C. options D. options

For webpack configuration, loader usually has some options parameters. To obtain the options parameters of a loader written by yourself, it is recommended to use the loader-utils package to obtain the options parameters and process the parameters in loader.

const loaderUtils = require('loader-utils');

module.exports = function (source, map, meta){// getOptions const options = loaderutils.getoptions (this); const output = dealOperation(source);
    
    return output;
}
Copy the code

4. Cache or not

The conversion operation is computationally intensive and time-consuming, and each rebuild makes the build process very slow. Webpack caches the results of all Loader processes by default, that is, to process files and their dependencies without changing their cache (note that loader should not have any external dependencies other than those specified in this.addDependency). This. Cacheable controls whether it is cached or not.

module.exports = function(source, map, meta) {// Disable the cache this.cacheable(false);
    return source;
}
Copy the code

Implement a loader

This section is the actual loader, write a loader for letter case conversion, using the loader can realize the conversion of letters in the TXT file case, the loader content and webpack.config.js related configuration as shown below (see github code for details)

// format-letters-loader.js
const loaderUtils = require('loader-utils');

const Lowercase2Uppercase = 'L2U';
const Uppercase2Lowercase = 'U2L';

module.exports = function (source, map, meta) {
    let output = ' '; // getOptions const options = loaderutils.getoptions (this); const { formatType } = options; switch(formatType) {case Lowercase2Uppercase: {
            output = source.toUpperCase();
            break;
        }
        case Uppercase2Lowercase: {
            output = source.toLowerCase();
            break;
        }
        default: {
            output = source;
        }
    }

    this.callback(null, output, map, meta);
};
Copy the code
// webpack.config.js
module.exports = {
    // ...
    module: {
        rules: [
            {
                exclude: /\.(css|js|html|png|jpg|gif)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[ext]',
                            outputPath: 'asset',
                        }
                    },
                    {
                        loader: 'format-letters-loader',
                        options: {
                            formatType: 'U2L'},]}]}, // Parsing the loader package is set to how modules are parsed resolveLoader: {modules: ['./node_modules'.'./loader'],// tells Webpack what directory to search for when parsing the loader. }},Copy the code

Note: this article is just to play a role, hope you big guy give advice.

Related chapters illustrated Webpack———— Basics illustrated Webpack———— optimization

Welcome to follow the public account (reply “Simple Webpack” to get the PDF version of simple Webpack, reply “WebPack04” to get the mind map of this section)