前言
随着业务发展,公司后台系统越来越多页面,开发构建速度从10s飙升到1、2分钟,甚至有的机器因为内存问题,项目跑不动!这怎么能忍!于是乎,写个插件
webpack插件的基本结构
通过翻阅webpack文档得知,插件就是一个具有apply函数的类,如下
class Plugin() {
constructor() {}
apply(compiler) {
// 做些事情
}
}
写插件需要关注的几个核心点
-
compiler
webpack整个生命周期的对象,有自己的hooks
-
compilation
构建的产物,有自己的hooks
-
各种hook
hook,指在特定时期会执行的钩子函数
ps:因为了解不深,只能补充一些我自己的概念,如有需要可自行查阅官方文档,有更仔细的说明
怎么减少构建速度?
我的思路是,在开发阶段,比如开发A需求,我们通常只需要关注A需求的模块(具体为路由,页面),那除了A的这些模块,是不是可以选择性地不构建它呢?答案是:可以的
于是我们插件的开发思路可以划分为以下几个步骤
- 定义一个apply函数的插件类
- 在apply函数中来控制构建哪些模块
- 过滤完成,减少了不必要的构建,从而减少了构建时间
具体代码
1、监听模块创建时的hook
- normalModuleFactory:
import
形式的模块的工厂函数 - contextModuleFactory:
require.context
形式的模块的工厂函数
工厂函数也有自己的hook
- beforeResolve:
解析模块具体内容之前的钩子
,可以通过返回false来阻止解析
apply(compiler) {
compiler.hooks.normalModuleFactory.tap(this.name, (nmf) => {
nmf.hooks.beforeResolve.tap(this.name, this.checkIgnore)
})
compiler.hooks.contextModuleFactory.tap(this.name, cmf => {
cmf.hooks.beforeResolve.tap(this.name, this.checkIgnore)
})
compiler.hooks.done.tap(this.name, () => {
// 构建结束做些什么
})
}
2、判断模块路径是否满足过滤规则,是则停止解析
回调函数checkIgnore接受解析的一些上下文信息,比如
- request:请求路径
- context:请求的上下文
举个例子,我们有个a文件
// a.js
import './b.js'
当解析到b模块的时候,context
就是a的文件路径,request
就是'./b.js'
checkIgnore(resolveData) {
if (!resolveData) {
return resolveData
}
const { request, context } = resolveData
if (request.indexOf('./b.js') !== -1) {
// 停止解析这个模块
return false
}
return resolveData
}
3、结合自己项目的实际场景,通过配置文件来控制构建
我这边的做法是
- 新增加构建dev命令
- 生成config,根据config的数据来选择性构建哪些页面,哪些路由
- 完成构建
结尾
webpack真的太太太太难了,虽然脚本最后成功投入在开发环境使用了,但是期间也踩了不少坑,比如解析文件路径出错,模块找不到导致运行不起来等问题,但也是在不断踩坑中,加强了对webpack的一些实际理解,有一说一,webpack万物皆为模块的想法真的牛逼!