亮神知识库 亮神知识库
首页
  • 手写代码

    • 手写代码系列
  • 基础知识

    • 基础
    • JS底层
    • CSS
  • 原理
  • 浏览器
  • HTTP
  • 网络安全
  • babel
  • webpack基础
  • webpack进阶
  • Vite
  • TypeScript
  • Vue2
  • Vue3
  • Node基础

    • glob
    • 模块化机制
    • 事件循环
    • KOA2框架原理
    • Node子进程
    • cluster原理(了解)
  • 教育行业2021

    • B端
    • C端
    • 工具
  • 游戏行业2025
  • 刷题
  • 杂(待整理)
  • 学习
  • 面试
  • 实用技巧
  • 心情杂货
  • 年度总结
  • 友情链接
关于
  • 分类
  • 标签
  • 归档
  • 收藏
GitHub (opens new window)

亮神

前程明亮,未来可期
首页
  • 手写代码

    • 手写代码系列
  • 基础知识

    • 基础
    • JS底层
    • CSS
  • 原理
  • 浏览器
  • HTTP
  • 网络安全
  • babel
  • webpack基础
  • webpack进阶
  • Vite
  • TypeScript
  • Vue2
  • Vue3
  • Node基础

    • glob
    • 模块化机制
    • 事件循环
    • KOA2框架原理
    • Node子进程
    • cluster原理(了解)
  • 教育行业2021

    • B端
    • C端
    • 工具
  • 游戏行业2025
  • 刷题
  • 杂(待整理)
  • 学习
  • 面试
  • 实用技巧
  • 心情杂货
  • 年度总结
  • 友情链接
关于
  • 分类
  • 标签
  • 归档
  • 收藏
GitHub (opens new window)
  • babel

  • webpack基础

  • webpack深入

    • 源码深入
    • 手写简易webpack
    • webpack-loader机制
    • webpack插件机制
      • plugin介绍
      • 面试
    • webpack模块加载原理
    • 懒加载(未完全理解)
    • 热更新原理
    • webpack proxy原理
  • Vite

  • TypeScript

  • 打包工具
  • webpack深入
0zcl
2021-12-18
目录

webpack插件机制

# plugin介绍

plugin赋予其各种灵活的功能,例如打包优化、资源管理、环境变量注入等,它们会运行在 webpack 的不同阶段(钩子 / 生命周期),贯穿了webpack整个编译周期

// webpack/lib/Compiler.js
if (Array.isArray(plugins)) {
  for (const plugin of plugins) {
    plugin.apply(childCompiler);
  }
}
1
2
3
4
5
6

由上面部分源码,可知plugin本质上是一个拥有<code>apply方法</code>的JS对象,apply 方法 传入<code>compiler</code>参数

明白了插件的结构后,接下来以webpack hook的emit钩子为例,讲下异步事件钩子(async event hooks (opens new window))

// tapAsync: 异步事件钩子
compiler.hooks.emit.tapAsync('HelloAsyncPlugin', (compilation, callback) => {
    // Do something async...
    setTimeout(function () {
      console.log('Done with async work...');
      callback();
    }, 1000);
  }
)
// tapPromise 也是异步事件钩子
compiler.hooks.emit.tapPromise('HelloAsyncPlugin', (compilation, callback) => {
    // Do something async...
    return new Promise((resolve, reject) => {
      setTimeout(function () {
        console.log('Done with async work...');
        resolve();
      }, 1000);
    })
  }
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

webpack编译过程的hook钩子。更多Compiler Hooks (opens new window)

  • beforeRun: 在运行编译器之前添加一个钩子
  • run: Hook into the compiler before it begins reading records
  • compiler: 在创建新的compilation之前,在beforeCompile之后立即调用
  • compilation: Runs a plugin after a compilation has been created. (compilation创建之后)
  • make: 在compilation完成之前执行
  • emit: 在将内存中 assets 内容写到output目录之前
  • after-emit: 在将内存中 assets 内容写到磁盘文件夹之后
  • done: 完成所有的编译过程
  • fail: 编译失败的时候

插件demo (opens new window)

const JSZip = require('jszip')
const path = require('path')
const RawSource = require('webpack-sources').RawSource
const zip = new JSZip()

module.exports = class ZipPlugin {
  constructor(options) {
    this.options = options
  }

  apply(compiler) {
    compiler.hooks.emit.tapAsync('ZipPlugin', (compilation, callback) => {
      console.log('options', this.options, compilation.assets)
      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 => {
        console.log('content', content)
        const outputPath = path.join(compilation.options.output.path, this.options.filename + '.zip')
        console.log('outputPath', outputPath)
        const outputRelativePath = path.relative(
          compilation.options.output.path,
          outputPath
        )
        console.log('outputRelativePath', outputRelativePath)
        compilation.assets[outputRelativePath] = new RawSource(content)
      
        callback()
      })

    })
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 面试

问:是否写过 Plugin?简单描述一下编写 Plugin 的思路?

  • 插件是在webpack编译的不同的生命周期做功能扩展
  • 插件本质上是一个拥有apply方法的JS对象。因为webpack源码中是遍历plugins数组,执行每个plugin.apply(compiler), 并给apply方法传入compiler对象
  • compiler对象提供了webpack整个生命周期相关的钩子(compiler hooks), 因此可以利用compiler.hooks在不同生命周期做功能扩展

问:webpack 中 loader 和 plugin 的区别是什么

答:

  • loader是做文件转换,把A文件转换成B文件
  • plugin基于tapable事件机制,在webpack编译的生命周期节点做功能扩展
编辑 (opens new window)
上次更新: 2025/07/17, 07:17:44
webpack-loader机制
webpack模块加载原理

← webpack-loader机制 webpack模块加载原理→

最近更新
01
2024年
07-20
02
2023年
07-20
03
2022年
07-20
更多文章>
Theme by Vdoing | Copyright © 2025-2025 亮神 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式