esbuild快速打包助力webpack开发研效
背景
随着项目开发周期越来越长,项目越来越来大,基于webpack构建的项目打包速度会越来越长。 如果采用ts + tsx构成,开发环境下编译速度慢的情况会非常明显 目前接手项目的打包速度如下
首次打包
2min30s
单次编辑打包
15s
迫切的需要提高构建效率
优化思路
基于vite重构打包内容
优点:
- 直接启动开发服务器,对请求模块进行实时编译,进行毫秒级别打包
- 天然支持HMR,浏览器仅需要请求改动模块
缺点:
- 目前对代码打包方式侵入较大
- 目前vite工具对react支持上可能存在缺陷
采用esbuild-loader + webpack
优点:
- 可以快速提高打包速度
- 对现有打包工程侵入较小,可以仅以插件的形式注入
缺点:
- 优化点不够彻底,仍有较大提升空间
- esbuild-loader本身提供的能力较弱,可能需要针对修复
优化方案
单次编译速度优化
目前采用esbuild-loader方案进行优化
单次优化只针对ts tsx占比比较大的单一类型进行优化
通过 webpackEsBuildPlugin 插件介入webpack生命周期 替换掉ts-loader babel-loader 为 esbuild-loader
提前记录文件变化点 方便后期做热更新校验优化
首次编译速度优化
针对首次耗时较大的babel-loader开启多线程打包
采用 HappyPack 进行打包拆分
esbuild-loader使用问题
不支持装饰器
esbuild本身不支持ts装饰器
解决方案
使用oneOf对单文件采用单一loader, 当returen false的时候即采用babel-loader + ts-loader形式打包文件;
oneOf: [
{
test: filePath => {
if (!filePath) {
return false;
}
try {
const fileContent = fs.readFileSync(filePath).toString();
return !hasDecorator(fileContent);
} catch (e) {
return false;
}
},
use: [
{
loader: 'esbuild-loader',
options: {
loader: 'tsx',
target: 'es2018',
},
},
],
},
{
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
],
},
],
判断输入文件是否有装饰器
/** 判断是否具有装饰器 */
function hasDecorator(fileContent, offset = 0) {
const atPosition = fileContent.indexOf('@', offset);
if (atPosition === -1) {
return false;
}
if (atPosition === 1) {
return true;
}
if (["'", '"'].includes(fileContent.substr(atPosition - 1, 1))) {
return hasDecorator(fileContent, atPosition + 1);
}
return true;
}
不支持循环依赖
分离依赖项,解决循环依赖
不支持按需加载
因为是在开发环境使用esbuild,开发环境可以进行全量引入。
以antd为例,生产环境必须开启按需引入
开发环境对于按需引入导致的样式缺失部分只能采取全量引入
开发环境需要打包成es5
开发环境需要兼容低端浏览器,对于tsconfig, target需要保留为es5
通过ts-loader打包出来的es5代码和esbuild打包出来的es6代码可能存在冲突
开发环境需要指定配置,将ts-loader设置成es6代码
尽量保留开发环境不变的前提下,写入config文件
{
"extends": "../../tsconfig.json", // 继承开发环境的配置
"compilerOptions": {
"target": "es6", // 覆盖设置
"baseUrl": "../../src", // 注意根目录修改
},
"include": ["../../src"], "exclude": ["../../node_modules", "../../build", "../../dist"]
}
查阅文档得知最新的ts-loader设置可以使用
configFile字段指定对应的json文件
如果想全局替换
可以使用
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
进行更换
如果想替换esbuild下config指定配置可以通过
MinifyPlugin
下替换tsconfigRaw
后期迭代更新计划
- 使用vite重构打包方式(慎重考虑)
- 把开发环境更多的loader改成esbuild打包
- 使用splitcode单独拆分库进行打包(dllpugin因为库更新问题暂不考虑)
优化效果
单次编译速度
10s-15s => 1-3s
首次编译速度
2min30s => 20s
转载自:https://juejin.cn/post/7001013395692617735