likes
comments
collection
share

ts-node/esno/tsx 运行 ES module TS 运行时差异

作者站长头像
站长
· 阅读数 191

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() 静态和动态导入
  • from
  • export
  • default

模块配合(路径相关的模块)

  • 浏览器: 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.js import.meta 保存文件协议
console.log(import.meta) // {url: 'file:///xxx/xx/x'} // nodejs 环境

ts-node/esno/tsx 运行 ES module TS 运行时差异

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

ts-node/esno/tsx 运行 ES module TS 运行时差异

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

ts-node/esno/tsx 运行 ES module TS 运行时差异

配合 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/esno/tsx 运行 ES module TS 运行时差异

  • ts-node 运行 ts 文件提示:

ts-node/esno/tsx 运行 ES module TS 运行时差异

ES Module

{
    "scripts": {
        "dev": "ts-node src/index.ts"
    },
}

错误如下:

ts-node/esno/tsx 运行 ES module TS 运行时差异

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

ts-node/esno/tsx 运行 ES module TS 运行时差异

使用 ts-node-esm 来运行 ts 文件

ts-node 以指定 --loader 等等参数的方式运行

{
    "scripts": {
        "dev": "node --loader ts-node/esm --inspect ./index.ts src/index.ts"
    },
}

ts-node 指定 NODE_OPTIONSloader 的方式运行

{
    "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/esno/tsx 运行 ES module TS 运行时差异

ts-node 使用 swc 形式运行

  • 依赖包
npm i -D @swc/core @swc/helpers regenerator-runtime
{
    "scripts": {
        "dev": "ts-node --swc src/index.ts"
     },
}

不挑剔的 esno/tsx

esnotsx 本质基于 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.jsontsconfig.json,路径必须完整,写后缀必须是 .jsts-node 支持使用功能 swc
  • tsx/esno 由于 esbuild 的加持,使得运行 ts/tsx 运行更加灵活快速,方便快捷。
  • 如果仅仅是运行时,并且对性能没有过高要求或者仅仅使用在开发环境下工作,使用 esno/tsx 是很好的选择。

推荐文章

参考

转载自:https://juejin.cn/post/7163685872750034981
评论
请登录