preface
Have you encountered any of these problems:
- Webpack-packed files are not compressed
- Static files are manually copied to the output directory
- There is a lot of redundant code written in the code for environmental judgments
The previous “WebPack Core features” Loader talked about webPack’s Loader mechanism. This article focuses on another core feature: plugins.
The plug-in mechanism is designed to solve these problems by automating the work of a project in addition to the packaging of resource modules.
Plugins are designed to extend WebPack functionality by injecting hooks into the build process, which gives WebPack a lot of flexibility.
What are the differences between plugins and Loaders?
Loader is a converter that compiles and converts one file into another. For example, convert a.less file to a.css file.
Plugins are extenders for the entire packaging process after the loader finishes. It does not directly operate on files, but instead works based on an event mechanism. Events are broadcast at specific times in the WebPack build process, and the plug-in can listen for these events to occur and do something at specific times. These include: packaging optimization, resource management, injecting environment variables.
How should the plugin be configured?
For example, HtmlWebpackPlugin can generate an HTML file for us that includes all the modules in the body using the script tag. Here’s how to configure it:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpackConfig = {
...
plugins: [new HtmlWebpackPlugin()]
};
Copy the code
Note Loader is configured in module.rules as the module parsing rule. The type is array. Each entry is an object containing properties such as test(type file), Loader, and options(parameter). Plugins are individually configured as arrays, each of which is an instance of the Plugin, and the arguments are passed in through the constructor.
What are some common plugins?
The following list of plugins is from webpack’s official website. If you are not familiar with the plugin, you can click on the name to jump to have a look and understand the specific gameplay.
The name of the | describe |
---|---|
AggressiveSplittingPlugin | Divide the original chunk into smaller chunks |
BabelMinifyWebpackPlugin | Use Babel-Minify for compression |
BannerPlugin | Add the banner at the top of each generated chunk |
CommonsChunkPlugin | Extract the generic module shared between chunks |
CompressionWebpackPlugin | A pre-prepared compressed version of the resource that uses Content-Encoding to provide access |
ContextReplacementPlugin | Override the inferred context of the require expression |
CopyWebpackPlugin | Copy individual files or entire directories to the build directory |
DefinePlugin | Global constants that allow configuration at compile time |
DllPlugin | To greatly reduce build time, subcontract DLLS |
EnvironmentPlugin | Shorthand for the process. Env key in DefinePlugin. |
ExtractTextWebpackPlugin | Extract text (CSS) from the bundle into a separate file |
HotModuleReplacementPlugin | Enable Hot Module Replacement – HMR |
HtmlWebpackPlugin | Simply create an HTML file for server access |
I18nWebpackPlugin | Added internationalization support for bundles |
IgnorePlugin | Exclude certain modules from the bundle |
LimitChunkCountPlugin | Sets minimum/maximum limits for chunks to fine tune and control chunks |
LoaderOptionsPlugin | Used to migrate from WebPack 1 to WebPack 2 |
MinChunkSizePlugin | Ensure that the chunk size exceeds the specified limit |
NoEmitOnErrorsPlugin | During the output phase, a compilation error was encountered and skipped |
NormalModuleReplacementPlugin | Replaces the resource that matches the regular expression |
NpmInstallWebpackPlugin | Missing dependencies are automatically installed at development time |
ProvidePlugin | You don’t need to use modules via import/require |
SourceMapDevToolPlugin | More granular control over the Source Map |
EvalSourceMapDevToolPlugin | More granular control over the Eval Source map |
UglifyjsWebpackPlugin | You can control the version of UglifyJS in your project |
ZopfliWebpackPlugin | A pre-compressed version of the resource with Node-Zopfli |
How do I write a plugin?
Before I talk about how to write plugins, let’s take a look at some of the fun things: tapable, Compiler, and Compilation.
tapable
Tapable is a library similar to NodeJS EventEmitter, which controls the publishing and subscription of hook functions. Of course, the hook mechanism provided by Tapable is more comprehensive, which is divided into synchronous and asynchronous two categories (asynchronous and asynchronous parallel and asynchronous serial), and the Bail/Waterfall/Loop type is derived according to the different termination conditions of event execution.
Basic use:
const { SyncHook } = require('tapable');
const hook = new SyncHook(['name']);
hook.tap('hello'.(name) = > {
console.log(`hello ${name}`);
});
hook.tap('hi'.(name) = > {
console.log(`hi ${name}`);
});
hook.call('july');
// hello july
// hi july
Copy the code
Summary:
The basic logic of tapable is to register the handler function corresponding to the hook through the tap method of the class instance, and then trigger the callback function through the call method.
compiler
The Compiler object contains all configuration information about the WebPack environment, including options, loaders, and plugins. Can be understood simply as webpack instances. Represents the entire WebPack startup to shutdown lifecycle.
Compile internal implementation:
class Compiler extends Tapable {
constructor(context) {
super(a);this.hooks = {
/ * *@type {SyncBailHook<Compilation>} * /
shouldEmit: new SyncBailHook(["compilation"]),
/ * *@type {AsyncSeriesHook<Stats>} * /
done: new AsyncSeriesHook(["stats"]),
/ * *@type {AsyncSeriesHook<>} * /
additionalPass: new AsyncSeriesHook([]),
/ * *@type {AsyncSeriesHook<Compiler>} * /. }; . }Copy the code
Summary:
Compile inherits tapable and binds a hook object to the instance.
compilation
The Compilation object contains the current module resources, compiled generated resources, and changed files. Represents only a new compilation.
Implementation of Compilation:
class Compilation extends Tapable {
/**
* Creates an instance of Compilation.
* @param {Compiler} compiler the compiler which created the compilation
*/
constructor(compiler) {
super(a);this.hooks = {
/ * *@type {SyncHook<Module>} * /
buildModule: new SyncHook(["module"]),
/ * *@type {SyncHook<Module>} * /
rebuildModule: new SyncHook(["module"]),
/ * *@type {SyncHook<Module, Error>} * /
failedModule: new SyncHook(["module"."error"]),
/ * *@type {SyncHook<Module>} * /
succeedModule: new SyncHook(["module"]),
/ * *@type {SyncHook<Dependency, string>} * /
addEntry: new SyncHook(["entry"."name"]),
/ * *@type {SyncHook<Dependency, string, Error>} * /}; }}Copy the code
When running the WebPack development environment middleware, every time a file change is detected, a new Compilation is created to generate a new set of compilation resources. A Compilation object represents current module resources, compiled generated resources, changed files, and tracked dependencies. The Compilation object also provides a number of time-critical callbacks that plug-ins can choose to use when doing custom processing.
Warm up
Write a basic plugin:
// A JavaScript named function.
function SimplePlugin() {}
// Define a 'apply' method on the prototype of the plug-in function.
SimplePlugin.prototype.apply = function (compiler) {
// Specify an event hook to mount to webPack itself.
compiler.plugin("webpacksEventHook".function (
compilation /* Handle webPack internal instance specific data. * /,
callback
) {
console.log("This is an simple plugin!!!");
// When the functionality is complete, call the callback provided by WebPack.
callback();
});
};
Copy the code
After WebPack started, it did the following:
- Execute first during the read configuration process
new SimplePlugin()
, initialize a SimplePlugin and get an example. - In the initialization
compiler
Object, and then callSimplePlugin.apply(compiler)
For the plug-in instancecompiler
Object. - The plug-in instance is obtained at
compiler
Object, you can passcompiler.plugin("webpacksEventHook", function(compilation, callback){})
Listen to webPack broadcast events and passcompiler
Object to manipulate WebPack.
In actual combat
Let’s write a useful plug-in.
To do something when WebPack closes right away. For example, it tells you whether the package is completed or not. Or execute some script. We’ll call it AfterWebpackPlugin. The usage is as follows:
module.exports = {
plugins: [
// Pass the success and failure callbacks, respectively
new AfterWebpackPlugin(
() = > {
// You can notify the user of a successful build and execute the release script
},
(err) = > {
// Throw an exception when the build fails
console.error(err); })]};Copy the code
The implementation here requires the following two hooks:
- Done: Occurs when WebPack exits immediately after a successful build and output of the file.
- Failed: Occurs when the build failed due to a build exception and WebPack exits immediately.
The implementation code is as follows:
class AfterWebpackPlugin {
constructor(doneCb, failedCb) {
// Pass the callback function
this.doneCb = doneCb;
this.failedCb = failedCb;
}
apply(compiler) {
compiler.plugin("done".(res) = > {
// Callback in webPack lifecycle 'done'
this.doneCb(res);
});
compiler.plugin("failed".(err) = > {
// Callback in webPack lifecycle 'failed'
this.failedCb(err); }); }}module.exports = AfterWebpackPlugin;
Copy the code
Summary of plug-in development:
- Notice in the WebPack lifecycle to find the appropriate hooks to complete the functionality.
- Take care to understand the nuances of the various hooks in the WebPack lifecycle.
expand
Events that occur during the Output phase of WebPack and are explained below:
The event name | explain |
---|---|
should-emit | All files that need to be output have been generated. Ask the plug-in which files need to be output and which do not |
emit | After determining which files to output, file output is performed, where the output can be retrieved and modified |
after-emit | File output completed |
done | Complete a complete compilation and output process successfully |
failed | If an exception is encountered during the compilation and output process, causing webPack to exit, it will be directly skipped to this step, and the plug-in can obtain the specific error cause in this event |
series
- Webpack Core Features loader
- “Webpack Core Features” plugin
- “Webpack Core Features” Module Hot Replacement (HMR)
Thank you
- If this article helped you, just give it a like! Thanks for reading.
- I participated in the 2020 List of creators. If you like me, you can vote for me