从上文提炼出 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 等概念的理解
网友评论