Previous articles:

  • Relearn webpack4 principle analysis

  • Relearn webpack4 basics

  • Re-learn webpack4 loader development

  • Relearn webpack4 plugin development

  • Webpack plug-in development second open cache plug-in

  • Relearn webpack4 packaging libraries and components

  • Relearn webpack4 build speed and volume optimization

The environment in which the plug-in runs

  • Plug-ins do not have a separate runtime environment like loader, run-loader
  • Can only run inside webPack

Basic plug-in structure

// Plug-in name
class MyPlugin {
  constructor(options) {}
  // The plugin runs the apply method
  apply(compiler) {
    / / the plugin hooks
    compiler.hooks.done.tap('My Plugin'.(/* xxx */) = > { 
      // Plug-in processing logic}}})module.exports = MyPlugin
Copy the code
  • use

plugins: [new MyPlugin()]

Error handling of plug-ins

  • The parameter verification phase can throw errors directly
  • The compilation object’s warning and errors structures
compileration.warning.push('warning')
compileration.errors.push('error')
Copy the code

Write files through compilation

  • Compilation assets can be used to write files
  • File writing needs to use Webpack-sources
compilation.assets[name] = new RawSource('xxxx')
Copy the code

There are different types of event hooks: SyncBailHook, AsyncSeriesHook, SyncHook, etc

If it’s an asynchronous event hook, you can register event functions using tapPromise or tapAsync,

TapPromise requires the method to return a Promise in order to handle asynchracy, while tapAsync requires callback to return the result

compiler.hooks.done.tapPromise('PluginName'.(stats) = > {
    return new Promise((resolve, reject) = > {
    Reject (err) : resolve()
});
compiler.hooks.done.tapAsync('PluginName'.(stats, callback) = > {
    callback( err)) 
});
Copy the code

In addition to synchronous and asynchronous, the registered event functions with the name of parallel will be called in parallel, and the registered event functions with the name of Bail will be called sequentially until a method has a return value with the name of waterfall,

Each registered event function takes as its input the result returned by the previous method. Some types can be combined, such as AsyncParallelBailHook, so that it has more diverse features

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
    apply(compiler) {
        // Register a method in the compiler hooks that will be called when this stage is executed
        compiler.hooks.run.tap(pluginName, compilation= > {
            console.log("The webpack build process is starting!!!"); }); }}Copy the code

use

plugins: [ new ConsoleLogOnBuildWebpackPlugin() ]

Write your own plugin

my-plugin

├── ├─ ├─ ├─ ├─ ├─ ├─ ├─ ├─ ├── ├.class.txtCopy the code

package.json

{
  "name": "loader-order"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "build": "webpack"
  },
  "keywords": []."author": ""."license": "ISC"."devDependencies": {
    "webpack": "^ 4.43.0"."webpack-cli": "^" 3.3.12}}Copy the code

webpack.config.js

const path = require('path');
const MyPlugin = require('./plugins/my-plugin')

module.exports = {
  mode: 'production'.entry: './src/index.js'.output: {
    path: path.join(__dirname, 'dist'),
    filename: 'main.js'
  },
  plugins: [
    new MyPlugin('xfz')]}Copy the code

my-plugin.js

class MyPlugin { // Plug-in name
  constructor(options) {
    this.options = options
  }
  apply(compiler) {
    console.log('my plugin is executed')
    compiler.hooks.done.tap('My Plugin'.(/* xxx */) = > {
      // Plug-in processing logic
      console.log('my plugin options:'.this.options)
    })
  }
}

module.exports = MyPlugin
Copy the code

index.js

const a = 1
Copy the code

NPM run build, log printing

my plugin is executed
my plugin options: xfz
Copy the code

zip-plugin

├ ─ ─ dist │ ├ ─ ─ the main, js │ └ ─ ─ offline. Zip ├ ─ ─ package. The json ├ ─ ─ the plugins │ └ ─ ─ the zip - plugin. Js ├ ─ ─ the SRC │ └ ─ ─ index. The js └ ─ ─ webpack.config.jsCopy the code

package.json

{
  "name": "zip-plugin"."version": "1.0.0"."description": ""."main": "index.js"."scripts": {
    "build": "webpack"
  },
  "keywords": []."author": ""."license": "ISC"."devDependencies": {
    "loader-utils": "^ 2.0.0." "."webpack": "^ 4.43.0"."webpack-cli": "^" 3.3.12."yazl": "^ 2.5.1." "
  },
  "dependencies": {
    "jszip": "^ 3.5.0." "}}Copy the code

webpack.config.js

const path = require('path');
const ZipPlugin = require('./plugins/zip-plugin');

module.exports = {
  mode: 'production'.entry: './src/index.js'.output: {
    path: path.join(__dirname, 'dist'),
    filename: 'main.js'
  },
  plugins: [
    new ZipPlugin({
      filename: 'offline'}})]Copy the code

zip-plugin.js

// Compress the file into a zip package
const JSZip = require('jszip')
const RawSource = require('webpack-sources').RawSource
const path = require('path')

const zip = new JSZip()

class ZipPlugin {
  constructor(options) {
    this.options = options
  }
  apply(compiler) {
    // Operate on the generate file hook
    compiler.hooks.emit.tapAsync('ZipPlugin'.(compilation, callback) = > {
      const folder = zip.folder(this.options.filename)

      for (let filename in compilation.assets) {
        const source = compilation.assets[filename].source()
        folder.file(filename, source)
      }

      zip.generateAsync({ type: 'nodebuffer'})
        .then(content= > {
          const outputPath = path.join(
            compilation.options.output.path, 
            this.options.filename + '.zip'
          )

          const outputRelativePath = path.relative(
            compilation.options.output.path,
            outputPath
          )
          compilation.assets[outputRelativePath] = new RawSource(content)

          callback()
        })
    })
  }
}

module.exports = ZipPlugin
Copy the code

index.js

const a = 1
Copy the code

NPM run build

  • main.js
  • offline.zip

htmlAfterWebpackPlugin

  • Front-end cache: Stores the packaged Runtime, Vendor, and index files in localStorage and updates them incrementally
  • The server is requested for the first load and the script stored in localStorage is requested for the second load

Webpack plug-in development second open cache plug-in

Join us at ❤️

Bytedance Xinfoli team

Nice Leader: Senior technical expert, well-known gold digger columnist, founder of Flutter Chinese community, founder of Flutter Chinese community open source project, well-known developer of Github community, author of dio, FLY, dsBridge and other well-known open source projects

We look forward to your joining us to change our lives with technology!!

Recruitment link: job.toutiao.com/s/JHjRX8B