这几天在写typescript,遇到个路径依赖问题,编写的.ts文件直接运行OK,但是编译成.js后,运行提示 Error: Cannot find module xxx,📝记录分析和解决过程 。
问题描述
原始文件,有index.ts 其会引用src/say.ts,如下所示,
// index.ts
import { sayHi } from "src/say";
console.log(sayHi());
// src/say.ts
export function sayHi() {
return "hi";
}
// tsconfig.json
{
"compilerOptions": {
"baseUrl": "./",
"outDir": "./build",
"experimentalDecorators": true,
"lib": ["es2015", "es2016", "es2017.object", "es2020.Promise", "esnext.asynciterable", "dom"],
"module": "commonjs",
"moduleResolution": "node",
"noImplicitAny": false,
"sourceMap": true,
"strict": true,
"strictPropertyInitialization": false,
"target": "es2017",
},
"compileOnSave": true,
"exclude": ["node_modules/**/*", "**/*.d.ts", "test"],
"include": ["src/**/*", "./index.ts"],
}
如果直接运行 npx tsx index.ts ,可以直接运行。
但是如果先编译npx tsc 得到build文件夹以及编译的js文件后,运行 node build/index.js,则会报错
node:internal/modules/cjs/loader:942
throw err;
^
Error: Cannot find module 'src/say'
Require stack:
原因分析
当使用npx tsx index.ts时,会参考tsconfig.json文件中baseUrl (或paths)参数,找到src路径。但是使用tsc编译后,这部分信息并不会体现在编译后的build文件里面,此时再执行node build/index.js 则会提示找不到模块。
进一步说,这个问题 本质是别名问题 ,tsc不会转换路径别名。也看到网上有这么评价tsc,
- tsc不会转换路径别名,其实也是因为tsc的定位就是在开发阶段中使用的一个工具。
下一步,我们需要找到一种方式,让编译后的文件路径是正常的。
解决方案
方式1 修改引用路径
这种比较简单直接,不改变编译工具,还用tsc,引用时把相对路径加上 ,则编译后的路径依赖是正常的。
// index.ts
// import { sayHi } from "src/say"; no
import { sayHi } from "./src/say"; // yes
console.log(sayHi());
方式2 打包
不动代码,把项目整体打包成一个文件。以webpack打包工具举例。
npm install --save-dev webpack webpack-cli
npm install --save ts-loader
webpack配置文件
// webpack.config.js
const path = require("path");
module.exports = {
entry: "./index.ts",
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
preferRelative: true,
},
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"),
},
};
执行打包
npx webpack
打包后得到node dist/bundle.js,运行也是正常的。也不会再报路径模块找不到的问题。