随着项目越来越大后,咱们脚手架使用 babel
进行代码编译感觉越来越慢。为了提升编译速度,尝试了一下使用 esbuild
后发现速度提升明显,于是决定将 esbuild
正式集成到脚手架中。
主要内容
- 为什么要使用 esbuild
- 如何集成
- 遇到的问题及解决方案
为什么要使用 esbuild ?
- esbuild 基于 go 实现,构建速度非常快(官网声称比 webpack5 快 10-100 倍)
- 目前 esbuild 生态已相对成熟,基本满足替换目前使用的 babel 的条件
- 项目越来越大后,使用 babel 确实感觉比较慢,并且经过对比测试后,使用 esbuild 在编译时间确实有提升
如何集成?
直接使用 esbuild-loader 代替目前的 babel-loader 即可。
从 ola-cli@3.7.x 开始同时支持 babel 和 esbuild,通过 .olarc.js 配置 esbuild: true 开启 esbuild 编译
需要注意的是:esbuild 目前只能产出 es2015 代码,所以不兼容 IE 浏览器,若有兼容需求请慎用
遇到的问题
1. 原有的 autoCssModule 功能会失效
失效原因
autoCSSModules
功能主要是通过 js 代码中引用 css 文件的方式来自动判断是否启用 cssModule 功能,比如 import './index.css'
这种写法就是普通 css 引用,import styles from './index.css'
就是以 cssModule 的方式引用。
当编译工具发现以 cssModule 方式引用时,会自动将代码改写成 import styles from './index.css?modules'
,这样在 webpack 的 css-loader 配置中可以匹配到 ?modules
参数并开启 cssModule 功能。
自动改写代码原来是基于 babel 的插件实现,esbuild-loader 不支持自定义插件,于是只能在 esbuild-loader 编译完成后来处理这部分改动。
如何解决从
webpack 的 loader 入手,在 esbuild-loader 后增加一个 loader 来处理 esbuild 编译完成后的代码。
使用 es-module-lexer
对代码进行分析,提取出需要开启 cssModule 的 css 引用方法。es-module-lexer
会分析出代码具体在文件中的位置。
使用 magic-string
将对应位置引用的 css 文件加上 ?modules
后缀。magic-string
是一个文本内容维护工具,支持对文本内容进行各种修改,最终生成修改后的结果并支持输出 source-map
的一个工具。
2. 原有的 transformImports 功能会失效
失效原因
原有功能是使用了 babel 的一个插件 babel-plugin-transform-imports
。这个插件的主要作用是将 es6 模块的整体引入改写为部分引入,减少了打包后的代码依赖项。例如通过如下配置:
1 |
|
可以将代码里 import { Button } from '@jd/jmtd'
改写成 import Button from '@jd/jmtd/es/Button'
。两者的区别就是,前者会引入 '@jd/jmtd/index.js'
,导致整个组件库的代码都会被引入进来,而后者只会去引用 Button 组件。
同 csModule 一样,由于 esbuild-loader 不支持自定义插件,无法在 esbuild 编译对代码进行改写,所以 transformImports 功能会失效。
如何解决
和 cssModule 的处理方法类似,通过 webpack 的 loader 来处理 esbuild 编译过后的代码。同样使用 es-module-lexer
和 magic-string
,根据 .olarc.js 配置文件中的 transformImports 配置内容,对代码文件内引用的模块进行匹配,符合条件的模块引用代码会被重写为逐条引入的写法。
3. sourceMap 定位飘移
当使用 webpack loader 对 esbuild 编译后内容进行修改过后,会导致 esbuild 产生的 sourceMap 和源码内容定位不准确的问题。原因就是在进行 transfromImports 修改过后,文件内容的行数可能会发生变化。
要解决这个问题,主要思路就是读取 esbuild 产生的 sourceMap 内容,并且将要重写的那部分代码的映射关系删除掉,重新添加新的映射关系。
这里需要用到一个工具叫 source-map
。它可以读取已有的 sourceMap 内容并且支持对它进行再次修改,最后再生成一个最新的 sourceMap 内容。
最后
对 transform-imports 支持已经抽离成了一个 npm 包,源码可以查看 transform-imports-loader