在tsconfig中包含Server目录时出现.ts文件扩展名未知错误
全TS项目中Vite导入server目录TS文件出现ERR_UNKNOWN_FILE_EXTENSION错误
我用Vite搭建了React前端+Node.js+Express后端的全TypeScript项目,当在tsconfig.json中包含server目录并导入该目录下的文件时,出现以下错误:
node:internal/errors:490 ErrorCaptureStackTrace(err); ^ TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/**name**/projects/**project-name**/server/database/models/problem.ts at new NodeError (node:internal/errors:399:5) at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:79:11) at defaultGetFormat (node:internal/modules/esm/get_format:121:38) at defaultLoad (node:internal/modules/esm/load:81:20) at nextLoad (node:internal/modules/esm/loader:163:28) at ESMLoader.load (node:internal/modules/esm/loader:605:26) at ESMLoader.moduleProvider (node:internal/modules/esm/loader:457:22) at new ModuleJob (node:internal/modules/esm/module_job:64:26) at #createModuleJob (node:internal/modules/esm/loader:480:17) at ESMLoader.getModuleJob (node:internal/modules/esm/loader:434:34) { code: 'ERR_UNKNOWN_FILE_EXTENSION' }
不包含server目录时项目可正常运行,不确定该问题是否与TypeScript或Vite的底层机制有关。
我的tsconfig.json配置:
{ "compilerOptions": { "target": "ESNext", "lib": ["DOM", "DOM.Iterable", "ESNext"], "module": "ESNext", "skipLibCheck": true, "allowSyntheticDefaultImports": true, "allowJs": true, "outDir": "./build", "esModuleInterop": true, /* Bundler mode */ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, "include": ["src", "server"], "exclude": ["node_modules"] }
package.json配置:
{ "name": "**project-name**", "private": true, "version": "0.0.0", "type": "module", "scripts": { "start": "PORT=$PORT npm run dev:seed", "dev": "vite", "dev:seed": "SEED=true npm run dev", "build": "tsc && vite build", "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", "test": "vitest", "test-ui": "vitest --ui" }, "dependencies": { "@emotion/react": "^11.11.0", "@emotion/styled": "^11.11.0", "@mui/icons-material": "^5.11.16", "@mui/material": "^5.13.0", "@reduxjs/toolkit": "^1.9.5", "axios": "^1.4.0", "cookie-parser": "^1.4.6", "dotenv": "^16.0.3", "express": "^4.18.2", "googleapis": "^118.0.0", "konva": "^9.2.0", "nodemon": "^3.0.1", "pg": "^8.11.0", "pg-hstore": "^2.3.4", "react": "^18.2.0", "react-color": "^2.19.3", "react-dom": "^18.2.0", "react-icons": "^4.10.1", "react-konva": "^18.2.10", "react-redux": "^8.0.5", "react-router-dom": "^6.11.2", "sequelize": "^6.31.1", "socket.io": "^4.7.2", "socket.io-client": "^4.7.2", "uuid": "^9.0.0" }, "devDependencies": { "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", "@types/cookie-parser": "^1.4.3", "@types/express": "^4.17.17", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", "@types/testing-library__jest-dom": "^5.14.5", "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "^5.57.1", "@typescript-eslint/parser": "^5.57.1", "@vitejs/plugin-react-swc": "^3.0.0", "@vitest/ui": "^0.31.1", "eslint": "^8.38.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.3.4", "jsdom": "^22.0.0", "msw": "^1.2.1", "sequelize-cli": "^6.6.0", "ts-node": "^10.9.1", "ts-node-dev": "^2.0.0", "typescript": "^5.0.2", "vite": "^4.3.2", "vitest": "^0.31.0" } }
问题原因与解决办法
核心原因
项目package.json中设置了"type": "module"启用ES模块,但Node本身不支持直接导入.ts文件;同时Vite作为前端构建工具,仅默认处理src目录下的前端代码,不会编译server目录的后端TS文件。当前端代码导入server目录的TS文件时,Vite会将路径直接交给Node处理,导致Node无法识别.ts扩展名报错。
解决办法
1. 拆分前后端TS配置(推荐)
- 根目录
tsconfig.json仅用于前端,修改include为["src"] - 在
server目录下新建tsconfig.server.json,配置后端TS编译:{ "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "node", "outDir": "../build/server", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "resolveJsonModule": true }, "include": ["."], "exclude": ["node_modules"] } - 更新
package.json的scripts,添加后端启动命令(需先安装concurrently:npm i -D concurrently):"scripts": { "dev:server": "ts-node-dev --respawn --transpile-only server/index.ts", "dev": "concurrently \"npm run dev:server\" \"vite\"", "build": "tsc && tsc -p server/tsconfig.server.json && vite build", // 其他命令保留 } - 前端不要直接导入后端代码,通过API请求与后端交互。
2. 单独管理共享类型(若需前后端共享类型)
- 新建
shared目录存放前后端共享的类型定义文件 - 根目录
tsconfig.json的include添加"shared",这样Vite能正确处理共享TS文件,同时避免引入后端业务代码
3. 临时修复(不推荐生产环境)
- 若临时需要在前端导入后端代码,可先用
ts-node或esbuild预编译server目录的TS文件,前端导入编译后的.js文件,但这种方式会混淆前后端边界,不建议长期使用
内容的提问来源于stack exchange,提问作者Jiayu Zhang
相关产品推荐
相关产品推荐

