Tree-shaking TypeScript/JavaScript 在浏览器和 Node 之间共享

Tree-shaking TypeScript/JavaScript shared between browser and Node

我正在开发一个 TypeScript 项目,该项目包含在浏览器客户端和基于节点的服务器之间共享的各种模块。我们想用 webpack/rollup 为浏览器捆绑和摇树模块,这需要将 TypeScript 编译器配置为以 ES6 为目标以保留导入。然而,为了 运行 在 Node 上,我们需要以 ES5 为目标,它将 imports 转换为 require 从而防止 tree-shaking。

有没有一种优雅的方法可以解决这个问题而无需将所有内容都编译两次,一次编译为 ES5,一次编译为 ES6?

可能的解决方案是:

.1 在这两种情况下都以单个 ES6 为目标,但在 Node 的情况下使用额外的 Rollup 步骤并启用 external 选项并以 ES5 为目标。在那种情况下 tsc 保证删除所有类型注释和其他与类型相关的东西,然后 Rollup 通过转换 ES6 → ES5 和 tree-shaking 东西来做繁重的工作。你需要 Rollup 的 JavaScript API,因为 CLI API 只支持 external = string[] 与具体模块,但你需要 «external all»。在那种情况下 JavaScript API: external: (id) => id != main_file.

缺点

  • 在那种情况下你不能使用 Rollup CLI API,你需要编写脚本

.2 使用 Rollup 作为主力,rollup-plugin-typescript 用 Rollup 生成两个不同的目标:ES5 和 ES6。在 Rollup 中从一个包中生成多个目标非常简单。

缺点

  • rollup-plugin-typescript,即使正式在 Rollup 的组织翼下,开发也很慢。我不能将其描述为“稳定”。

.3 仅生成 ES6 并使用 ESM for Node target. You can learn more by link, but in fact this already works well and performance shall be OK.

缺点

  • 提供 ESM 需要修补程序到节点目标(简单)

.4 如果“将所有内容编译两次”的主要问题是速度,那么只在生产环境中进行完整构建(即使是两次构建)。您可以引入一些简单的脚本,仅在开发中执行所需的操作并利用 tsc(或 Rollup)的 --watch 能力。