在tsconfig的`paths`中定义了一个模块,但找不到该模块。

106

我正在尝试为我的模拟服务器设置别名。每当我尝试编译ts文件时,它返回错误,即找不到正确的模块,尽管这些模块在tsconfig.json->paths中定义了。

文件夹结构:

├── server
│   └── src
│       └──/json
├── src
│   └──/modules
├── tsconfig.json

这是我的tsconfig.json文件

{
    "compilerOptions": {
        "baseUrl": "./src",
        "experimentalDecorators": true,
        "jsx": "react",
        "lib": [
            "dom",
            "es2015",
            "es2015.promise"
        ],
        "module": "commonjs",
        "moduleResolution": "node",
        "noImplicitAny": true,
        "noUnusedLocals": true,
        "esModuleInterop": true,
        "paths": {
            "@project/app/modules/*": [
                "modules/*"
            ],
            "@project/server/data/*": [
                "../server/src/json/*"
            ]
        },
        "sourceMap": true,
        "target": "es5"
    },
    "exclude": [
        "node_modules",
        "tools"
    ]
}

错误: 错误:找不到模块“@project/server/data/accounts/accountsList”


它适用于@project/app/modules/*吗? - George.S
我的配置文件中,有一个包含标志指向 ['src']。试一下。 - George.S
我必须检查一下,因为如果你使用了webpack,你也需要在那里声明你的别名。 - George.S
5
谢谢!最终使用了tsconfig-paths包。 - Jamil Alisgenderov
@JamilAlisgenderov,你使用的cdk + tsconfig-paths的具体命令是什么? - 55 Cancri
显示剩余5条评论
17个回答

59

嗯,在经历了几个小时的折磨后,我找到了一个解决方案, 我正在使用ts-node包,并且遇到了相同的错误Error: Cannot find module '@modules/logger'

你需要在tsconfig.json文件中添加ts-node的配置。 你可以在ts-node上获取更多信息。

这是我的tsconfig.json文件的样子

{
    "ts-node": {
        // Do not forget to `npm i -D tsconfig-paths`
        "require": ["tsconfig-paths/register"]
    },
    "compilerOptions": {
        "lib": ["es5", "es6", "es7"],
        "target": "es2017",
        "module": "commonjs",
        "moduleResolution": "node",
        "rootDir": "src",
        "outDir": "build",
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "esModuleInterop": true,
        "noImplicitAny": true,
        "strict": true,
        "resolveJsonModule": true,
        "allowJs": true,
        "sourceMap": true,

        "baseUrl": ".",
        "paths": {
            "@modules/*": ["src/modules/*"],
            "*": ["node_modules/*"]
        },

    },
    "include": ["src/**/*"]
}


这是我的package.json文件。
"_moduleAliases": {
        "@modules": "build/modules",
        "@core": "build/core"
    }

你需要将这个包安装为模块别名的依赖项 npm i module-alias 并且不要忘记在应用程序的入口文件中添加 import 'module-alias/register'; 作为模块别名的依赖项。

1
这是最好的解决方案,tsconfig与node本身的分辨率不同,因此您需要一种方法来让node识别您闪亮的别名路径,正如在此答案中所分享的:https://dev59.com/5VMI5IYBdhLWcg3wPpK4#69514947 - Jesús Franco
1
添加 tsconfig-paths 开发依赖和 tsconfig-paths/register 允许在 ts_node 执行下工作路径“别名”。如果只需要这些,就不需要 module-alias - CortexCompiler
3
为了使其正常工作,您需要在入口文件中导入module-alias依赖项 import 'module-alias/register';,如本文所述 https://dev.to/larswaechter/path-aliases-with-typescript-in-nodejs-4353。 - Sarcadass
非常感谢这个解决方案,现在我可以安心睡觉了。 - callmenikk
我的朋友(抱歉假设您的性别),您的解决方案最好。祝福您。 - Shalom Effiom
显示剩余4条评论

20

经过一段时间的战斗,我想出了解决方法——你需要在主要的tsconfig.json文件中使用tsconfig-paths包含所有目录。你的tsconfig.json文件的工作版本可能是这样的:

{
    "compilerOptions": {
        "baseUrl": ".",
...
        "paths": {
            "@project/app/modules/*": [
                "src/modules/*"
            ],
            "@project/server/data/*": [
                "server/src/json/*"
            ]
        },
    },

    "include": [
        "./src",
        "./server"
    ],
}

2
但是这样会包括src中的所有文件夹,甚至没有路径。在我的项目中,src中有一个和我引用的库同名的文件夹。因为它尝试读取本地文件夹而不是包时,会出现问题。 - marcellsimon
1
它在开发模式下对我有效,但在使用tsc build并运行node dist/index.js时无效,所以我将"dist/"添加到路径中,同时加上"src/"和键为"@/*",现在它可以工作了。 - Oleg Abrazhaev
需要注意的一点是,@符号是一种约定,用于指示项目的根目录。 - Remi

19

我也遇到了同样的问题。尝试了很多方法后,我找到了一个适用于我的解决方案。在我的 Angular 项目中,我有一个应用程序和一个库。我想在应用程序中使用库的别名。

以下是我的项目结构:

├── projects
│   └── lib
│       └── src
│           └── lib
│               └── lib-service.ts
│           └── index.ts
│   └── app
│       └──tsconfig.app.json
├── tsconfig.json

在根目录下的tsconfig.json文件中,我定义了以下路径:

"paths": {
  "my-lib": [
    "projects/lib/src/index.ts"
  ]
}

我在那里访问一个index.ts文件,在这个文件中定义我想要导出的内容。在我的情况下,index.ts文件具有以下条目:

export * from './lib/lib-service';

现在我可以通过别名在应用程序的组件中访问LibService

import {LibService} from 'my-lib';

需要强调的是,如果我将此条目添加到tsconfig.app.json文件中,该解决方案将不起作用。 我认为IDE(在我的情况下是WebStorm)会在靠近根文件夹的tsconfig.json文件中搜索别名。因此,我在tsconfig.app.json中扩展了tsconfig.json

"extends": "../../tsconfig",

也许您需要重新启动IDE以消除导入行的红色下划线。

我希望这个解决方案对您有用。您需要做更多的设置工作,因为您必须在index.ts文件中定义要导出的类。但在使用库的情况下,这是有意义的,因为您不希望将所有内容都暴露给其他应用程序。


应用程序运行得像个魔术一样!但是即使重新启动了IDE,TypeScript仍然抱怨,显示错误:找不到模块。 - Extreme
4
我必须重新启动VS Code才能消除红色下划线! - Taylor A. Leach
3
@TaylorA.Leach 有时候你可以通过在VS Code中重新启动TS服务器来消除红线。按下cmd+shift+p,输入Restart TS Server即可。 - Patrick
这应该是粗体字:也许你需要重新启动你的IDE来消除导入行的红色下划线。 - himanshupareek66

15

我的问题是我的tsconfig.app.json文件覆盖了tsconfig.json中的"baseUrl"选项。我从tsconfig.app.json中删除了它,因此它没有"baseUrl""paths"选项。最终,我的tsconfig.json文件具有以下编译器选项:

"baseUrl": "src/",
"paths": {
    "@shared/*": ["shared/*"],
    "@client/*": ["client/*"],
    "@server/*": ["server/*"]
}

9
下面的 tsconfig.json 对我有用,允许我使用 import { foo } from '@models' 等来导入与其关联的 index.ts 桶出口:
{
    "baseUrl": "./",
    "paths": {
      "@environment": ["./src/environments/environment.ts"],
      "@models": ["./src/app/shared/models/index.ts"],
      "@services": ["./src/app/shared/services/index.ts"]
    },
}

8

TypeScript的 path 属性可以可靠地解析基于类型的URL,比如一个接口。

预期的行为是允许TypeScript解析类型信息[1]

大多数人似乎会遇到指向实际依赖项的路径无法按我们的预期编译的情况。尽管文档中说了什么,但这显然是有意设计的。

{
  "compilerOptions": {
    "baseUrl": ".", // This must be specified if "paths" is.
    "paths": {
      "jquery": ["node_modules/jquery/dist/jquery"] // This mapping is relative to "baseUrl"
    }
  }
}

阅读 Mitchell Simoens 的这篇精彩分析:为什么 TypeScript 路径对我失灵了

在将@paths设置为应用程序中的共享文件夹后,我发现在编译时,TypeScript路径会出问题,实际构建中缺少各种模块。就个人而言,这是 TypeScript 无法可靠地解决依赖项的巨大失望。


6

简而言之:

运行命令npm i -D module-alias,并将你的tsconfig.json路径映射添加到package.json中的_moduleAliases

"_moduleAliases": {
  "foo": "dist"
}

关于这背后的原因,使用 "jsx": "react""module": "commonjs" 结合使用会阻止你使用绝对导入,即使 baseUrlpaths 已经正确配置。可以在这个问题中找到详细的讨论。


4

当你只使用带有 tsconfig.json ("typescript": "^4.4.4") 的最基础的版本,没有使用任何第三方库时:

  1. 添加 baseUrl
"baseUrl": ".",
  1. 添加paths
"paths": {
      "@app/assets/*": ["src/assets/*"],
      "@app/components/*": ["src/components/*"],
      "@app/features/*": ["src/features/*"],
      "@app/hooks/*": ["src/hooks/*"],
      "@app/navigation/*": ["src/navigation/*"],
      "@app/services/*": ["src/services/*"],
      "@app/utils/*": ["src/utils/*"]
}
  1. 在目标文件夹内的每个路径上添加一个别名,使用package.json文件,并为其设置name属性。
// src/assets/package.json
{
  "name": "@app/assets"
}

由于@字符,此名称在package.json中不允许使用。 - szymeo

3

如果您在使用Jest时遇到此问题,则可以编辑您的jest.config文件,包含一个类似于以下内容的moduleNameMapper

{

  "moduleNameMapper": {
    "^@project/server(|/.*)$": "<rootDir>/server/$1"
  }
}

因此,这个正则表达式将导入@project/server...映射到路径"<rootDir>/server/$1"

。它涉及到IT技术方面的内容。

2
你可以轻松地定义一个简单的路径解析器,如下所示:

loader.js

const Module = require("module");
const originalResolveFilename = Module._resolveFilename;
const tsConfig = require("./tsconfig.json");
const Path = require("path");
const fs = require('fs');
if (!tsConfig.compilerOptions || !tsConfig.compilerOptions.baseUrl)
    throw "Compiler options Base URL (compilerOptions.baseUrl) is required in tsconfig.json.";
const basePath = Path.resolve(tsConfig.compilerOptions.baseUrl, tsConfig.compilerOptions.outDir);

//Inspired by https://github.com/dividab/tsconfig-paths but that one does not work with VS Code
Module._resolveFilename = function (request) {
    if (tsConfig.compilerOptions && tsConfig.compilerOptions.paths[request] instanceof Array) { //Supports only without wildchars, but enough for our use
        const pathsTried = [];
        for (const reqPath of tsConfig.compilerOptions.paths[request]) {
            const modPath = Path.resolve(basePath, reqPath) + ".js";
            if (fs.existsSync(modPath)) return modPath;
            pathsTried.push(reqPath);
        }
        throw "Module " + request + " not found, paths tried: " + pathsTried.join(", ");
    }
    const ret = originalResolveFilename.apply(this, arguments);
    return ret;
};

然后在VS Code的launch.json文件中引用它,如下所示:

"configurations": [
{
  "type": "node",
  "request": "launch",
  "name": "Node.js",
  "runtimeArgs": ["-r", "./loader.js"],
  "program": "${workspaceFolder}/run.ts",
  "preLaunchTask": "tsc: build - tsconfig.json",
  "outFiles": [
    "${workspaceFolder}/out/**/*.js"
  ]
}]
    

它不支持在paths中使用模式,但是可以通过这个存根来添加。

tsconfig.json应该像这样:

"compilerOptions": {
    "outDir": "out", //required
    "moduleResolution": "node",
    "baseUrl": "./", //required
    "paths": {
        "InjectableStub": [ //requires 2
            "myapp/myfolder/mymodule", //used in runtime
            "./myfolder/mymodule //used in compile-time
        ]
    }
}

至少对于我来说,tsc会在out文件夹中创建以根文件夹名称命名的子文件夹,这就是为什么需要进行两次注册。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接