使用esbuild-loader加速前端工程打包速度(亲测提速50%)
在五月底项目上线的时候突然被卡住了,部署不了,因为云效的构建总时长有限制。为了给项目节省资源,想着从前端工程的角度做一些优化,主要使用的工具是esbuild-loader
。
项目背景
前端项目使用的工程化设施有点久远,原始项目使用的是 Webpack3 + Ant-Design 3 + Mobx,后来为了前端UI规范标准化,又在引入了新的G3组件库(基于Ant-Design 4)。
大约梳理了一下构建脚本需要处理的工作如下:
- 基础loader处理工作(如js、less、图片)
- dll公共包处理
- Ant-Design 3 与 ant-design 4 共存
- 注入环境变量
- ES-Lint检查
- 其他项目运行相关
所以项目的打包构建脚本中有不少历史包袱,在改造的同时需保证原项目所有功能正常运行。
找到的解决方案
在网上找了一圈解决方案,大约整理如下:
- 升级 Webpack
- 使用 Vite 重写
- 使用 ESBuild 重写
- 使用 esbuild-loader “无痛”改造
最后选了方案4.
对比了一下,其实开始想使用方案一,也就是升级webpack版本,但时间有点紧,需要把之前所以的配置重写,在 webpack 配置这块我也不是特别有经验,于是做为备选。方案2和3也是一样,需要重新搭建脚手架,可能需要排在后期来尝试。
接入方法
esbuild-loader
这个插件顾名思义,就是把esbuild
的能力包装成Webpack的loader来实现js、ts、css等资源的打包编译。
安装 esbuild-loader
// npm
npm i -D esbuild-loader
//yarn
yarn add -D esbuild-loader
配置loader
esbuilder-loader
支持绝大部分前端常用的文件类型打包,本项目中主要是前端js页面文件打包比较耗时,所以只替换了js文件相关的打包部分。
rules: [
{
test: /\.(js|jsx)$/,
// use: 'happypack/loader?id=jsx',
loader: 'esbuild-loader?id=jsx',
options: {
loader: 'tsx',
target: 'es2015',
// 定义你需要的环境变量
define: {
ENV: JSON.stringify(process.env.ENV || 'dev'),
}
},
include: path.join(__dirname, 'src'),
exclude: /(node_modules)/
},
// other rules
]
这里为啥.jsx
使用的是tsx
的loader?这个后面在问题里再细说。
PS:真实项目中改造其实更加复杂,这里只是一个简单的demo,由于相关问题都是具体项目相关,这里不赘述了。
效果实测试
使用原来的happypack
的打包时间
优化后的打包时间:
从42s变成21s,速度提升50%。
遇到的问题
改造过程中遇到了不少问题,这里也统一记录一下。
环境变量丢失
原来使用DefinePlugin
完成的操作。
解决方案要手动转移到esbuild-loader
的define
字段。
mobx失效
因为mobx使用的是@
装饰器,但esbuild-loader
中的jsx
不支持装饰器语法。
解决方案是使用tsx
的loader。
less样式丢失
因为原来的ant-design 3的样式是通过babel-import-plugin
实现的,esbuild-loader
目前不支持。
解决方案全局引入ant-design样式
不支持原生esbuild插件
esbuild-loader
使用的是esbuild
的trasform
API,而它的插件是使用build方法时注入的。这个的详细内容可以参考:
Possibility of using esbuild plugins · Discussion #119 · privatenumber/esbuild-loader
方案总结
使用esbuild-loader
可以快速将老项目中的loader替换,借用esbuild
的能力实现前端工程的快速打包构建。
优点
- 改造小,几乎是开着火车换轮子式的外科手术操作,对项目影响最小,时间就是生命。
- 速度提升明显,尤其是对于页面繁多的老工程项目。
缺点
- 没那么快(我个人猜测完全改造成vite会更快)
- 功能还比较简陋,不支持原生插件,还是要踩不少坑
后续规划
- 如果时间允许,想尝试直接转 vite。
- 如果时间紧,那就尝试升级下webpack版本(大概率是这条路子)
欢迎有相关经验的大佬留言提出更好的方案。