webpack plugn 插件原理
从上文提炼出 webpack 的一些主要流程
init => run(前两个一般不用) => compile(编译开始的时候) => compilation(准备编译的整个过程) => make(开始编译) => afterCompile(编译结束) => seal(对代码进行封装,比如优化、合并…) => codeGenerate(生成代码) => emit(发射,把文件写到硬盘里面) => done
插件,就是找个地方插进去
比如:imagemin-webpack-plugin 、clean-webpack-plugin
imagemin-webpack-plugin
- 这是一个压缩图片的插件
- 文件目录非常简单
- 主要看 apply 这个函数
- 根据看源码的步骤,跳过声明
- 直接看最后的 if else,因为我们一般使用的是 webpack 4 以上的版本,所以进入 compiler.hooks 分支(见代码备注)
- 发现他监听了 emit 这个事件
- 直接看函数名字我们就能知道他的主要功能(优化项目中图片和其他外部图片)
- 对 compilation.assets (此次编译的文件)进行 map 操作,用 testFunction 判断是否是图片文件,然后执行 optimizeImage 这个方法进行图片优化(这里用到了 imagemin 这个库)
这个插件非常简单
clean-webpack-plugin
- 这是一个清理 webpack 的输出目录的插件
- 分析这个插件之前,我们先思考如果我们要写这个插件,我们应该监听哪个钩子函数?如果是init 可能可以?但是有点不妥,因为有可能初始化的过程中会报错,这样就不会产生新的文件,所以就没有必要清除之前的文件
- 很显然我们应该在 emit (写文件之前)去清理文件
- 果然他也是在监听 emit,从而去执行 handleInitial 和 removeFiles(看函数名字就知道了,这俩函数逻辑非常简单,这里暂不分析了)
- 但是细心的你肯定也发现了,为什么下面他还监听了 done?
- 因为可能 emit 的时候也会产生一些垃圾、临时文件,所以也需要清理
ProvidePlugin
- 这个插件主要用于注入全局变量,比如说每个文件都需要用到 JQuery,你需要每个文件都引入,
用这个插件他会帮你自动引入,你直接用就好了 - 使用方法很简单
- 在选项中声明好,只要你用到了 $ 或者 JQuery,就会自动引入 JQuery
vue 同理
同样,如果是我们写这个插件,我们应该监听哪个钩子函数?
猜测应该是在 compilation 或者 make 阶段
- 这个插件就不一样了,他主要监听的是 nft 的 parse 阶段
- 我们来看这个 handle 函数做了什么
- 遍历了 definition (就是选项哪个对象: {$: ‘jquery’, vue: [….]})
- 分析所有的表达式(expression),如果你用到了哪些,就帮你直接在依赖中添加(等价于帮你自动 import)
- 主要思路
正式因为插件可以在任何阶段进行魔改,所以 webpack 功能非常强大
常用插件
loader 与 plugin 的区别
- loader 是在 make 阶段执行的,而 plugin 可以在任何一个阶段插入,两者之间没有关系
- webpack 中 loader 和 plugin 的区别是什么
- 截取一个最高赞的分析一下
loader 没啥问题,就是转换文件
它丰富了webpack本身(难道 loader 没有丰富 webpack 吗?)
针对是loader结束后(plugin 可以对任何阶段进行操作)
它并不直接操作文件(他可以直接操作文件,甚至可以删文件)
就这些修正
loader 比较简单,在 make 阶段中执行,单纯的文件转换过程,而 plugin 他是对 webpack 的功能进行拓展,他是基于事件机制,对 webpack 的每个阶段都可以进行介入,做一些功能(任何你想做的)。
如何自己写一个 plugin
必须名声一个 class
必须有一个 apply 函数,并且接受一个 compiler 参数
接下来对某一个钩子进行监听,在写你的主要逻辑
举例
一个简单的在 done 之后打印一句话,和使用方法
用到的主要知识
对 webpack hooks 的了解
对编译原理的了解
对 chunk、hash、module、dep、factor 等概念的理解