What is the use of webPack plug-ins
Webpack plug-ins are used to handle functions that cannot be completed by Loader. Loader is used for the conversion of module source code, while plug-ins can access every link of compilation through the hooks provided by Webpack to realize the extension of Webpack functions.
Implementation of the WebPack plug-in
Plugins must be an object that has an apply method. The compiler object is passed in as the first parameter to the apply method. Compiler. hooks provide hooks for every link in webPack compilation.
Here is a simple implementation of the official plug-in:
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) = > {
console.log('The WebPack build process begins! '); }); }}module.exports = ConsoleLogOnBuildWebpackPlugin;
Copy the code
In my tests, the following works, but sometimes we want to pass some configuration to the plug-in, so we need to use the class approach.
module.exports = {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) = > {
console.log('The WebPack build process begins! '); }); }};Copy the code
Or a function, which WebPack calls with the call method, and you can see that it resets the context (this) to compiler;
plugin.call(compiler, compiler);
Copy the code
Form of the Node API
Plugins can also be called using new Webpack.Progressplugin ().apply(compiler).
const webpack = require('webpack'); // Access the WebPack runtime
const configuration = require('./webpack.config.js');
let compiler = webpack(configuration);
new webpack.ProgressPlugin().apply(compiler);
compiler.run(function (err, stats) {
// ...
});
Copy the code
Tapable
Tapable is one of the core tools of WebPack. Many objects inside WebPack are extended from the Tabable class, exposing methods such as TAP, tapAsync, and tapPromise, which plug-ins can use to access each step of the compilation to achieve custom functionality.
As shown below, Tapable exposes several synchronous and asynchronous Hook classes.
const {
SyncHook, // Synchronous hooks
SyncBailHook, // Synchronous fuse hook
SyncWaterfallHook, // Synchronous flow hook
SyncLoopHook, // Synchronize loop hooks
AsyncParallelHook, // Asynchronous concurrent hooks
AsyncParallelBailHook, // Asynchronous concurrent fuse hook
AsyncSeriesHook, // Asynchronous serial hooks
AsyncSeriesBailHook, // Asynchronous serial fuse hook
AsyncSeriesWaterfallHook // Asynchronous serial pipeline hook
} = require("tapable");
Copy the code
An example of SyncHook
SyncHook is a synchronous hook that calls the callbacks registered by tap in turn after calling call.
const { SyncHook } = require('tapable');
const hook = new SyncHook(['name']);
hook.tap('hello', (name) => {
console.log(`hello ${name}`);
});
hook.tap('hello again', (name) => {
console.log(`hello ${name}, again`);
});
hook.call('world');
// hello world
// hello world, again
Copy the code
An example of SyncBailHook
Similar to SyncHook, but if the value returned in the registered callback is not undefined, then none of the later registered callbacks will be executed.
const { SyncBailHook } = require('tapable');
const hook = new SyncBailHook(['name']);
hook.tap('hello'.(name) = > {
console.log(`hello ${name}`);
return false;
});
hook.tap('hello again'.(name) = > {
console.log(`hello ${name}, again`);
});
hook.call('world');
// hello world
Copy the code
An example of SyncLoopHook
The callback function registered by SyncLoopHook will continue execution if the value returned is not undefined.
As you can see, hello world is printed three times before hello World again.
const { SyncLoopHook } = require('tapable');
const hook = new SyncLoopHook(['name']);
let index = 0;
hook.tap('hello'.(name) = > {
console.log('hello ' + name + ' ' + index);
return ++index === 3 ? undefined : true;
});
hook.tap('hello again'.(name) = > {
console.log('hello ' + name + ' again');
});
hook.call('world');
// hello world 0
// hello world 1
// hello world 2
// hello world again
Copy the code
An example of SyncWaterfallHook
In the registered callback, if there is a return value, it will be used as an argument to the next registered function.
const { SyncWaterfallHook } = require('tapable');
const hook = new SyncWaterfallHook(['name']);
hook.tap('hello'.(name) = > {
console.log('hello ' + name);
return 'again';
});
hook.tap('hello again'.(name) = > {
console.log('hello ' + name);
});
hook.call('world');
// hello world
// hello again
Copy the code
An example of AsyncParallelHook
Synchronous hooks can only register callbacks through TAP, while asynchronous hooks can register callbacks through TAP, tapAsync, and tapPromise.
Asynchronous hooks must be called using either callAsync or promise.
const { AsyncParallelHook } = require('tapable');
const hook = new AsyncParallelHook(['name']);
console.time('cost');
hook.tap('greeting'.function(name) {
console.log(`hello ${name}`);
});
hook.tapAsync('greeting again'.function(name, cb) {
setTimeout(function() {
console.log(`hello ${name} again`);
cb();
}, 1000);
});
hook.tapPromise('greeting again again'.function(name) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(`hello ${name} again again`);
resolve();
}, 1000);
});
});
// hook.call('world'); // TypeError: hook.call is not a function
// hook.callAsync('world', function() {
// console.timeEnd('cost');
// });
// hello world
/ / hello world again - | ___ at the same time
// hello world again again ----|
/ / cost: 1.014 s
hook.promise('world'.function() {
console.log('done');
console.timeEnd('cost');
});
// hello world
/ / hello world again - | ___ at the same time
// hello world again again ----|
Copy the code
An example of AsyncParallelBailHook
After my tests, I found that only tap registered synchronous hook functions return non-undefined, and the following hook functions will not be executed. Other asynchronous registered hook functions do not have any effect. At first, I thought that all the functions would be effective, but later I thought it was right, asynchronous hook functions can not block.
const { AsyncParallelBailHook } = require('tapable');
const hook = new AsyncParallelBailHook(['name']);
console.time('cost');
hook.tap('greeting'.function(name) {
console.log(`hello ${name}`);
return false;
});
hook.tapAsync('greeting again'.function(name, cb) {
setTimeout(function() {
console.log(`hello ${name} again`);
cb(false);
}, 1000);
});
hook.tapPromise('greeting again again'.function(name) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(`hello ${name} again again`);
resolve();
}, 1000);
});
});
hook.callAsync('world'.function() {
console.timeEnd('cost');
});
// hello world
/ / cost: 13.593 ms
Copy the code
An example of AsyncSeriesHook
const{AsyncSeriesHook example} =require('tapable');
const hook = newExamples of AsyncSeriesHook (['name']);
console.time('cost');
hook.tap('greeting'.function(name) {
console.log(`hello ${name}`);
});
hook.tapAsync('greeting again'.function(name, cb) {
setTimeout(function() {
console.log(`hello ${name} again`);
cb();
}, 1000);
});
hook.tapPromise('greeting again again'.function(name) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(`hello ${name} again again`);
resolve();
}, 1000);
});
});
hook.callAsync('world'.function() {
console.timeEnd('cost');
});
// hello world
// hello world again
// hello world again again
/ / cost: 2.016 s
Copy the code
An example of AsyncSeriesBailHook
Unlike asynchronous parallelism, callbacks registered after returning non-undefined in tapAsync and tapPromise are not called, but note that non-undefined must be returned before the CB call.
const { AsyncSeriesBailHook } = require('tapable');
const hook = new AsyncSeriesBailHook(['name']);
console.time('cost');
hook.tap('greeting'.function(name) {
console.log(`hello ${name}`);
});
hook.tapAsync('greeting again'.function(name, cb) {
setTimeout(function() {
console.log(`hello ${name} again`);
return false;
}, 1000);
});
hook.tapPromise('greeting again again'.function(name) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(`hello ${name} again again`);
resolve();
}, 1000);
});
});
hook.callAsync('world'.function() {
console.timeEnd('cost');
});
// hello world
// hello world again
Copy the code
An example of AsyncSeriesWaterfallHook
The value returned by the tap registered callback is given to the next registered callback, the second parameter of CB in the tapAsync registered callback is given to the next registered callback, and the value passed in resolve in the tapPromise registered callback is given to the next registered callback.
const { AsyncSeriesWaterfallHook } = require('tapable');
const hook = new AsyncSeriesWaterfallHook(['name']);
console.time('cost');
hook.tap('greeting'.function(name) {
console.log(`hello ${name}`);
return 'one';
});
hook.tapAsync('greeting again'.function(name, cb) {
setTimeout(function() {
console.log(`hello ${name} again`);
cb(null.'two');
}, 1000);
return 'two';
});
hook.tapPromise('greeting again again'.function(name) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(`hello ${name} again again`);
resolve('three');
}, 1000);
});
});
hook.tapPromise('greeting again again again'.function(name) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(`hello ${name} again again again`);
resolve('three');
}, 1000);
});
});
hook.callAsync('world'.function() {
console.timeEnd('cost');
});
// hello world
// hello one again
// hello two again again
// hello three again again
/ / cost: 3.016 s
Copy the code