Implement a webpack loader and a webpack plugin

Time:2021-9-28

loader

Definitions on the official website:

Loader is a converter used to convert source code.

for examplebabel-loaderES6 code can be converted to Es5 code;sass-loadertakesassCode conversion tocsscode.

The configuration code of general loader is as follows:

module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    //The loader is executed from bottom to top
                    {
                        loader: path.resolve('./src/loader2.js'),
                    },
                    {
                        loader: path.resolve('./src/loader1.js'),
                    },
                ]
            }
        ]
    },

The rules array contains matching rules and specific loader files.

In the above codetest: /\.js$/Is the matching rule, which means that the following two loaders are used for JS files.

The processing order of loader is from bottom to top, that is, first use loader1 to process the source code, and then transfer the processed code to loader2.

The code processed by loader2 is the final packaged code.

Implementation of loader

Loader is actually a function. Its parameters are the source code of the matching file, and the return result is the processed source code. The following is the simplest loader, which does nothing:

module.exports = function (source) {
    return source
}

Such a simple loader is not challenging. We can write a slightly more complex loader tovarReplace keyword withconst

module.exports = function (source) {
    return source.replace(/var/g, 'const')
}

After writing, let’s test it. The test file is:

function test() {
    var a = 1;
    var b = 2;
    var c = 3;
    console.log(a, b, c);
}

test()

wepback.config.jsThe configuration file is:

const path = require('path')

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: path.resolve('./src/loader1.js'),
                    },
                ]
            }
        ]
    },
}

functionnpm run build, get the packaged filebundle.js, let’s take a look at the packaged Code:

eval("function test() {\r\n    const a = 1;\r\n    const b = 2;\r\n    const c = 3;\r\n    console.log(a, b, c);\r\n}\r\n\r\ntest()\n\n//# sourceURL=webpack:///./src/index.js?");

As you can see, thevarHas becomeconst

Asynchronous loader

The loader just implemented is a synchronous loader, which is used after processing the source codereturnreturn.

Let’s implement an asynchronous loader:

module.exports = function (source) {
    const callback = this.async()

    //Due to the 3-second delay, it takes 3 + seconds to pack
    setTimeout(() => {
        callback(null, `${source.replace(/;/g, '')}`)
    }, 3000)
}

The asynchronous loader needs to call the of webpackasync()Generate a callback whose first parameter iserror, which can be set asnull, the second parameter is the processed source code. When you asynchronously process the source code, call it.callbackJust.

Let’s try whether the asynchronous loader is effective or not. Here, a 3-second delay is set. Let’s compare the packing time:

Implement a webpack loader and a webpack plugin
Implement a webpack loader and a webpack plugin
The above figure shows the packaging time of calling the synchronous loader, which is 141 MS; The following figure shows the packaging time of calling asynchronous loader, which is 3105 MS, indicating that the asynchronous loader is effective.

If you want to see the complete demo source code, please click on my GitHub.

plugin

Webpack will trigger many different events in the whole compilation cycle. The plugin can listen to these events and call the API of webpack to process the output resources.

This is the difference between it and loader. Generally, loader can only convert the source file code, while plugin can do more. Plugin can be called throughout the compilation cycle as long as it listens for events.

For webpack compilation, there are two important objects to understand:

Compiler and compilation
The two most important resources in plug-in development are compiler and compilation object. Understanding their roles is an important first step in extending the webpack engine.

The compiler object represents the complete configuration of the webpack environment. This object is created at one time when starting the webpack, and all operable settings are configured, including options, loader and plugin. When a plug-in is applied in a webpack environment, the plug-in will receive a reference to the compiler object. You can use it to access the main environment of webpack.

The compilation object represents a resource version build. When running the webpack development environment middleware, whenever a file change is detected, a new compilation will be created to generate a new set of compilation resources. A compilation object represents the current module resources, compilation generated resources, changed files, and state information that is tracked and dependent. The compilation object also provides many callbacks at critical times for the plug-in to choose when doing custom processing.

These two components are an integral part of any webpack plug-in (especially compilation), so developers will benefit a lot after reading the source code and becoming familiar with them.

Implementation of plugin

Let’s take a look at the definition of the official website. The webpack plug-in consists of the following parts:

  1. A JavaScript named function.
  2. Define an apply method on the prototype of the plug-in function.
  3. Specify an event hook bound to the webpack itself.
  4. Process specific data for webpack internal instances.
  5. The callback provided by webpack is called after the function is completed.

Simply put, a function with an apply method is a plug-in, and it wants to listen to an event of webpack. Here is a simple example:

function Plugin(options) { }

Plugin.prototype.apply = function (compiler) {
    //This event is triggered after all file resources are processed by the loader
    compiler.plugin('emit', function (compilation, callback) {
        // after the function completes, call the callback provided by webpack.
        console.log('Hello World')
        callback()
    })
}

module.exports = Plugin

How to call after writing the plug-in?

First introduce the plug-in in the webpack configuration file, and then configure it in the plugins option:

const Plugin = require('./src/plugin')

module.exports = {
    ...
    plugins: [
        new Plugin()
    ]
}

This is a simple plug-in.

Now let’s write a more complex plug-in, which is used to package the files processed by the loaderbundle.jsIntroduced intoindex.htmlMedium:

function Plugin(options) { }

Plugin.prototype.apply = function (compiler) {
    //This event is triggered after all file resources are processed by different loaders
    compiler.plugin('emit', function (compilation, callback) {
        //Get the packaged JS file name
        const filename = compiler.options.output.filename
        //Generate an index.html and import the packaged JS file
        const html = `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script></script>
</head>
<body>
    
</body>
</html>`
        //All processed resources are placed in compilation.assets
        //Add an index.html file
        compilation.assets['index.html'] = {
            source: function () {
                return html
            },
            size: function () {
                return html.length
            }
        }

        // after the function completes, call the callback provided by webpack.
        callback()
    })
}

module.exports = Plugin

OK, execute it and see the effect.

Implement a webpack loader and a webpack plugin
Perfect, as like as two peas.

Complete demo source code, please see my GitHub.

To learn more about events, please refer to the official website to introduce the compiler hook.

reference material

  • Write a loader
  • Write a plug-in

Recommended Today

Blog Garden Background page dynamic effects

1. To set animation, you must first apply for permission 1.1 first enter [my blog park] and enter [settings] in [management] 1.2 find [blog sidebar announcement] and click [apply for JS permission] 1.3 write the content of application JS permission (examples are as follows) Dear blog administrator: Can you open JS permission for me? I […]