使用 ts-node 运行 ts文件,启动 nodejs项目
最近在写一个nodejs项目,使用 ts-node 启动项目。遇到了一些问题,在此记录一下。
ts-node 是 TypeScript 执行引擎和 Node.js 的 REPL(一个简单的交互式的编程环境)。
它能够直接在 Node.js 上执行 TypeScript,而无需预编译。 这是通过挂接 node 的模块加载 API 来实现的,使其能够与其他 Node.js 工具和库无缝衔接。
1. 安装:
npm i ts-node
npm i ts-node -g // 也可以全局安装
检查是否安装成功
ts-node -v
如果不识别该命令,以管理员身份运行 IDE 或 powershell。
2. 目录结构
|-- server_node
| |-- src
| |-- login
| | |-- index.ts
| |-- test
| |-- index.ts
| |-- index.ts
| |-- package-lock.json
| |-- package.json
index.ts
import express from "express";
import Login from "./src/login";
import Test from "./src/test";
const app = express();
app.use("/api", Login);
app.use("/api", Test);
app.listen(9090, () => {
console.log("success server http://localhost:9090");
});
3. 启动 + 排错
添加启动命令:“dev”: “ts-node index.ts”
package.json
{
"name": "server_node",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "ts-node index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
...
}
啪的一下子,就报错了,很干脆啊!
这是因为 nodejs 默认支持 CommonJS语法,不识别 import 导入。有两个解决方案:
- package.json 中添加
"type": "module"
ts-node index.ts
改为ts-node-esm index.ts
,-esm是让 ts-node 以 ESModule语法执行。
但是!!!它又不识别 ts 后缀文件了。。。
然后排错了好久,查了好多解决方案:
- package.json 和 tsconfig.json 配置冲突的
- 安装 typescript
和我遇到的情形不一样,没什么卵用。。
4. 解决方案
然后还是去翻文档,找到这个:
意思就是,如果想要支持 ESMoudle,必须在 package.json 和 tsconfig.json 中如此配置。
我们执行 tsc -init
, 生成 tsconfig.ts 文件。(tsc 命令文末有补充)
设置 "moduleResolution": "node",
,指定 TypeScript 如何从给定的模块指定符中查找文件。
运行报错 npm run dev,报错:
ERR_UNSUPPORTED_DIR_IMPORT:这个错误表明你尝试导入的目录不是一个合法的、可导入的模块结构。
这需要我们把导入路径补全:
import Login from "./src/login/index.ts";
设置 "allowImportingTsExtensions": true
和 "noEmit": true
支持 ts扩展名,解决报错。
最终 tsconfig.ts 配置如下:
tsconfig.ts
{
"compilerOptions": {
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
/* Modules */
"module": "ESNext", /* Specify what module code is generated. */
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
"allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
"noEmit": true, /* Disable emitting files from a compilation. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"ts-node": { "esm": true }
}
修改对应配置后,发现运行还是不行,又回到最初的报错了。。。
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts"
WTM,这是逼我搞玄学呀!
我们看第一段话,意思大概是,(node 的底层都是 CommonJS,)node 的 ESMoudle 功能支持目前是试验阶段,随时可能会变化。我们会尽量稳定对 ESMoudle 的支持,但是它依赖某些API,并且这些API可能会在新版本的 node 中中断,所以不建议生产中使用。
OK,那就很明了了,肯定是 node版本问题,新版本的 node 可能还没有适配。
经过我的测试,结果如下:
- 在没有 tsconfig.json 的情况下,16版本及以上都会出现问题,14,15版本都是OK的,再低的版本我就没测了。
- 而在有 tsconfig.json 的情况下,最高可以支持到
18.18.0
版本。
于是,我把我的 node 版本从 20 降到 18,就能成功运行了。
5. 补充
这是一个常规的 ts文件运行方法,先编译后运行。
npm i typescript // tsc
// 编译 ts 为 js
tsc index.ts
npm i nodemon // nodemon
// 热加载 index.js
nodemon index.js