Open lulujianglab opened 5 years ago
前端技术发展迅速,各种框架工具库层出不穷,诸如'大前端'、'前后端分离'、'本地开发构建'等等热门词汇我们更是屡见不鲜,这些现代前端技术基石自然离不开 webpack ,webpack 的工作更离不开各类插件 Plugin 的支持
webpack
相信不少小伙伴在平时的项目开发中使用过 Webpack Plugins, 我的上篇文章 Webpack4 和 Babel 7 全套配置也有介绍搭配 Webpack Plugins 的配置过程,但对于自己开坑写 webpack ,可能是比较少的(包括我寄几),这两天抽空看了下 webpack 中文文档(v4.15.1),又逢读到 Webpack 原理-编写 Plugin 好文章一篇,豁然开朗,所以简单的介绍下插件开发的过程
Webpack Plugins
例子中使用的插件我已经发到 npm 用来测试了
webpack 插件是一个具有 apply 属性的 JavaScript 对象。apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问
apply
webpack compiler
compiler
class BasicPlugin{ // 在构造函数中获取用户给该插件传入的配置 constructor(options){ } // Webpack 会调用 BasicPlugin 实例的 apply 方法给插件实例传入 compiler 对象 apply(compiler){ compiler.hooks.run.tap(pluginName, compilation => { // console.log("webpack 构建过程开始!") }) } } // 导出 Plugin module.exports = BasicPlugin
compiler hook 的 tap 方法的第一个参数,应该是驼峰式命名的插件名称。建议为此使用一个常量,以便它可以在所有 hook 中复用
compiler hook
tap
hook
const BasicPlugin = require('BasicPlugin.js') module.export = { plugins:[ new BasicPlugin(options), ] }
new BasicPlugin(options)
basicPlugin.apply(compiler)
在基本结构中比较重要的两个对象就是 Compiler 和 Compilation ,它们是 Plugin 和 Webpack 之间的桥梁
Compiler
Compilation
Plugin
Webpack
Compiler 对象包含了 Webpack 环境所有的的配置信息,包含 options,loaders,plugins 这些信息,这个对象在 Webpack 启动时候被实例化,它是全局唯一的,可以简单地把它理解为 Webpack 实例 Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack 以开发模式运行时,每当检测到一个文件变化,一次新的 Compilation 将被创建。Compilation 对象也提供了很多事件回调供插件做扩展。通过 Compilation 也能读取到 Compiler 对象
Compiler 对象包含了 Webpack 环境所有的的配置信息,包含 options,loaders,plugins 这些信息,这个对象在 Webpack 启动时候被实例化,它是全局唯一的,可以简单地把它理解为 Webpack 实例
Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack 以开发模式运行时,每当检测到一个文件变化,一次新的 Compilation 将被创建。Compilation 对象也提供了很多事件回调供插件做扩展。通过 Compilation 也能读取到 Compiler 对象
Compiler 和 Compilation 的区别在于
Compiler 代表了整个 Webpack 从启动到关闭的生命周期,而 Compilation 只是代表了一次新的编译
webpack 就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果
插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理
Webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作
Webpack 的事件流机制保证了插件的有序性,使得整个系统扩展性很好,事件流机制应用了观察者模式
/** * 广播出事件 * event-name 为事件名称,注意不要和现有的事件重名 * params 为附带的参数 */ compiler.apply('event-name',params) /** * 监听名称为 event-name 的事件,当 event-name 事件发生时,函数就会被执行。 * 同时函数中的 params 参数为广播事件时附带的参数。 */ compiler.hooks.event-name.tap('plugin-name',function(params) { })
apply 方法是必须要有的,因为当我们使用一个插件时( new somePlugins({})),webpack 会去寻找插件的 apply 方法并执行
new somePlugins({})
compiler.hooks.event-name.tap() 就相当于给 compiler 设置了事件监听,当监听到 event-name (Compilation)事件,应该做些相应操作,类似于 document.addEventListener
compiler.hooks.event-name.tap()
event-name
document.addEventListener
下面写一个插件名为 LogWebpackPlugin 的例子,作用是 Webpack 在执行过程中打印一些日志,实现该插件非常简单,完整代码如下
class LogWebpackPlugin { constructor(doneCallback, emitCallback) { // 存下在构造函数中传入的回调函数 this.emitCallback = emitCallback this.doneCallback = doneCallback } apply(compiler) { compiler.hooks.emit.tap('LogWebpackPlugin', () => { // 在 emit 事件中回调 emitCallback this.emitCallback() }) compiler.hooks.done.tap('LogWebpackPlugin', () => { // 在 done 事件中回调 doneCallback this.doneCallback() }) compiler.hooks.compilation.tap('LogWebpackPlugin', () => { // compilation('编译器'对'编译ing'这个事件的监听) console.log("The compiler is starting a new compilation...") }) compiler.hooks.compile.tap('LogWebpackPlugin', () => { // compile('编译器'对'开始编译'这个事件的监听) console.log("The compiler is starting to compile...") }) } } // 导出插件 module.exports = LogWebpackPlugin
使用该插件的方法如下
npm i log-webpack-plugin --D
const logWebpackPlugin = require('log-webpack-plugin') module.exports = { plugins: [ // 在初始化 logWebpackPlugin 时传入了两个参数,分别是在成功时的回调函数和模块完成转换的回调函数; new logWebpackPlugin(() => { // Webpack 模块完成转换成功 console.log('emit 事件发生啦,所有模块的转换和代码块对应的文件已经生成好~') } , () => { // Webpack 构建成功,并且文件输出了后会执行到这里,在这里可以做发布文件操作 console.log('done 事件发生啦,成功构建完成~') }) ] }
npm run build 编译结果
npm run build
完整插件可见 log-webpack-plugin
前言
前端技术发展迅速,各种框架工具库层出不穷,诸如'大前端'、'前后端分离'、'本地开发构建'等等热门词汇我们更是屡见不鲜,这些现代前端技术基石自然离不开
webpack
,webpack 的工作更离不开各类插件 Plugin 的支持相信不少小伙伴在平时的项目开发中使用过
Webpack Plugins
, 我的上篇文章 Webpack4 和 Babel 7 全套配置也有介绍搭配Webpack Plugins
的配置过程,但对于自己开坑写 webpack ,可能是比较少的(包括我寄几),这两天抽空看了下 webpack 中文文档(v4.15.1),又逢读到 Webpack 原理-编写 Plugin 好文章一篇,豁然开朗,所以简单的介绍下插件开发的过程例子中使用的插件我已经发到 npm 用来测试了
基本插件结构
配置
new BasicPlugin(options)
初始化一个 BasicPlugin 获得其实例basicPlugin.apply(compiler)
给插件实例传入 compiler 对象compiler hook
的tap
方法监听到 Webpack 广播出来的事件,hook 上绑定了事件名称,第二个参数是回调函数Compiler 和 Compilation
在基本结构中比较重要的两个对象就是
Compiler
和Compilation
,它们是Plugin
和Webpack
之间的桥梁Compiler 和 Compilation 的区别在于
Compiler 代表了整个 Webpack 从启动到关闭的生命周期,而 Compilation 只是代表了一次新的编译
事件流
webpack 就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果
插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理
Webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条生产线中,去改变生产线的运作
Webpack 的事件流机制保证了插件的有序性,使得整个系统扩展性很好,事件流机制应用了观察者模式
apply
方法是必须要有的,因为当我们使用一个插件时(new somePlugins({})
),webpack 会去寻找插件的 apply 方法并执行compiler.hooks.event-name.tap()
就相当于给 compiler 设置了事件监听,当监听到event-name
(Compilation)事件,应该做些相应操作,类似于document.addEventListener
实战
下面写一个插件名为 LogWebpackPlugin 的例子,作用是 Webpack 在执行过程中打印一些日志,实现该插件非常简单,完整代码如下
使用该插件的方法如下
npm run build
编译结果完整插件可见 log-webpack-plugin