webpack性能优化(1)-使用esbuild-loader替换babel-loader

2,177 阅读3分钟

什么是esbuild

esbuild是同webpack一样,作为前端的打包工具,一个打包速度比较快的打包和压缩工具

[官网链接]  esbuild.github.io/ 

webpack结合esbuild-loader使用

但是现在我们大多数项目,使用的还是webpack,如果整体将webpack迁移到esbuild,费时费力,所以我们仍然可以使用webpack,将babel-loader以及ts-loader替换为esbuild-loader,具体例子可以通过github.com/privatenumb…github.com/privatenumb…查看,但是在使用的过程中,还需要注意webpack本身的target属性,tsconfig的target属性以及esbuild-loader提供的target属性,建议将这三个属性一致。(不过目前发现使用esbuild-loader时,此loader还会进行部分代码语法的检查,不能仅做编译代码使用,暂未发现可以关闭语法检查的开关)

esbuild的打包速度为什么快

(1) 语言优势

编译器和解释器将人类可读的代码转换为计算机可读的机器代码。 对于编译型语言,目标计算机以编译语言直接翻译程序。 而对于解释型语言,源代码不会直接由目标计算机翻译,而是由另一个程序(即解释器)读取并执行代码

webpack基于js实现,esbuild基于go语言实现。

js作为一门解释型语言,程序每次执行都需要先由解释器一边将源码翻译成机器语言,一边调度执行;而go是一种编译型语言,在编译阶段就已经将源码转为机器码,启动时只需要直接执行这些机器码即可。相当于,当esbuild解析我们的js代码文件时,node可能正忙于解析我们打包工具webpack的js代码。

(2)多线程优势

go语言具有多线程运行能力,而js本质是一门单线程语言,虽然引入了WebWorker规范后,我们可以使用js在浏览器、Node中实现多线程操作,但是在查阅资料后webpack中并未使用webworker提供的多线程能力。反观esbuild,尽可能饱和地使用各个CPU核,特别是打包过程的解析、代码生成阶段的过程。

(3)与ts-loader以及babel-loader对比

ts-loader

webpack的ts加载器,将ts编译成js。ts-loader在内部是调用了ts的官方编译器--tsc,所以ts-loader和tsc是共享tsconfig.json文件的。

module.exports = {
  ...
  module: {
    rules: [
      {
        test: /.tsx?$/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              transpileOnly: true // 只做语言转换,而不做类型检查
            }
          }
        ]
      }
    ]
  }
}

为了性能的提升,我们一般会设置transpileOnly: true,只做语言的转换,而不做类型检查。esbuild同样完全抛弃了ts的类型检查,只做代码转换。

babel-loader(搬运官网)

在webpack中使用其将es6+高版本js代码转译为es5低版本,此过程可能需要经过多次数据转换:

  • Webpack 读入源码,此时为字符串形式
  • Babel 解析源码,转换为 AST 形式
  • Babel 将源码 AST 转换为低版本 AST
  • Babel 将低版本 AST generate 为低版本源码,字符串形式
  • Webpack 解析低版本源码
  • Webpack 将多个模块打包成最终产物

源码需要经历 string => AST => AST => string => AST => string ,在字符串与 AST 之间反复横跳。

esbuild最大的不同就是能够在多个编译阶段共用相似的AST结构,尽可能减少字符串到AST的结构转换

总结

对我个人而言,webpack算是前端方面天花板较高的部分,鄙人也是一知半解,仍处于学习的阶段,如果不想体验webpack结合esbuild-loader这种模式,可以根据项目推荐使用vite,从vue官方正式宣布以后vue默认版本为vue3时,自己也是接触到了vite这个工具,并且目前vite已经内置了esbuild,有兴趣的话可以尝试下。