Node.js中.cts文件为何可使用ESM模块导入导出语法?
问题背景与复现步骤
- 创建Node.js 18.15.0版本新项目,在
package.json中添加"type": "module"字段:
{ "name": "ts-node-test", "version": "1.0.0", "description": "", "type": "module", "scripts": { "test": "cross-env NODE_OPTIONS=\"--loader ts-node/esm\" node index.cts" }, "author": "", "license": "ISC", "devDependencies": { "cross-env": "^7.0.3", "ts-node": "^10.9.2", "tslib": "^2.6.2", "typescript": "^5.4.5" }, "volta": { "node": "18.15.0" } }
tsconfig.json配置如下:
{ "$schema": "https://json.schemastore.org/tsconfig", "ts-node": { "transpileOnly": true, "files": true, "experimentalResolver":true, "esm": true, }, "compilerOptions": { "outDir": "./dist", "allowJs": true, "allowSyntheticDefaultImports": true, "baseUrl": "./", "esModuleInterop": true, "experimentalDecorators": true, "forceConsistentCasingInFileNames": true, "importHelpers": true, "lib": [ "DOM", "ESNext" ], "module": "ESNext", "moduleDetection": "force", "moduleResolution": "node", "noEmitOnError": true, "resolveJsonModule": true, "skipLibCheck": true, "sourceMap": true, "strict": true, "target": "esnext", "typeRoots": [ "./node_modules/@types", ] }, "include": [ "index.cts", "module.cts" ] }
- 创建
index.cts文件:
import test from './module.cjs' console.log(test(1, 2))
- 同目录下的
module.cts文件:
export default (a: number, b: number) => a + b
- 执行
test脚本后无报错,输出结果:
3
核心问题:为什么Node.js中的.cts文件可以使用ESM模块的导入导出语法?
- 完整项目已上传至GitHub仓库。
原因解析
.cts后缀的本质与ts-node加载器的干预.cts是TypeScript为CommonJS模块设计的后缀,本意是让TypeScript将其编译为.cjs格式文件,但这里你使用了ts-node/esm加载器,它会直接接管TypeScript文件的转译逻辑,忽略.cts原本的CommonJS编译目标,转而按照ESM规则处理代码,包括解析import/export语法。tsconfig与环境配置的协同作用tsconfig.json中"ts-node": { "esm": true }的配置,明确告诉ts-node以ESM模式处理所有指定的TypeScript文件;再加上package.json中"type": "module"将项目整体设为ESM环境,Node.js会优先以ESM规则处理模块,两者结合让.cts文件的ESM语法被正确识别。模块解析的兼容性处理
你在index.cts中导入./module.cjs,是因为ts-node/esm转译.cts后会输出.cjs文件,而Node.js在ESM环境中允许直接导入CommonJS模块,这也是代码能正常运行的关键环节。
内容的提问来源于stack exchange,提问作者Yao Tao
相关产品推荐
相关产品推荐

