355 - 《optimizePackageImports》

发布于 2023年10月19日

脑暴了下 Next.js 的 optimizePackageImports 在 Mako 下实现的 RFC,实现需要较多构建和 Mako 相关的背景知识,比较晦涩难懂。

背景

背景是看到 Next.js 的文章 https://vercel.com/blog/how-we-optimized-package-imports-in-next-js ,其中的 optimizePackageImports 看起来很心动。这个方法能大量减少模块总数,从构建工具的角度看,不仅减少了 build 的工作,也减少了 module graph 里的模块数,进而降低了 tree-shaking 和 code splitting 的压力。

我之前写过的 babel-plugin-import 也是这个目的,但不如 optimizePackageImports 通用和覆盖面广。覆盖面是决定最终效果的关键因素,之前做 mfsu 第一版的时候就深有体会。

问题

先看要达到的效果。

比如我们这么写。

import { Button } from 'antd';

然后 antd 的入口文件是 antd/es/index.js,其内容如下。

export { default as App } from './App';

那前面我们写代码如果被优化成这样,就可以大量减少模块数量了。

import Button from 'antd/es/App';

实现

怎么做到这一点呢?下面花 30 分钟脑暴下实现思路。

这个场景比较复杂,edge case 比较多,感觉测试驱动会比较好。所以先想下需要覆盖的用例。

基础用例如下。

  • import { x } from ‘foo’,如果 foo 是桶文件,期望会被替换
  • import { x } from ‘foo’,如果 foo 不是桶文件,期望不会被替换
  • 支持 import { x as y }
  • 支持 import x from ‘foo’ 的用 default specifier 的场景
  • 不支持 import * as x from ‘foo’,不管 foo 是不是桶文件,都期望不会被替换

进阶用例如下。

  • 支持递归桶文件,比如项目 > a,a 的入口文件依赖 a/button/index,而 a/button/index 也是个桶文件,期望拿到的是最终不是桶文件的路径
  • 支持 node_modules 下依赖的场景,项目 > a > b,a 里有 import { x } from ‘b’,如果 b 是桶文件,

内容预览已结束

此内容需要会员权限。请先登录以查看完整内容。