19

esbuild 上生产

 3 years ago
source link: https://zhuanlan.zhihu.com/p/408379997
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

esbuild 上生产

halo 大家好,我是 132,我在公司中负责小程序的工具链,使用 esbuild 的部分主要是编译器,容我一一道来

旧架构

小程序编译器的旧架构中,是使用 babel 先对小程序文件进行 AST 转换,转换为 react 项目,然后使用 webpack 对 react 项目进行打包,最终生成 js 文件,交给容器

babel => AST => React => webpack => js

在这个架构中,每个环节都很慢,除了 webpack 打包慢,babel 也慢,递归进行文件 IO 操作,也很慢……

所以最初尝试 esbuild 是因为它快

新架构

在新架构中,使用 esbuild 做控制流,所有的文件 IO 操作交给 esbuild,而 AST 转换的部分则做成 esbuild 的 plugin

这样一来,不仅解决了 webpack 慢,还解决了 IO 操作慢的问题

当然,babel 操作 AST 也是很慢的,这部分我们待会再说

经过这一波重构,构建速度从 50s 降到了 10s,大约提升了 5 倍性能

更重要的是,新架构的控制流更清晰了,以后有什么问题就找 esbuild 的 plugin 就好了

esbuild => plugin(swc) => js

为了节省 IO 的性能,我还是维护了一个图结构,它的作用主要是用来记录信息做缓存

esbuild 天坑

不支持 split common chunk

简直是天坑了……甚至我老板说只要 esbuild 解决不了这个问题,就无法上生产

https://github.com/evanw/esbuild/issues/1581

这是我提的 issue,esbuild 做过一个鸡肋版本的 split chunk,只支持 esm,也就是必须得是 支持 native module 的浏览器才可以

小程序当然不可以,所以不得已,临时解决方案

export const splitChuckCjs = {
  name: 'split-chunk-cjs',
  setup(build) {
    build.onEnd(result => {
      return Promise.all(result.metafile.outputs.mao(async path =>{
        const source = await fs.promises.readFile(path)
        await swc.transform(source, {
          jsc:{
            syntax: 'ecmascript',
            jsx: false,
            target: 'es5',
          },
          module: {
            type: 'commonjs'
          }
        })
      }))
    })
  },
}

就是先使用 esbuild build 出来 esm 的 chunks,然后再将产物使用 swc 转换为 cjs

在这里我顺便做了一层 es5 的兼容处理,因为上生成,还是有很多安卓 7- 的

至此,通过使用 esbuild + swc 配合的方式,可以说为生产做足了准备

使用 swc 做 AST 转换

小程序编译器最重要的一点就是将 wxml 转换为 jsx,这一步在旧架构中是使用 babel 做的,新架构中我使用 swc 做

swc 是 rust 写的,它的限制非常多,遍历起来很憋屈,为此我想了很多办法,具体可以看我之前写的一篇

最终它的完成度还是不够好,虽然我做了很多编译时检查,一些不支持的 case 可以在编译阶段友好地进行提示,但我感觉还是得继续写一段时间才行

这次我们上生产没有涉及这部分,先上 esbuild 再说,swc 下一波再升级

生产准备

携程小程序线上大约有 30+ 项目,在大公司,新技术想要上生产,只有两条路:

1. 领导帮忙推
2. 走群众路线

很明显,我走的是群众路线……

我会把线上每一个小程序,都拉到本地,一个一个地跑,有问题就修改,然后给负责人提 pr

业务童鞋不需要排期,只需要审查一下我的 pr,然后测试发布即可

就这样,一个个来,终于苍天呐,不仅跑通了小程序,我还和业务童鞋们打成一片

但还不行……

我们上生产,指的是上 CICD,携程小程序有一套流畅地自动发布的链路,为了生产不出问题,我必须做好随时回退到旧版本的准备

具体是使用 npm alias 做到的,也就是同一个编译器,装俩版本

npm i miniapp-cli1@npm:miniapp-cli
npm i miniapp-cli2@npm:miniapp-cli@next

然后只需要在 app.json 中配置一下版本,就可以走不同版本啦

总结

任重而道远,现在只是生产准备,可想而知年底不得消停

但我觉得一切值得……

另外今天得知一个好消息,有 native 小哥哥准备接坑小程序的 IOS 容器,我还是很开心的,很快就可以做 IOS 端的调试器了

一切都在慢慢变好……

希望今年能够将小程序彻底升级完,明年开始接新的容器,接更多小程序


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK