2023 使用 TypeScript + Node.js ESM 的使用体验.
截至 2023.8
可选方案
- ts-node
- tsx / @swc-node/core
- tsc
- tsup
ts-node
支持 esm, 需要
package.json
中type=module
,tsconfig.json
中{ts-node: {"esm": true}
node v20 还有新问题
https://github.com/TypeStrong/ts-node/issues/1997
其他问题
- tsconfig-paths 只支持 cjs https://github.com/dividab/tsconfig-paths/issues/243
- ts-node 准备自己实现, https://github.com/TypeStrong/ts-node/pull/1585 但是 years passed
tsx
- 支持 tsconfig.paths without config
- 但是发布有问题, 同 tsc
tsx NOTE
- 之前叫 esbuild-kit, tsconfig 使用
env.ESBK_TSCONFIG_PATH
- 后改名叫 tsx, tsconfig 使用
env.TSX_TSCONFIG_PATH
update when Node.js v20 become Active LTS
ts-node 依旧没有资源投入适配 node v20 module.register
API.
对于直接执行 ts file, tsx 是更好的选择.
发布
使用 TypeScript 编写的 cli 工具, 可以(但没必要)直接发布 TypeScript 源码, 发布需带上 tsconfig, 可以使用类似下面的代码
1
2
3
4
5// <project-root>/entry.mjs
import path from 'path'
process.env.TSX_TSCONFIG_PATH = path.join(import.meta.dirname, 'tsconfig.json')
await import('tsx')
await import('./src/entry.ts')使用 dynamic import function 可以使
./src/entry.ts
使用上 esm loader 逻辑作为库, 不应发布 TypeScript. 因为使用库的项目不一定使用 TypeScript, 就算用很可能 tsconfig 不同, 而无法使用项目的 tsconfig 编译库包含的 TypeScript 代码
update 1 year later
- ts-node OUT (官网依旧是
--loader ts-node/esm
,--loader
是很久之前的 experiment API, 现在(node v20 v22)是module.register
+--import
API) - tsx 被广泛 adopt, (包括 nodejs/Microsoft 组织下的 repo)
- tsx 收到赞助, 好像是来自微软. (在 https://tsx.is 网站上出现过, 但几天后被移除, 我记忆中出现过…)
- tsx@4.16.2 安装大小 20MB+, @esbuild+darwin-arm64@0.21.5 大小 9.8MB. (功能正常的包大点怎么啦…)
工具链的更改
vscode code-runner 更改
1 | "code-runner.executorMap": { |
tsc
开发可以用
tsc --watch --incremental
速度还可以可以正常发布
不支持 tsconfig.paths 编译
typescript-transform-paths 只支持 cjs, esm on the way https://github.com/LeDDGroup/typescript-transform-paths/issues/134 但同样是 years passed. 同时依赖 ttypescript / ts-patch 等修改版的 TypeScript 编译器.
TypeScript 5.2 在考虑增加 custom transform
tsup
体验下来比较爽的方案
- 基于 esbuild, dev
tsup --watch
很快 - 支持 tsconfig.paths 解析
- 由于发布 bundle 代码, 不存在运行时解析 tsconfig.paths
目前我的几个 cli 都是基于这个方案改造成了 esm
- yun-playlist-downloader
- handy-img
- …more