ts-node/esno/tsx 运行 ES module TS 运行时差异
Node.js + TypeScript 使用 ts-node/esno/tsx 对 ES Module 的支持使用时有何异同
- 直接运行
.ts文件 - 模块导入时,文件后缀的是否可以忽略
- ts-node 的多种运行方式以及限制
- 运行时中模块与ts/esm
ts 文件
传统方式:
- tsc 类型检查,编译 ts 文件
- 运行 js
- 程序运行,或者服务启动
开发一个库
一般开发库选用 TS,已经很常见了,选择 rollup 编译出 ES Module/Commonjs 等同类型的模块,提供给第三方使用。
但是,直接运行 ts/tsx 文件?
模块基础
ES Module 模块中的关键字
import/import() 静态和动态导入fromexportdefault
模块配合(路径相关的模块)
- 浏览器:
URL - 浏览器:
import.meta - nodejs:
url 模块 - nodejs:
path 模块
注意: import.meta 需要在支持了 ES Module 才能正常使用:
- 浏览器使用
<script type="module" src=""></script>支持 Node.js使用{ type: "module" }整个 Node 应用程序处在 ES Module 环境下支持- 其次
Node.js是.mjs文件表示 ES Module, 可以直接使用node ./xx.mjs运行
涉及文件类型
.js/.cjs/.mjs.ts/.cts/.mts
ES Module 完整的路径
所谓完整路径,就是支持网络下载(需要完整的路径才知道在哪里下),这一点与 Node.js 的包模块设计不同。
// commonjs
const foo = require('./foo')
// es module
import foo from './foo.js' // .js 需要完整的路径,并且补充完整,可以是相对路径
- 需要完整的路径(可以是相对路径)
ES Module import.meta 对象
暴露特定上下文的元数据属性的对象
完整的路径(注意文件协议)
Node.jsimport.meta保存文件协议
console.log(import.meta) // {url: 'file:///xxx/xx/x'} // nodejs 环境

- 浏览器环境
http协议(启动http服务)

- 浏览器中配合
URL使用
const url = new URL(import.meta.url)

配合 URL 构造器能直接解析为一个 URL 对象,方便直接使用 URL 对象属性方法
- 在
Node.js中配合url模块使用
在 Node.js 中,常用是实现 ES Module 下的 __dirname 和 __filename 两个变量
import { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
Node.js 环境带有 ES Module 运行 TS 文件
- ts-node
- tsx/esno
{
"scripts": {
"dev::tsnode": "ts-node src/index.ts",
"dev::tsnode::esm": "ts-node-esm src/index.ts",
"dev::tsx": "tsx src/index.ts",
"dev::esno": "esno src/index.ts"
},
}
ts-node 区分 ES Module 和 非 ES Module
非 ES Module
ts-node 默认是运行 commonjs 模块,如果在默认情况下使用 import.meta 等抛出错误要在 ES Module 条件下使用
ts-node运行js文件错误提示:

ts-node运行ts文件提示:

ES Module
{
"scripts": {
"dev": "ts-node src/index.ts"
},
}
错误如下:

解决:打开 node_modules 找到 package.json 文件,查看 bin 属性, 支持多种不同的环境的运行时:

使用 ts-node-esm 来运行 ts 文件
ts-node 以指定 --loader 等等参数的方式运行
{
"scripts": {
"dev": "node --loader ts-node/esm --inspect ./index.ts src/index.ts"
},
}
ts-node 指定 NODE_OPTIONS 和 loader 的方式运行
{
"scripts": {
"dev": "NODE_OPTIONS=\"--loader ts-node/esm\" node src/index.ts"
},
}
ts-node + ES Module 中导入模块需要 .js 后缀
在 ts-node + ES Module 的运行方式中, 从其他文件导入模块 .js 是不可忽略的,同时也不能改为 .ts
import aa from './abd.js'
否则会出现如下错误提示:

ts-node 使用 swc 形式运行
- 依赖包
npm i -D @swc/core @swc/helpers regenerator-runtime
{
"scripts": {
"dev": "ts-node --swc src/index.ts"
},
}
不挑剔的 esno/tsx
esno 和 tsx 本质基于 esbuild, 原生支持 ES Module, 所以无需指定环境, 甚至 package.json 中无需指定 type: "module":
{
"scripts": {
"dev::tsx": "tsx src/index.ts",
"dev::esno": "esno src/index.ts",
},
}
小结
得益于 go/rust 的发展,前端基础层面也搭上了顺风车,使得前端在运行时更加快速。
- 如果编写库类推荐使用
rollup+typescript编译出不同js版本, 提供给自己或第三方运行。 ts-node之处不同的环境,ES Module环境需要严格配置package.json和tsconfig.json,路径必须完整,写后缀必须是.js。ts-node支持使用功能swc。tsx/esno由于esbuild的加持,使得运行ts/tsx运行更加灵活快速,方便快捷。- 如果仅仅是运行时,并且对性能没有过高要求或者仅仅使用在开发环境下工作,使用
esno/tsx是很好的选择。
推荐文章
参考
- Node.js ES Module nodejs.org/api/esm.htm…
- ts-node npm www.npmjs.com/package/ts-…
- tsx www.npmjs.com/package/tsx
- esno www.npmjs.com/package/esn…
转载自:https://juejin.cn/post/7163685872750034981