如何在已有的 Vue CLI 项目使用 esbuild

2022 年 04 月 16 日

背景

我们的门户网站项目(Vue 2 / Vue CLI 45 / TypeScript / Element UI)前端部分编译所需时间太长,因此开始考虑在不对已有项目进行过于伤筋动骨的调整的前提下,提升编译速度的方式。

由于 Vite 使用了 esbuild 进行编译速度的提升,我们想到了一个主意:借助 esbuild-loader,把 Vue CLI 中的 Babel 替换为 esbuild。

分析

在项目根目录执行 npx vue-cli-service inspect,可以看到最终生成的 Webpack 配置中,以下部分涉及到了 babel-loader:

      /* config.module.rule('js') */
      {
        test: /\.m?jsx?$/,
        exclude: [
          function () { /* omitted long function */ }
        ],
        use: [
          /* config.module.rule('js').use('babel-loader') */
          // (略)
        ]
      },
      /* config.module.rule('ts') */
      {
        test: /\.ts$/,
        use: [
          /* config.module.rule('ts').use('babel-loader') */
          // (略)
          /* config.module.rule('ts').use('ts-loader') */
          // (略)
        ]
      },
      /* config.module.rule('tsx') */
      {
        test: /\.tsx$/,
        use: [
          /* config.module.rule('tsx').use('babel-loader') */
          // (略)
          /* config.module.rule('tsx').use('ts-loader') */
          // (略)
        ]
      }
    ]

由此可知,我们需要将 jststsx 的默认规则进行清空处理,然后让 jststsx 使用 esbuild-loader

操作

首先,安装 esbuild-loader

npm i -D esbuild-loader

然后,在 vue.config.js 下的 chainWebpack 中加入以下内容:

// 清空已有的使用 `babel-loader` 的规则
config.module.rule("js").uses.clear();
config.module.rule("ts").uses.clear();
config.module.rule("tsx").uses.clear();

// 注入使用 `esbuild-loader` 的新规则
config.module.rule("js")
    .test(/\.m?jsx?$/)
    .use("esbuild-loader")
    .loader("esbuild-loader")
    .options({
        loader: "jsx",
        target: "es2015"
    })
    .end();
config.module.rule("ts")
    .test(/\.ts$/)
    .use("esbuild-loader")
    .loader("esbuild-loader")
    .options({
        loader: "ts",
        target: "es2015"
    })
    .end();
config.module.rule("tsx")
    .test(/\.tsx$/)
    .use("esbuild-loader")
    .loader("esbuild-loader")
    .options({
        loader: "tsx",
        target: "es2015"
    })
    .end();

就可以了。

已知问题

  • 如果项目中有使用到 Web Worker,肯定会炸掉,出现 TypeError: Failed to construct 'URL': Invalid URL 错误。采用 Babel 则正常工作。

遗憾

尽管 esbuild 是好文明,我们依然无法在那个门户网站项目中使用;因为我们项目要求兼容 IE11,而 esbuild 目前最低只能编译到 ES2015,这就导致编译产物无法在 IE11 等不(完全)支持 ES2015 的浏览器中运行;不过,在本地调试时还是很爽的,因为开发环境冷启动和热更新速度确实快了不少。

不过,如果你的项目不需要兼容 IE11 等老浏览器,但恰好还没有升级到 Vue 3 + Vite,完全可以试一试。能快一点是一点啊)