The installation
NPM init -y: install webpack and webpack-CLI at the same time.
npm install webpack@4.43. 0 webpack-cli@3.312. -D
Copy the code
A global installation of WebPack is not recommended because it locks the version, and multiple projects may depend on different versions of WebPack, so it is recommended to install webPack within a project.
You can create a.npmrc file under the root directory to specify the source address on which the current project installation depends
registry=https://registry.npm.taobao.org
Copy the code
Zero configuration for Webpack
One of the gimmick advertised by WebPack is the zero-configuration build, which means that you can package it without writing any configuration, which is executable, but it doesn’t really meet your actual development needs.
For a quick run, create a new SRC /index.js file. We only write one line in index.js
console.log("hello, webpack !")
Copy the code
Then perform
npx webpack -v
Copy the code
NPX finds and starts the Webpack under the current project. You can see the dist/main.js file generated in the root directory.
You are advised to add build commands to package.json files to facilitate the addition of build parameters and make it easier to read.
"scripts": {
"dev": "webpack"
},
Copy the code
I only wrote one line of code, but there are so many characters in the package that if you look at the progress bar below, there are many more to come.
Because WebPack has a lot of compatibility by default, it also has a lot of redundant code compared to other build tools.
Webpack5 has some optimizations, but as more and more modules change, nothing much changes.
Build information
What is the output at build time
The contents of the packaged file are many, but the main structure is very simple, in fact, a self-executing function, as follows
(function(modules) {
// todo({})"./src/login.js": (function(module.exports) {
eval("xxxxx")})})Copy the code
In this structure, you can see that the argument to the self-executing function is an object, and the value of each key of the object contains a chunk, which is the code fragment.
It can also contain chunks, known as chunks, groups of chunks, and also known as chunk Names.
This entire object can contain multiple keys: values and is called a dependency graph.
The resource files generated after the build are called bundle files.
Several follow the following relationship:
- a
bundle
Correspond to at least onechunks
- a
chunks
Correspond to at least onemodule
- a
module
Correspond to at least onechunk
In a word:
Module, chunk, and bundle are the same logical code with three names in different transformation scenarios:
We write modules directly, webpack processes chunks, and finally generate bundles that the browser can run directly.
Configuration file for WebPack
If no configuration file is added, its default configuration is followed, which is called zero configuration. If a configuration file is added, WebPack is packaged according to the configuration file.
Usually the name of the webpack configuration file is webpack.config.js. You can configure it to something else, but it’s not necessary.
Modify package.json file by creating a command in script
–config Specifies the configuration file
"warbler": "webpack --config ./warbler.config.js"
Copy the code
Since the content of the configuration file is very large, and the syntax is difficult to remember all at once, we can use a few tricks to make the configuration file have syntax hints.
Start by installing @types/webpack.
npm i -D @types/webpack
Copy the code
Then specify the type in the configuration file.
// webpack.config.js
/ * * *@type {import('webpack').Configuration}* /
module.exports = {
}
Copy the code
Babel.config.js supports the same approach.
npm i -D @types/babel__core
/ * * *@type {import('@babel/core').TransformOptions}* /
Copy the code
Vue.config.js is also available, and no additional packages need to be installed.
/ * * *@type {import('@vue/cli-service').ProjectOptions}* /
Copy the code
Webpack configuration parameters
webpack
Is based onnodejs
All of themnodejs
Core modularapi
Can be directly introduced to use.
entry
The default entry for performing a packing task is SRC /index. Relative and absolute paths are supported.
entry: "./src/index.js"
Copy the code
Support string, arR, object if passed in as a string, it will also be converted to an object structure during build, the above code and the following code result is the same.
entry: {
main: "./src/index.js"
},
Copy the code
Support SPA (single entrance) and MPA (multiple entrance). Multiple entries output multiple bundles.
entry: {
index: "./src/index.js".login: "./src/login.js".home: "./src/home.js"
},
Copy the code
output
Output information about the resource file, including storage location and file name
path
: Storage location, where to put packaged files default isdist
The requirement is absolute path;filename
: File name, what is the name of the packaged file?
output: {
path: path.resolve(__dirname, './dist'),
filename: "main.js"
},
Copy the code
However, if entry sets multiple entries, multiple main.js will be generated and an error will be reported.
The solution is to use placeholders with the following syntax
filename: "[name].js"
Copy the code
The function is that the key in the entry is named whatever the filename is after being packed. Multiple entrances will correspond to multiple exits.
mode
Packaging mode, default is production mode, production mode will do code compression, tree shaking and other operations.
development
Development modeproduction
Production modenone
The default
plugins
A plug-in. A plug-in is essentially a class. The configuration of various common plug-ins will be explained separately later.
Plugins are executed from top to bottom.
plugins:[]
Copy the code
module
Module, webpack default only support.js,.json files, like we usually commonly used.vue,.png,.scss,.css,.ts and so on are not supported.
So if you want WebPack to support other types of files, you need a different type of Loader to parse.
The following configuration means what loader is used to process.css files when testing.
// webpack.config.js
module: {
rules: [{test: /\.css$/,
use: ["style-loader"."css-loader"]},]}Copy the code
- css-loader:
css
Module serialization, letwebpack
knowcss
Syntax can not be generatedchunk
. - style-loader:
css
Integration inhtml
Of the filehead
Of the labelstyle
In the.
When multiple Loaders are applied to a module, they are executed from right to left. That is, csS-loader is executed before style-loader is executed.
In fact, a Loader can also handle the above two tasks, but it is recommended that a Loader only do one thing, that is, follow the principle of single responsibility.
You can also write the loader configuration, in which case the object structure is used.
// webpack.config.js
module: {
rules: [{test: /\.less$/,
use: [
{
loader: 'style-loader'}, {loader: "css-loader".options: {
modules: true}}, {loader: 'postcss-loader'}, {loader: 'less-loader',}]}]}Copy the code
- less-loader:
less
Syntactic conversion tocss
Syntax. - postcss-loader :
postcss
Is aTool setThis is very powerful,postcss
对css
Is equivalent tobabel
forjs
As a plug-in itself, it can also carry plug-ins.
resolveLoader
Parse the loader and tell WebPack how to match the Loader. When we customize some loaders. We can use the absolute path to import the file, but it is too tedious. When we specify the folder through this field, we can write the loader name as if using a third-party loader.
// webpack.config.js
resolveLoader: {
// The default is node_modules
modules: ["node_modules"."./myLoaders"]},Copy the code
Common configurations of common plug-ins
html-webpack-plugin
Version: 4.5.2
- template: Generated using a specified template
html
。 - filename: Packed
html
The file name. - chunks: Packed
html
What will be includedchunk
.
// webpack.config.js
plugins: [
// Automatically generate HTML files, import bundle files, compress HTML
new htmlWebpackPlugin({
// The template matches
template: "./src/index.html".filename: "index.html".chunks: ["index".'login'],}),]Copy the code
If you want to generate multiple HTML, you simply create multiple instances.
// webpack.config.js
plugins: [
// Automatically generate HTML files, import bundle files, compress HTML
new htmlWebpackPlugin({
// The template matches
template: "./src/index.html".filename: "index.html".chunks: ["index".'login'],}).// Automatically generate HTML files, import bundle files, compress HTML
new htmlWebpackPlugin({
// The template matches
template: "./src/index.html".filename: "login.html".chunks: ["login"],}).// Automatically generate HTML files, import bundle files, compress HTML
new htmlWebpackPlugin({
// The template matches
template: "./src/index.html".filename: "home.html".chunks: ["home"],}),]Copy the code
But as a lazy programmer, you would never write this code, because the WebPack configuration file is itself an object. So of course there are ways to generate configuration items automatically.
In this example, each folder contains one index.html and one index.js. The structure is as follows. Of course, you can define the structure at will, and then write the corresponding function body.
├ ─ ─ the SRC ├ ─ ─ the list │ ├ ─ ─ index. The HTML │ └ ─ ─ index. The js ├ ─ ─ the login │ ├ ─ ─ index. The HTML │ └ ─ ─ index. The js ├ ─ ─ the detail │ ├ ─ ─ index. The HTML │ └ ─ ─ index. Js ├ ─ ─ index │ ├ ─ ─ index. The HTML │ └ ─ ─ index, jsCopy the code
The configuration is as follows, using the setMap method to automatically generate entry and htmlWebpackPlugins so that we don’t have to modify the configuration every time we add a file.
// webpack.config.js
const path = require('path')
const htmlWebpackPlugin = require("html-webpack-plugin")
// Fuzzy match path
const glob = require('glob')
// Automatically generate entry and htmlWebpackPlugins
const setMap = () = > {
const entry = {};
const htmlWebpackPlugins = []
// Fuzzy-match index.js in any directory under SRC returns the absolute path to the file
const entryFiles = glob.sync(path.join(__dirname, "./src/*/index.js"))
// Iterate over the matched result
entryFiles.forEach((entryFile) = > {
// Get the file name
const pageName = entryFile.match(/src\/(.*)\/index\.js$/) [1]
/ / generated entry
entry[pageName] = entryFile
/ / generated htmlWebpackPlugins
htmlWebpackPlugins.push(
new htmlWebpackPlugin({
template: `./src/${pageName}/index.html`.filename: `${pageName}.html`.chunks: [pageName]
}))
})
return {
entry,
htmlWebpackPlugins
}
}
const { entry, htmlWebpackPlugins } = setMap()
// Config file
module.exports = {
entry,
// Output information about the resource file
output: {
// Storage location
path: path.resolve(__dirname, './dist'),
// File name
filename: " [name].js"
},
// Package mode
mode: "development"./ / the plugin
plugins: [
...htmlWebpackPlugins,
],
}
Copy the code
postcss
Postcss also has its own configuration file, postcss.config.js, which is also a module, installed via require(“autoprefixer”).
// postcss.config.js
module.exports = {
plugins: [
require("autoprefixer"),require("cssnano")]}Copy the code
Postcss plugin for Autoprefixer
Autoprefixer automatically prefixes CSS properties using can I use data.
But that doesn’t work yet, so you need to set up Browserslist, the target set of browsers, the compatible version of the browser, and the tool that uses the browserslist will specifically output the compatible code based on browserslist’s description.
Browserslist can be set up in two ways.
You can add properties directly to the package.json file as follows
"browserslist": [
"1%" >."last 2 versions"
]
Copy the code
You can also create a.browserslistrc file in the root directory and write it directly, without parentheses.
// .browserslistrc
>1%
last 2 versions
Copy the code
- >1% : browsers with a global market share of more than 1%.
- Last 2 Versions: indicates the latest two major versions of compatible browsers.
You can use NPX Browserslist to query for compatible browser versions.
Postcss plugin CSsnano
Compress the CSS code.
mini-css-extract-plugin
Pull out the CSS code into a separate file, you can specify the filename, support absolute path, will automatically generate folders. Replace style-loader with minicss.loader where loader is written.
// webpack.config.js
const minicss = require("mini-css-extract-plugin")
module.exports = {
plugins: [
new minicss({
filename: 'style/index.css'})].module: {
rules: [{test: /\.less$/,
use: [
minicss.loader,
{
loader: "css-loader".options: {
modules: true}}, {loader: 'postcss-loader'}, {loader: 'less-loader',}]}]}Copy the code
clean-webpack-plugin
Clean up the packing directory before each packing.
// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
plugins: [
newCleanWebpackPlugin ()],}Copy the code
Implement a custom Loader
The loader reference
Create a myLoaders/a-loader.js file in the root directory and import it in the Module using an absolute path.
// webpack.config.js
module: {
rules: [{test: /\.js$/,
use: [
{
loader: path.resolve(__dirname, './myLoaders/a-loader.js'),},]},]}Copy the code
The structure of the loader
Loader is a function. Take source, which is the content of the module that matches the test re, in this case the.js file.
- This function cannot beArrow functionBecause the
webpack
providesloader api
It’s all mounted tothis
On the. - This function must return a value or an error will be reported.
// a-loader.js
module.exports = function(source) {
console.log('🚀 🚀 ~ source:', source);
return source
}
Copy the code
The SRC /index.js file outputs only one line of logs.
// src/index.js
console.log('hello, world');
Copy the code
Source is the SRC /index.js file that has not been compiled by Webpack.
The writing of the loader
In a-loader.js, we replace hello with hello and return.
// a-loader.js
module.exports = function(source) {
const _source = source.replace('hello'.'hello' )
return _source
}
Copy the code
If you look at the chunk, console.log(‘ Hello world’) shows that our custom loader has taken effect.
When we use a third-party loader, we usually define a configuration item options, so how to set the options of our custom loader?
First, set an options property in Use like any other loader.
// webpack.config.js
module: {
rules: [{test: /\.js$/,
use: [
{
loader: path.resolve(__dirname, './myLoaders/a-loader.js'),
options: {
name: "A Warbler's Tail"}},]},]}Copy the code
This. Query is used to retrieve options from a custom loader, which explains why loader cannot be an arrow function.
Replace world with name in the options we set.
// a-loader.js
module.exports = function(source) {
const _source = source.replace('world'.this.query.name )
return _source
}
Copy the code
Ok, successful substitution.
It is common for loader to perform asynchronous operations, so we need to use this.callback, a function that can be called synchronously or asynchronously and return multiple results.
this.callback(
err: Error | null.content: string | Buffer, sourceMap? : SourceMap, meta? : any );Copy the code
- The first parameter must be
Error
ornull
- The second argument is a
string
orBuffer
. - Optional: The third argument must be one that can be parsed by the module
source map
. - Optional: The fourth option, will be
webpack
Ignore, which can be anything (such as some metadata).
We also need to use this.async to tell the loader’s parser that the loader will call back asynchronously.
Create a new myLoaders/b-loader.js file and use setTimeout to simulate an asynchronous operation.
// b-loader.js
module.exports = function(source) {
const _callback = this.async();
const _source = source.replace('world'.this.query.name)
setTimeout(() = > {
_callback(null, _source)
}, 3000)}Copy the code
Then reference the Loader.
// webpack.config.js
module: {
rules: [{test: /\.js$/,
use: [
{
loader: path.resolve(__dirname, './myLoaders/b-loader.js'),
options: {
name: "A Warbler's Tail"}},]},]}Copy the code
If you look at the build time, it’s over three seconds.
And that’s what we wanted, replacing world with my name a warbler.
Asynchronous Loaders do not affect the loaders of other modules, but affect the loaders that multiple Loaders work on one module.
When a loader is finished, it will be handed over to the next loader until there is no loader, and finally to Webpack.
Let’s test the case that two Loaders work on the same module. Since loader runs from right to left, we write B-Loader first and a-loader later.
// webpack.config.js
module: {
rules: [{test: /\.js$/,
use: [
{
loader: path.resolve(__dirname, './myLoaders/b-loader.js'),
options: {
name: "A Warbler's Tail"}}, {loader: path.resolve(__dirname, './myLoaders/a-loader.js'),},]},]}// b-loader.js
module.exports = function(source) {
const _callback = this.async();
const _source = source.replace('world'.this.query.name)
setTimeout(() = > {
_callback(null, _source)
}, 3000)}// a-loader.js
module.exports = function(source) {
const _source = source.replace('hello'.'hello')
return _source
}
Copy the code
As you can see, both loaders are in effect.
However, there is a problem that our custom loader uses the absolute path reference mode, which is too tedious and cannot be read.
The solution is the resolveLoader configuration parameter mentioned above, which allows you to write the loader name as if you were using a third-party loader.
// webpack.config.js
resolveLoader: {
// The default is node_modules
modules: ["node_modules"."./myLoaders"]},module: {
rules: [{test: /\.js$/,
use: [
{
loader: "b-loader".options: {
name: "A Warbler's Tail"}}, {loader: "a-loader",},]},]}Copy the code
Practice writing loader
my-style-loader
module.exports = function(source) {
return `
const tag = document.createElement("style")
tag.innerHTML = ${source}
document.head.appendChild(tag)
`
}
Copy the code
my-css-loader
module.exports = function(source) {
return JSON.stringify(source)
}
Copy the code
my-less-loader
const less = require("less")
module.exports = function(source) {
less.render(source, (error, output) = > {
const cssInfo = output.css
this.callback(error, cssInfo)
})
}
Copy the code
Working with static Resources
As mentioned above, webpack does not recognize file types other than.js and.json, so we need to use different loaders to handle static resources.
Next we will learn about the new loader to handle image resources.
file-loader
Function: Exports a resource and returns the path.
Options:
- name: Image name, which can be a placeholder.
[name]
The name,[ext]
The suffix. - outputPath: The storage location of the output resource
dist
Directory. - publicPath: Where resources are used,
publicPath
+name
=The full usage path of images in the CSS
.
// webpack.config.js
module: {
rules: [{test: /\.(jpe? g|png|gif|webp)$/,
use: [
{
loader: "file-loader".options: {
name: "[name].[ext]".outputPath: "images".publicPath: ".. /images",}},]},]}Copy the code
url-loader
Function: Rely on file-loader, transfer the image to base64 encoding, can reduce the image request.
Options:
- name: Image name, which can be a placeholder.
[name]
The name,[ext]
The suffix. - outputPath: The storage location of the output resource
dist
Directory. - publicPath: Where resources are used,
publicPath
+name
=The full usage path of images in the CSS
. - limit: Images larger than the specified size will not be converted to
base64
, in bytes.
// webpack.config.js
module: {
rules: [{test: /\.(jpe? g|png|gif|webp)$/,
use: [
{
loader: "url-loader".options: {
name: "[name].[ext]".outputPath: "images".publicPath: ".. /images".limit: 4 * 102,}},]},]}Copy the code
image-webpack-loader
This loader needs to use CNPM to install successfully.
cnpm i image-webpack-loader -D
Copy the code
Purpose: Image compression
// webpack.config.js
module: {
rules: [{test: /\.(jpe? g|png|gif|webp)$/,
use: [
{
loader: 'image-webpack-loader',}]},]}Copy the code
If you look at the source file compared to the output file, the effect is still remarkable.
Image processing in webpack5
// webpack.config.js
module: {
rules: [{test: /\.(jpe? g|png|gif|webp)$/.// The asset generic configuration defaults to an 8KB limit over use asset/resource otherwise use asset/inline
// asset/resource is equivalent to file-loader
// asset/inline is the same as url-loader
type: "asset/resource".// The generator property can only be set in asset/resource
generator: {
filename: "images/[name][ext]",}parser: {
dataUrlCondition: {
The maxSize attribute takes effect only if you set it to asset
maxSize: 1 * 1024}}}]}Copy the code
Font file processing
The font file is referenced like this.
// index.less
@font-face {
font-family: 'webfont';
font-display: swap;
src: url('.. /font/webfont.eot'); /* IE9 */
src: url('.. /font/webfont.eot? #iefix') format('embedded-opentype'),
/* IE6-IE8 */ url('.. /font/webfont.woff2') format('woff2'),
url('.. /font/webfont.woff') format('woff'), /* Chrome, Firefox */url('.. /font/webfont.ttf') format('truetype'/* Chrome, Firefox, Opera, Safari, Android, iOS4.2+ * /url('.. /font/webfont.svg#webfont') format('svg'); / * iOS 4.1 - * /
}
body {
div {
height: 100px;
background: blue;
display: flex;
background: url(../images/main.jpg) 0 0 no-repeat;
font-family: 'webfont' ! important; }}Copy the code
Font file processing and image is the same, using the same loader.
Font files can also be converted to base64 format, so urL-loader can also be used.
// webpack.config.js
module: {
rules: [{test: /\.(eot|svg|ttf|woff|woff2)$/,
use: [
{
loader: "file-loader".options: {
name: "[name].[ext]".outputPath: "font".publicPath: ".. /font",}},]},]}Copy the code
Working with JavaScript modules
babel
First, install both of the following: babel-loader depends on @babel-core.
npm i @babel-core babel-loader -D
Copy the code
Much like PostCSS, Babel is a toolset that doesn’t do anything by itself, relying on its own plug-ins.
Babel is also a tool that works with collections of browsers.
@babel/preset-env
Used to deal with compatibility issues with ES6 + syntax.
Let’s start with something new for ES6.
// index.js
const arr = [new Promise(() = >{})]Copy the code
Then configure the plug-in.
// webpack.config.js
module: {
rules: [{test: /\.js$/,
use: [
{
loader: 'babel-loader'.options: {
presets: ["@babel/preset-env"]}}]},]}Copy the code
Pack and see what happens.
As you can see, const has been converted to VAR, but promise has not been converted. As mentioned above, this plugin is only used to transform ES6 + syntax, not new features.
So what to do? Of course, you have to rely on other friends.
@babel/polyfill
This package is used at run time, so it is installed into the production dependency.
npm i @babel/polyfill -S
Copy the code
This package contains all the new features to be referenced before any code.
// index.js
import "@babel/polyfill"
const arr = [new Promise(() = >{})]Copy the code
In later versions of babel7.4, the new approach is recommended.
// index.js
import "core-js/stable";
import "regenerator-runtime/runtime";
const arr = [new Promise(() = >{})]Copy the code
But since the package is too large, we also need to configure on-demand imports, again via @babel/preset-env options.
// webpack.config.js
module: {
rules: [{test: /\.js$/,
use: [
{
loader: 'babel-loader'.options: {
presets: [["@babel/preset-env", {
// Specify a collection of browsers separately
targets: {},
NPM I core-js@3 -s is required for the core-js version
corejs: 3./** * false When we introduce polyfill, we will not import on demand, the bundle will be very large * entry needs to import import in the entry file"@babel/polyfill" Babel will help us to import * usage on demand */
useBuiltIns: "usage"}]]}}]},]}Copy the code
Babel can also have its own configuration file. Create a new babel.config.js file in the root directory, and move the contents of the options file.
// babel.config.js
module.exports = {
presets: [["@babel/preset-env", {
targets: {},
corejs: 3.useBuiltIns: "usage"}}]]Copy the code
Integrated the react
Integrate react and install dependencies.
npm i react react-dom -S
npm i @babel/preset-react -D
Copy the code
Configure the Babel. Config. Js.
// babel.config.js
module.exports = {
presets: [["@babel/preset-react"}, {}]]Copy the code
Integrated vue
Integrate vUE, install dependencies. This has nothing to do with Babel, by the way.
Note that the vUE and vue-template-Compiler versions must be the same.
npm i vue vue-loader vue-template-compiler -D
Copy the code
Configuration webpack. Config. Js.
// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
module: {
rules: [
/ /... Other rules
{
test: /.vue$/,
loader: 'vue-loader'}},plugins: [
// Be sure to introduce this plugin!
new VueLoaderPlugin()
]
}
Copy the code
Implement custom plugins
The structure of the plugin
Create myPlugins/my-plugin.js in the root directory.
The essence of a plugin is a class. Receive the options configuration through the constructor. Each plugin must have a built-in Apply method, which receives a parameter Compiler, the instantiated Webpack, containing configuration information and so on.
// my-plugin.js
class MyPlugin {
constructor(options) {
console.log('🚀 🚀 ~ options:', options);
}
apply(compiler) {
/ / the console. The log (' 🚀 🚀 ~ : my - plugin ');}}module.exports = MyPlugin
Copy the code
The plugin’s reference
You can pass options when creating an instance.
// webpack.config.js
const MyPlugin = require("./myPlugins/my-plugin")
module.exports = {
plugins: [
new MyPlugin({
name: A Warbler's Tail}})]Copy the code
The writing of the plugin
How to determine the timing of plugin execution?
Webpack also has lifecycle hooks. We can take a look at what the hooks are.
// Create webpack.js in the directory and start it from Node webpack.js
/ / introduce webpack
const webpack = require("webpack")
// Import the configuration file
const config = require("./webpack.config.js")
// Produce the webPack instance from the configuration file
const compiler = webpack(config)
// Prints the webPack lifecycle hooks
Object.keys(compiler.hooks).forEach((hookName) = > {
compiler.hooks[hookName].tap("xxx".(compilation) = > {
console.log('🚀 🚀 ~ hookName:', hookName); })})// Perform compilation
compiler.run()
Copy the code
All of the lifecycle hooks are on the Compiler. hooks property, so we iterate over the printed result as follows:
You can see that webPack has too many lifecycle hooks.
So our plugin events just need to register with the corresponding lifecycle hooks, and the Webpack will pass through our plugin at the appropriate time.
class MyPlugin {
constructor(options){}// Accepting a parameter Compiler is that the instantiated Webpack contains configuration information
apply(compiler) {
// Register event synchronous hooks with TAP asynchronous hooks with tapAsync
// The event name can be any value. It is recommended to keep the semantics consistent with the plug-in name
compiler.hooks.emit.tapAsync('xxx'.(compilation, cb) = > {
// compilation
console.log(' '🚀 🚀 ~ compilation., compilation.assets);
const content = 'hello,plugin xxxxx'
// Add static resources
compilation.assets['warbler.txt'] = {
source: function() {
return content
},
// It is only used for viewing and does not affect the actual file size
size: function() {
return content.length
}
}
cb()
})
}
}
module.exports = MyPlugin
Copy the code
Events can be registered in any lifecycle using the Compiler parameter of the Apply method, but some lifecycle are synchronous and some are asynchronous. For details, see the official website.
Synchronous hooks register events with TAP and asynchronous hooks register events with tapAsync.
For asynchronous hooks, a CB argument is passed in the event callback and called at the end.
The event name can be any value. It is recommended to keep the same semantics as the plug-in name for easy reading of the source code and understanding of the function.
The compilation parameters for the event callbacks are the half-finished compilation parameters of the previous hook execution.