What is the WebPack plug-in

Webpack plug-in is the skeleton of the whole WebPack tool, and WebPack itself is built by using this plug-in mechanism

const webpack = require('webpack') const TestWebpackPlugin = require('test-webpack-plugin') webpack({ plugins: [new TestWebpackPlugin({/* opt config */})]})Copy the code

What kind of thing is a Webpack plug-in? A complete WebPack plug-in needs to meet the following rules and characteristics

  • Is a separate JS module
  • The module exposes a JS function
  • The function’s prototype defines an Apply method that injects the Compiler object as a parameter
  • The Apply function mounts the WebPack event hook by calling the Compiler object. The hook callback gets the current compilation object, or the callback if the plug-in is compiled asynchronously
  • Complete the custom compilation process to handle the internal data of compiltion objects
  • If it is an asynchronous plug-in, the callback is executed after the data is processed

So our plugin looks like this

// es5
var pluginName = 'test-webpack-plugin'
function TestWebpackPlugin (opt) {
	this.options = opt
}
TestWebpackPlugin.prototype.apply = function (compiler) {
	if (compiler.hooks) { // webpack4 +
    	compiler.hooks.emit.tapAsync(pluginName, function (compilation) {
        	// ...
        })
    } else {
    	compiler.plugin('emit', function (compilation, callback) {
        	// ...
            callback()
        })
    }
}
// es6
const pluginName = Symbol('test-webpack-plugin')
class TestWebpackPlugin {
	constructor (opt) {
    	this.options = opt
    }
    apply (compiler) {
    	const { hooks } = compiler
        if (hooks) {
        	hooks.emit.tapAsync(pluginName, (compilation) => {})
        } else {
        	compiler.plugin('emit', (compilation) => {})
        }
    }
}
Copy the code

Compiler and compilation objects

  • The Compiler object contains all configuration information for the Webpack environment

  • The Compilation object contains the current module resources, compile-generated resources, changing files, and so on

  • The difference between Compiler and Compilation is that Compiler represents the entire Webpack lifecycle from startup to shutdown, while Compilation simply represents a new Compilation.

compiler

The Compiler object is the compiler object of Webpack. The compiler object will be initialized once when Webpack is started. The Compiler object contains all webPack customizable configurations, such as loader configuration. Plugin configuration, entry configuration and other original Webpack configuration

Compiler source code Reference

compilation

The Compilation instance is inherited from compiler, and the compilation object represents a single version of the Webpack build and the generation of compiled resources. When running the WebPack development environment middleware, each time a file change is detected, a new compilation is created, resulting in a new set of compilation resources and a new compilation object. A compilation object contains the current module resources, the compile-generated resources, the changing files, and the state information of the dependencies being tracked. The compiled object also provides a number of keypoint callbacks that plug-ins can choose to use when doing custom processing.

Compilation source code Reference

Webpack plugin mechanism

Webpack makes it more flexible through the Plugin mechanism to adapt to various application scenarios. Many events are broadcast during the life cycle of a Webpack run, and the Plugin can listen for these events and change the output when appropriate through the API provided by Webpack. Compiler.plugin (event name, callback function), compiler.hooks.someHook.tap(…) The plugin mechanism comes from the Tapable library

Tapable

Webpack’s plug-in architecture is based on Tapable, an internal library of the WebPack project that abstracts a set of plug-in mechanisms.

Const {SyncHook, // Synchronizes the serial hook. After the event is triggered, all the event handlers, SyncBailHook, are executed in the order in which the event was registered. // SyncWaterfallHook (); // SyncWaterfallHook (); // SyncLoopHook (); The event handler returns true to continue the loop, and if undefined, AsyncParallelHook, // AsyncParallelBailHook, // AsyncSeriesHook, // AsyncSeriesBailHook, // AsyncSeriesWaterfallHook} = require("tapable");Copy the code

Tapable source code reference

Compiler event hooks

Event hooks trigger parameter type
entryOption After the Entry configuration item is processed, execute the plug-in SyncBailHook Synchronizes insurance
run Hook into Compiler before starting to read records compiler AsyncSeriesHook Asynchronous serial
compile After a new compilation is created, the compiler is hooked into it compilation SyncHook synchronization
compilation After creation, the plug-in is executed compilation SyncHook synchronization
make Recursively analyze the dependencies starting with Entry and prepare to build each module compilation AsyncParallelHook Asynchronous parallelhook
after-compile The build process is complete compilation AsyncSeriesHook Asynchronous serial
emit Before generating resources to the output directory compilation AsyncSeriesHook Asynchronous serial
after-emit After generating the resource to the output directory compilation AsyncSeriesHook Asynchronous serial
done The compilation is complete stats SyncHook synchronization

Pictured above,

Dry goods, delete sourceMap plug-in after uploading sourceMap in project

const _del = require('del') const symbols = require('log-symbols') const chalk = require('chalk') const pluginName = { name: 'clean-source-map-webpack-plugin' } class CleanSourceMapWebpackPlugin { constructor (options) { const defaultOptions = { SourceMapPath: [], / / sourceMap dangerouslyAllowCleanPatternsOutsideProject file location: } this.options = object. assign(defaultOptions, options) this.outputPath = '' } handleDone () { const { sourceMapPath, DangerouslyAllowCleanPatternsOutsideProject} = this. The options const {outputPath} = this try {/ / call _del library to delete sourceMap file _del.sync(sourceMapPath.map(item => outputPath + '/' +item), { force: dangerouslyAllowCleanPatternsOutsideProject }) console.log(symbols.success, chalk.green('clean-source-map-webpack-plugin: complated')) } catch (error) { const needsForce = /Cannot delete files\/folders outside the current working directory\./.test(error.message) if (needsForce) { const message = 'clean-source-map-webpack-plugin: Cannot delete files/folders outside the current working directory. Can be overridden with the `dangerouslyAllowCleanPatternsOutsideProject` option.' throw new Error(message) } throw error } } apply (compiler) { // If (! compiler.options.output || ! compiler.options.output.path) { console.warn(symbols.warning, chalk.red('clean-source-map-webpack-plugin: options.output.path not defined. Plugin disabled... ')) return} const {sourceMapPath} = this.options // If (sourcemappath.length === 0) { console.warn(symbols.warning, chalk.red('clean-source-map-webpack-plugin: please input sourceMapPath. Plugin disabled... Const ')) return} {hooks} = compiler enclosing outputPath. = the compiler options. The output. The path / / if it is webpack4 + the if (hooks) {/ / Tap (pluginName, stats => {this.handledone ()})} else {compiler.plugin('done', stats => { this.handleDone() }) } } } module.exports = CleanSourceMapWebpackPluginCopy the code

Take a look at the real Webpack plug-in

Webpack4 core module Tapable source code analysis

Easy to understand Webpack