Webpack(五)自定义Plugin实现过程

65 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。本文主要写了自定义Plugin的实现过程。

Webpack 系列专栏地址 进入

本文demo地址查看

自定义 Plugin(插件)

开发自定义 Plugin插件之前,先回想一下 Plugin 是怎么使用的。

		new htmlWebpackPlugin({
			template: './public/index.html',
			filename: 'index.html',
			chunks: ['index'],
		}),

分析代码不难得知,Plugin 本身应该是一个 ,参数通过类的构造函数传递。

打包流程

执行 npx webapck 命令后的打包流程大概是是下面这样:

  • 合并webpack配置
  • 启动构建任务
  • 执行配置项 loader plugin ...

那么插件是如何注册进去的?又是如何区分打包顺序/执行时机的?(例如CleanWebpackPlugin 是打包前执行清理目录,而htmlWebpackPlugin是资源目录输出到dist目录之前执行),这些问题都将在下面解决。

插件基本结构

插件开发的要点:

  • 插件是个类
  • 必须内置一个 apply 函数,其中applycompiler参数是实例化的webpack对象,其中包含了配置等信息
  • compiler 钩子,是webpack打包流程的生命周期文档
  • 同步钩子用 tap 注册,异步钩子用 tapAsync 注册

新建 myPlugins/my-webpack-plugin.js,根据上面的要点可以搭建出来一个插件的基本结构

class MyWebpackPlugin {
	constructor(options) {
		console.log('options----', options)
	}
	apply(compiler) {
		console.log('compiler----', compiler)
	}
}

module.exports = MyWebpackPlugin

钩子

相关的钩子www.webpackjs.com/api/compile…

访问钩子的格式:

compiler.hooks.someHook.tap(...)

emit 钩子的执行时机是生成资源到 output 目录之前,也就是可加工bundle文件的最后一步

emit 钩子注册一个事件:

class MyWebpackPlugin {
	constructor(options) {
		console.log('options----', options)
	}
	apply(compiler) {
		console.log('compiler----', compiler)
		compiler.hooks.emit.tapAsync('myWebpackPluginEmit', (compilation, cb) => {
			console.log('compilation---------', compilation.assets)
			cb()
		})
	}
}

module.exports = MyWebpackPlugin
  • 事件名可以为任意值,最好有语义,此处为myWebpackPluginEmit
  • 事件主体的函数有一个参数 compilation,以及一个 cb 回调函数参数(异步的钩子才需要)。
  • 事件主体执行完,必须执行一次 cb 回调函数(异步的钩子才需要)。
  • compilation 是在当前钩子中 原材料被加工后的样子

执行打包命令,可以看到 compilation.assets 的结构如下:

捕获.PNG

emit 钩子事件中,给bundle文件添加进去一个资源文件 1.txt

compiler.hooks.emit.tapAsync('myWebpackPluginEmit', (compilation, cb) => {
        // 添加 1.txt 文件
	const content = '我是在钩子中添加的文件'
	compilation.assets['1.txt'] = {
            source() {
		return content
            },
            size() {
                return content.length
            },
        }
	console.log('compilation---------', compilation.assets)
	cb()
})

再次执行打包命令,查看bundle文件,多出了一个 1.txt 文件。