Introduction to the Webpack Build Process

The core concept of webpack

  • Entry: Entry, the first entry of webpack execution and construction, which can be abstractly understood as input
  • Module: Module, everything in webpack is a module, a module corresponds to a file, webpack will start from the configured Entry, recursion finds all dependent modules.
  • Chunk: Code Block, a chunk is composed of multiple modules for code merging and splitting.
  • Loader: Module converter, used to convert the metadata of the module into new content as required.
  • Plugin: extension plug-in, broadcast corresponding events at specific times in the webpack build process, plug-in can listen to these events and do corresponding things at specific times.

webpack

Previous article first参考文章Pictures in

For a piece of code with the same logic, when we write a file by hand, whether it is ESM or commonJS or AMD, they are all ** modules **;

When the module source file we write is sent to webpack for packaging, webpack will generate a ** chunk ** file according to the file reference relationship, and webpack will perform some operations on this chunk file;

After webpack processes the chunk file, it will finally output the ** bundle ** file. This bundle file contains the final source file that has been loaded and compiled, so it can be run directly in the browser.

Generally speaking, a chunk corresponds to a bundle, such as’utils.js - > chunks 1 - > utils.bundle.js’ in the above figure; but there are exceptions. For example, in the above figure, I used’MiniCssExtractPlugin ‘to extract the’index.bundle.css’ file from chunks 0.

Webpack build process analysis

Webpack source code is a plugin architecture, many functions are achieved through many built-in plugins. Webpack specifically writes a plugin system for this purpose, called’Tapable ', which mainly provides the functions of registering and calling plugins.

The workflow of webpack

Webpack is a serial process. From startup to completion, the following process will be executed in sequence

  • Initialization parameters: Merge parameters from shell parameters and configuration files to obtain final parameters
  • Start compile: initialize the compiler object with the parameters obtained from the previous step, load all plugins, and execute compile through the run method.
  • identify entries: find all entry files based on the configuration file entries.
  • compile module: start from the entry file, call all configured loaders to translate the module into compliation, then recursion all dependent modules, and then repeat compile. Get the final translated content of each module and their dependencies.
  • Output resources: Assemble chunks containing multiple modules according to the dependencies of the entry and the module, and then convert the chunk into a separate file to join the output list. This is the last chance to modify the output content
  • Output complete: After determining the output content, determine the output path and file name according to the configuration, and write the content of the file to the file system.

img

WebPack compiles the flowchart, the original picture is from:blog.didiyun.com/index.php/2…

In the above process, webpack will broadcast specific events at specific time points, and the plugin will execute specific logic after listening to the events of interest and change the running results of webpack.

这篇文章会从源码级别讲解流程,有兴趣或者有需要可以回头看。

Understanding the Event Stream Mechanism

'Webpack 'is essentially an event flow mechanism, and its workflow is to connect various plugins, and the core of all this is Tapable.

Webpack’s Tapable event streaming mechanism ensures the orderliness of the plugin, concatenates each plugin, Webpack will broadcast events during operation, and the plugin only needs to listen to the events it cares about to join this webapck mechanism, to change the operation of webapck, making the entire system scalable.

‘Tapable ‘is also a small library and a core tool of’Webpack’. Similar to the’events’ library in’node ', the core principle is a subscription publishing mode. The role is to provide a similar plugin interface.

The core’Compiler ‘responsible for compiling and’Compilation’ responsible for creating bundles in webpack are both instances of Tapable, which can broadcast and listen to events directly on the’Compiler ‘and’Compilation’ objects. The methods are as follows:

1
2
3
4
5
6
7
8
9
10
11
/**
* Broadcast events
* Event-name is the name of the event, be careful not to duplicate the name of an existing event
*/
compiler.apply('event-name',params);
compilation.apply('event-name',params);
/**
* Monitoring incidents
*/
compiler.plugin('event-name',function(params){});
compilation.plugin('event-name', function(params){});

The Tapable class exposes the tap, tapAsync, and tapPromise methods, which allow you to select a function to inject logic based on the synchronous/asynchronous mode of the hook.

'Tap 'sync hook

1
2
3
compiler.hooks.compile.tap('MyPlugin', params => {
Console.log ('Touch compile hook synchronously.')
}

'tapAsync ‘asynchronous hook, tell’Webpack’ to complete asynchronous execution through’callback ‘callback’tapPromise’ asynchronous hook, return a’Promise ‘to tell’Webpack’ to complete asynchronous execution

1
2
3
4
5
6
7
8
9
10
compiler.hooks.run.tapAsync('MyPlugin', (compiler, callback) => {
Console.log ('Touch run hook asynchronously.')
callback()
})

compiler.hooks.run.tapPromise('MyPlugin', compiler => {
return new Promise(resolve => setTimeout(resolve, 1000)).then(() => {
Console.log ('hit run hook asynchronously with delay')
})
})

Tapable usage

1
2
3
4
5
6
7
8
9
10
11
const {
SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
AsyncParallelHook,
AsyncParallelBailHook,
AsyncSeriesHook,
AsyncSeriesBailHook,
AsyncSeriesWaterfallHook
} = require("tapable");

tapable

Simple implementation of a

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Hook{
constructor(args){
this.taps = []
This. interceptors = [] // this for the back
this._args = args
}
tap(name,fn){
this.taps.push({name,fn})
}
}
class SyncHook extends Hook{
call(name,fn){
try {
this.taps.forEach(tap => tap.fn(name))
fn(null,name)
} catch (error) {
fn(error)
}

}
}
Copy the code

How does tapable associate webapck/webpack plugins?

Compiler.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const { AsyncSeriesHook ,SyncHook } = require("tapable");
//Create a class
class Compiler {
constructor() {
this.hooks = {
Run: new AsyncSeriesHook (["compiler "]), // asynchronous hook
Compile: new SyncHook (["params"]),//sync hook
};
},
run(){
//perform asynchronous hook
this.hooks.run.callAsync(this, err => {
this.compile(onCompiled);
});
},
compile(){
Execute synchronization hook and pass parameters
this.hooks.compile.call(params);
}
}
module.exports = Compiler

MyPlugin.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const Compiler = require('./Compiler')

class MyPlugin{
Apply (compiler) {//Accept compiler parameters
compiler.hooks.run.tap("MyPlugin", () => console.log('开始编译...'));
//Add a method in the run phase
compiler.hooks.complier.tapAsync('MyPlugin', (name, age) => {
setTimeout(() => {
Console.log ('compiling...')
}, 1000)
});
//Add method in compier stage
}
}

//This is similar to the plugins configuration of webpack.config.js
//pass a new instance to the plugins property

const myPlugin = new MyPlugin();

const options = {
plugins: [myPlugin]
}
let compiler = new Compiler(options)
compiler.run()

If you want to learn more about’tapable ', you can take a look at this article:

'Webpack4 ‘core module’tapable’ source code parsing: https://www.cnblogs.com/tugenhua0707/p/11317557.html

Summary

In general, the packaging of webpack is divided into several stages, similar to the life cycle. Events can be issued at the beginning and end of each life cycle. The loader is used in the compile stage to compile files of the type we specify.

So as mentioned earlier, the build process of webpack is event-based. For webpack, its event issuance and subscription depend on the Tapable class. Our Plugin is actually a Tapable class, and the compiler we use Or compilation is the built-in Plugin.

We can use the apply and plugin methods of the Tapable class to issue and subscribe to events. Since complier itself is a Tapable, it can apply and plugin events itself, and we add function to complier hooks through a method similar to tap, which is equivalent to listening to the event issued by the hooks.

Reference article:

webpack构建流程分析

webpack 中那些最易混淆的 5 个知识点

揭秘webpack插件工作流程和原理

webpack插件编写及原理解析