Esbuild vs Babel

前言

最近在做等create-react-app-webpack5官方支持的同时, 去研究了一下最近新出的一些打包工具, 如vite/snowpack, 发现了一些他们各自的优缺点, 在此总结一下

打包工具

webpack

webpack就不用过多介绍了, 完善的生态和插件系统, 各工具链必须要支持的框架, 基本满足所有需求, webpack5的本地缓存机制出现后也极大的提高了开发体验

snowpack

相比起webpack来说, 主要优化了bundle构建的过程, 不再将所有依赖内容打包压缩到bundle.js中, 而是拆分成各自的小文件, 这样达到O(1)的构建速度, 贴个官方的对比图

但缺点也是很明显的: 社区支持不够, 各插件的整合程度不强, 如果需要用一些新功能需要自己采坑, 可能会比较困难. 而且还有个比较严肃的问题: 这种在开发期分离打包的做法, 会导致开发期和生产环境代码不一致, 风险很大. 所以在尝试了一下react-demo后, 暂时先搁置

vite

vite是最近两年的热门打包工具之一, 也有受到snowpack启发和影响, 同样是开发期通过es-modules加载依赖库, 但有更好的官方支持和社区环境, 以及一个比较大的新特性: 使用了esbuild来打包js代码

按照官方文档初始化了一个react项目后, 确实有了丝滑的开发体验, 打包速度也是非常快, 但同样存在开发期和打包生产环境内容不一致的问题, 而且polyfill都需要自己引用解决, 在正式项目上还是不太方便使用

esbuild

虽然vite并不太适合现在的react项目开发, 但是里面的esbuild却是个非常好的工具, 其实在webpack中也是可以使用esbuild来打包的

esbuild-loader

esbuild可以简单的理解为: 使用go语言开发的babel编译器

webpack中使用也非常简单: 直接用esbuild-loader替换掉babel-loader即可

这里直接简单粗暴的通过索引替换掉babel-loader, 如果要生产环境使用可以使用findfilter查询到索引后替换

1
2
3
4
5
6
7
8
9
10
11
12
13
config.module.rules[1].oneOf[3].loader = require.resolve('esbuild-loader');
config.module.rules[1].oneOf[3].options = {
loader: 'tsx',
target: 'es2015',
};

config.module.rules[1].oneOf.splice(4, 1);

config.optimization.minimizer = [
new ESBuildMinifyPlugin({
target: 'es2015',
}),
];

替换完成后, 执行npm start, 在webpack5的加持下可以做到10s内启动完成, 相比起使用babel-loader25s来说, 提高了大约150%的构建速度, 同时, 也不存在vite/snowpack的开发环境和生产环境代码不一致的问题, 看起来是个比较好的选择

问题

虽然esbuild极大的提高了编译速度, 但是存在一个硬伤: 暂时还不支持插件, 这意味着无法自定义或者按需修改编译内容. 而现在很多工具链都是依赖babel-plugin来实现各自的功能的.

styled-jsx

比如常用的styled-jsx, 是通过[babel-plugin]styled-jsx/babel插件来实现的自定义解析jsx, 以及现在支持的babel-macro也需要使用babel-plugin-macros. 使用esbuild的情况下, 就完全无法使用styled-jsx

rollup中的babel插件也是同样可以支持styled-jsx的, 但vite虽然使用的rollup, 但由于同样使用esbuild, 所以无法支持styled-jsx

istanbul

其次是代码覆盖率插件, 上个月研究的cypress的代码覆盖率生成, 是依赖babel-plugin-istanbul注入代码调用埋点的, 在esbuild打包时没有办法注入, 所以也就没有办法获取覆盖率了

结论

兜兜转转饶了一圈, 结果还是回归原始的webpack+babel老套路了. 虽然前端工程迭代足够快, 但想达到更高的高度, 还是需要时间沉淀优化的

作者

Mosby

发布于

2021-08-19

许可协议

评论