plugin 的特征
webpack 插件有以下特征
-
是一个独立的模块。
-
模块对外暴露一个 js 函数。
-
函数的原型
(prototype)
上定义了一个注入compiler
对象的apply
方法。 -
apply
函数中需要有通过compiler
对象挂载的 webpack 事件钩子,钩子的回调中能拿到当前编译的compilation
对象,如果是异步编译插件的话可以拿到回调 callback。 -
完成自定义子编译流程并处理
complition
对象的内部数据。 -
如果异步编译插件的话,数据处理完成后执行 callback 回调。
class HelloPlugin {
// 在构造函数中获取用户给该插件传入的配置
constructor(options) {}
// Webpack 会调用 HelloPlugin 实例的 apply 方法给插件实例传入 compiler 对象
apply(compiler) {
// 在emit阶段插入钩子函数,用于特定时机处理额外的逻辑;
compiler.hooks.emit.tap(‘HelloPlugin’, (compilation) => {
// 在功能流程完成后可以调用 webpack 提供的回调函数;
})
// 如果事件是异步的,会带两个参数,第二个参数为回调函数,
compiler.plugin(‘emit’, function (compilation, callback) {
// 处理完毕后执行 callback 以通知 Webpack
// 如果不执行 callback,运行流程将会一直卡在这不往下执行
callback()
})
}
}
module.exports = HelloPlugin
复制代码
-
webpack 读取配置的过程中会先执行
new HelloPlugin(options)
初始化一个HelloPlugin
获得其实例。 -
初始化
compiler
对象后调用HelloPlugin.apply(compiler)
给插件实例传入 compiler 对象。 -
插件实例在获取到
compiler
对象后,就可以通过compiler.plugin
(事件名称, 回调函数) 监听到 Webpack 广播出来的事件。并且可以通过compiler
对象去操作 Webpack。
事件流机制
webpack 本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心就是 Tapable
。
Webpack 的 Tapable
事件流机制保证了插件的有序性,将各个插件串联起来, Webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条 webapck 机制中,去改变 webapck 的运作,使得整个系统扩展性良好。
Tapable
也是一个小型的 library,是 Webpack 的一个核心工具。类似于 node 中的 events 库,核心原理就是一个订阅发布模式
。作用是提供类似的插件接口。方法如下:
// 广播事件
compiler.apply(‘event-name’, params)
compilation.apply(‘event-name’, params)
// 监听事件
compiler.plugin(‘event-name’, function (params) {})
compilation.plugin(‘event-name’, function (params) {})
复制代码
我们来看下 Tapable
function Tapable() {
this._plugins = {}
}
//发布name消息
Tapable.prototype.applyPlugins = function applyPlugins(name) {
if (!this._plugins[name]) return
var args = Array.prototype.slice.call(arguments, 1)
var plugins = this._plugins[name]
for (var i = 0; i < plugins.length; i++) {
plugins[i].apply(this, args)
}
}
// fn订阅name消息
Tapable.prototype.plugin = function plugin(name, fn) {
if (!this._plugins[name]) {
this._plugins[name] = [fn]
} else {
this._plugins[name].push(fn)
}
}
//给定一个插件数组,对其中的每一个插件调用插件自身的apply方法注册插件
Tapable.prototype.apply = function apply() {
for (var i = 0; i < arguments.length; i++) {
arguments[i].apply(this)
}
}
复制代码
Tapable
为 webpack 提供了统一的插件接口(钩子)类型定义,它是 webpack 的核心功能库。webpack 中目前有十种 hooks,在 Tapable 源码中可以看到,他们是:
exports.SyncHook = require(‘./SyncHook’)
exports.SyncBailHook = require(‘./SyncBailHook’)
exports.SyncWaterfallHook = require(‘./SyncWaterfallHook’)
exports.SyncLoopHook = require(‘./SyncLoopHook’)
exports.AsyncParallelHook = require(‘./AsyncParallelHook’)
exports.AsyncParallelBailHook = require(‘./AsyncParallelBailHook’)
exports.AsyncSeriesHook = require(‘./AsyncSeriesHook’)
exports.AsyncSeriesBailHook = require(‘./AsyncSeriesBailHook’)
exports.AsyncSeriesLoopHook = require(‘./AsyncSeriesLoopHook’)
exports.AsyncSeriesWaterfallHook = require(‘./AsyncSeriesWaterfallHook’)
复制代码
Tapable
还统一暴露了三个方法给插件,用于注入不同类型的自定义构建行为:
-
tap:可以注册同步钩子和异步钩子。
-
tapAsync:回调方式注册异步钩子。
-
tapPromise:Promise 方式注册异步钩子。
webpack 里的几个非常重要的对象,Compiler
, Compilation
和 JavascriptParser
都继承了 Tapable
类,它们身上挂着丰富的钩子。
编写一个插件
一个 webpack 插件由以下组成:
-
一个 JavaScript 命名函数。
-
在插件函数的 prototype 上定义一个 apply 方法。
-
指定一个绑定到 webpack 自身的事件钩子。
-
处理 webpack 内部实例的特定数据。
-
功能完成后调用 webpack 提供的回调。
下面实现一个最简单的插件
class WebpackPlugin1 {
constructor(options) {
this.options = options
}
apply(compiler) {
compiler.hooks.done.tap(‘MYWebpackPlugin’, () => {
console.log(this.options)
})
}
}
module.exports = WebpackPlugin1
复制代码
然后在 webpack 的配置中注册使用就行,只需要在 webpack.config.js
里引入并实例化就可以了:
const WebpackPlugin1 = require(‘./src/plugin/plugin1’)
module.exports = {
entry: {
index: path.join(__dirname, ‘/src/main.js’),
},
output: {
path: path.join(__dirname, ‘/dist’),
filename: ‘index.js’,
},
plugins: [new WebpackPlugin1({ msg: ‘hello world’ })],
}
复制代码
此时我们执行一下 npm run build
就能看到效果了
Compiler 对象 (负责编译)
Compiler
对象包含了当前运行 Webpack 的配置,包括 entry
、output
、loaders
等配置,这个对象在启动 Webpack 时被实例化,而且是全局唯一的。Plugin
可以通过该对象获取到 Webpack 的配置信息进行处理。
compiler 上暴露的一些常用的钩子:
下面来举个例子
class WebpackPlugin2 {
constructor(options) {
this.options = options
}
apply(compiler) {
compiler.hooks.run.tap(‘run’, () => {
console.log(‘开始编译…’)
})
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
总结
前端资料汇总
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
-
框架原理真的深入某一部分具体的代码和实现方式时,要多注意到细节,不要只能写出一个框架。
-
算法方面很薄弱的,最好多刷一刷,不然影响你的工资和成功率😯
-
在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。
-
要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!
喜欢这篇文章文章的小伙伴们点赞+转发支持,你们的支持是我最大的动力!
面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**
-
框架原理真的深入某一部分具体的代码和实现方式时,要多注意到细节,不要只能写出一个框架。
-
算法方面很薄弱的,最好多刷一刷,不然影响你的工资和成功率😯
-
在投递简历之前,最好通过各种渠道找到公司内部的人,先提前了解业务,也可以帮助后期优秀 offer 的决策。
-
要勇于说不,对于某些 offer 待遇不满意、业务不喜欢,应该相信自己,不要因为当下没有更好的 offer 而投降,一份工作短则一年长则 N 年,为了幸福生活要慎重选择!!!
喜欢这篇文章文章的小伙伴们点赞+转发支持,你们的支持是我最大的动力!