【问题标题】:Avoiding relative paths in Angular CLI避免 Angular CLI 中的相对路径
【发布时间】:2017-05-18 13:35:39
【问题描述】:

我正在使用最新的 Angular CLI,并且我创建了一个自定义组件文件夹,它是所有组件的集合。

例如,TextInputComponent 有一个 TextInputConfiguration 类,该类位于 src/components/configurations.ts 内部,而在我使用它的 src/app/home/addnewuser/add.user.component.ts 中有:

import {TextInputConfiguration} from "../../../components/configurations";

这很好,但是随着我的应用越来越大,../ 越来越深,我该如何处理?

以前,对于 SystemJS,我将通过system.config.js 配置路径如下:

System.config({
..
 map : {'ng_custom_widgets':'components' },
 packages : {'ng_custom_widgets':{main:'configurations.ts', defaultExtension: 'ts'},
)};

如何使用 Angular CLI 为 webpack 生成相同的内容?

【问题讨论】:

  • 仅供参考,我尝试将路径添加到 tsconfig.json 不起作用` "paths": { "@components/*": ["src/components/*"] }, ` 和 app.component ` 从“@components/configurations”导入 {TextInputConfiguration};`
  • 我认为这是因为您的@components 路径错误。看我的回答;我们在类似的地方有一个lib/ 目录,它工作正常。

标签: angular typescript webpack angular-cli


【解决方案1】:

保持简单

让我们保持简单,只需了解一些您需要了解的信息,以便能够将此解决方案应用于任何未来的项目。

前言:Angular 没有设置“常规”@/~/ path mappings,可能是因为它选择在这件事上不那么固执己见。

但它确实为所有导入设置了 baseUrl./(这意味着 tsconfig.json 所在的文件夹)。

这意味着任何非相对导入(不以./../ 开头的导入)都会自动以baseUrl 为前缀。

因此,只要您使用以该基本 URL 开头的路径进行导入,您就应该已经有了解决方案!只要您的重构工具能够识别基本 URL 并且能够正确应用导入路径重构,您就不应该遇到重构问题。

因此,默认情况下,使用未修改的 TS 配置,您可以使用这种导入,而不必担心相对路径变得难以管理:

// sample import taking into consideration that there is
// a baseUrl set up for all imports which get prefixed to
// all imports automatically:

import { ComingSoonComponentModule } from 'src/app/components/coming-soon/coming-soon.module';

另一种解决方案

但是,如果您真的想使用 @/ 之类的前缀,您可以使用简单的 path mapping 轻松做到这一点,如下所示:

// tsconfig.json

{
  // ...
  "compilerOptions": {
    "baseUrl": "./",
    // notice that the mapping below is relative to the baseUrl: `src/app/*` is in fact `{baseUrl}src/app/*`, ie. `./src/app/*`.
    "paths": { "@/*": ["src/app/*"] },
    // ...
  },
  // ...
}

然后您可以作为其中之一导入:

import { ComingSoonComponentModule } from 'src/app/components/coming-soon/coming-soon.module';
import { ComingSoonComponentModule } from '@/components/coming-soon/coming-soon.module';

要记住的事情:

  1. paths tsconfig 选项相对于 baseUrl 选项(因此请记住并为 paths 键使用相对路径)。
  2. * - 星号是指定的模块路径(根据您在代码中的规范,您导入的位置),其他所有内容都是根据您在 tsconfig 中的规范添加到最终路径的前缀或后缀。

【讨论】:

    【解决方案2】:

    我有一个更简单的解决方案来解决这个问题。在您的“tsconfig.json”中,只需将 baseURL 设置为空字符串:

    "baseUrl": ""
    

    现在您可以从根目录引用从一个文件到另一个文件的路径,如下所示:

    import { ProductService } from 'src/app/services/product.service'; 
    

    这些是绝对路径,但 Angular 使用它们的方式似乎是相对的。但他们工作!我不喜欢上面提到的“路径”快捷方式,因为我想知道所有东西的物理位置,这就是发明绝对路径的方式和原因。

    请记住,这可以解决在导入时引用模块和组件或构建 Angular 项目时的路径问题,但这并不能解决与模板、样式路径或使用完全不同的图像等资产相关的路径问题构建和编译项目时 Angular 中的路径系统。

    如果这有助于解释这个愚蠢的路径系统,项目根目录中的“angular.json”工作区文件控制着“sourceRoot”文件夹是什么,默认设置为“src”。这就是 Angular 构建块使用的“源根”文件夹的开始。请记住,Angular“工作区根”是“src”上方的项目文件夹,是项目和编译器的真正根。因此,当您编写“src/app/...”时,根实际上位于“src”之上。 angular.json 显然是从其当前位置派生其起始文件夹,因此“src/app/”实际上是基于 angular.json 位置的相对本地文件夹。这就是为什么“/src/app”对于 baseURL 不起作用的原因,因为它相对于 angular.json,我相信。

    默认情况下,Angular 的“src”文件夹是构建/编译项目时所有构建路径解析的文件夹。我怀疑 webpack 在解析时也会在 angular.json 中查看相同的“sourceRoot”“src”值。

    经过一番努力,我发现将 tsconfig 中的 baseURL 设置为“”而不是“。”或“./”,只要从“src”文件夹开始,您现在就可以使用这些完整路径。这些类型的绝对路径对我来说更有意义,因为现在您可以直观地知道所有内容从顶部根向下的位置,而不是在文件树上上下移动。这简直是​​疯了!

    我不知道为什么 Angular 的孩子们使用那些愚蠢的相对路径系统。这些“./”路径完全没用,并且在编译器路径解析系统和它们使用的 HTML/URL 路径解析系统中都使导航变得更加困难。我认为,如果他们花时间了解开发人员使用相对路径的原因和时间,他们可能会意识到在广泛的环境中假设每个文件都引用其本地文件夹中的所有其他文件并不是很有用。

    【讨论】:

      【解决方案3】:

      在 Angular 8 中,不需要 *. * 将导致Cannot find module 的错误 将此添加到您的 tsconfig.json 文件中

      "baseUrl": "./",
      "paths": {
            "@test": [ "src/app/test/" ],
            "@somthing": [ "src/app/something/" ],
            "@name": [ "src/app/name/" ]
          },
      
      

      【讨论】:

        【解决方案4】:

        不知道为什么,但是当我在 VS2017 中尝试其他答案时,我能够编译 Angular 而没有错误,但我仍然在 VS“找不到模块...”中看到错误。当我将 baseUrl 从 "." 设置为 "src" 时,每个人都很高兴。

        tsconfig.json

        {
          "compileOnSave": false,
          "compilerOptions": {
            "outDir": "./dist/out-tsc",
            "sourceMap": true,
            "declaration": false,
            "moduleResolution": "node",
            "emitDecoratorMetadata": true,
            "experimentalDecorators": true,
            "target": "es5",
            "typeRoots": [
              "node_modules/@types"
            ],
            "baseUrl": "src",                 // Main source directory same level as tsconfig
            "paths": {
              "app/*": [ "app/*" ],           // src/app
              "ui/*": [ "ui/*" ],             // src/ui       
              "services/*": [ "services/*" ], // src/services
              "assests/*": [ "assests/*" ],     // src/assests
              "models/*": [ "models/*" ]      // src/models
            },
            "lib": [
              "es2017",
              "dom"
            ]
          }
        }
        

        然后导入:

        import { AppMenuComponent } from 'ui/app-menu/app-menu.component';
        

        注意:如果 Visual Studio 仍然抛出错误,请尝试关闭并重新打开文件或重新启动 Visual Studio 以使其识别新路径。

        【讨论】:

          【解决方案5】:

          首先答案是正确的,但是在通过互联网搜索试图了解究竟是什么问题并尝试不同的故障排除选项后,我开始了解 baseUrlPath 如何一起工作

          如果你像下面这样使用 baseUrl:"." 它可以在 VScode 中工作,但不能在编译时

          {
            "compileOnSave": false,
            "compilerOptions": {
              "outDir": "./dist/out-tsc",
              "baseUrl": ".",
              "paths": {
                "@myproject/*": ["src/app/*"]
              }    
          }
          

          根据我的理解和我的工作应用程序并签入 angular aio 代码,我建议使用 baseUrl:"src" 如下所示

          {
            "compileOnSave": false,
            "compilerOptions": {
              "outDir": "./dist/out-tsc",
              "baseUrl": "src",
              "paths": {
                "@myproject/*": ["app/*"],
                "testing/*": ["testing/*"]
              }    
          }
          

          通过将基本 url 作为源(src 目录),编译器可以正确解析模块。

          我希望这有助于人们解决此类问题。

          【讨论】:

          • 感谢您解决了这个问题。没有 baseUrl 作为“src”编译器试图解析根目录。
          • 我正在使用 Angular CLI - 所以我不想编辑 webpack 文件...这对我帮助很大。
          • baseUrl 设置为 src 对我有用 :) 否则其他答案都很好。
          • 你试过用./代替.吗?
          【解决方案6】:

          根据this comment,您可以通过pathstsconfig.json 中添加您的应用程序源:

          {
            "compilerOptions": {
              ...,  
              "baseUrl": ".",
              "paths": {
                ...,
                "@app/*": ["app/*"],
                "@components/*": ["components/*"]
              }
            }
          }
          

          然后您可以从app/components/ 绝对导入,而不是相对于当前文件:

          import {TextInputConfiguration} from "@components/configurations";
          

          注意:如果paths 是,则必须指定baseUrl

          另见

          【讨论】:

          • 太棒了! ,根据您的新答案进行配置,顺利通过!
          • 对于未来的其他人,我必须设置baseUrl 的选项以及答案才能使其正常工作。
          • @SyedAliTaqi 将其设置为什么?
          • @jonrsharpe:到我的应用程序的根目录。即使在那之后,VS Code 也能够解决依赖关系,但Webpack's ts loader 仍然给出unable to resolve module 的错误。为了解决这个问题,我必须在我的 webpack.config 中添加 aliasmodules 属性。
          • 是的,我尝试使用 ".",但我必须在 webpack 配置中明确添加 baseUrlpaths 才能使其工作。
          【解决方案7】:

          感谢 jonrsharpe's answer 为我指明了正确的方向。尽管按照答案中的定义添加paths 后,我仍然无法使其工作。对于将来遇到与我相同问题的其他人,这是我为解决问题所做的工作。

          我有一个共享模块,它的服务被多个组件使用,所以...

          tsconfig.json:

          {
              "compilerOptions": {
                  ...
                  "baseUrl": ".", //had to add this too
                  "paths": {
                      "@shared/*": ["src/app/modules/shared/*"]
                  }
              }
          }
          

          在此之后,VS Code 能够解析 import,但在编译时我仍然收到来自 webpack 的以下错误。

          找不到模块:错误:无法解决

          为了解决这个问题,我必须添加

          1. baseUrl of tsconfigwebpack's resolve.modules
          2. paths of tsconfigwebpack's resolve.alias

          webpack.config.js:

          resolve: {
            extensions: ['*', '.js', '.ts'],
            modules: [
              rootDir,
              path.join(rootDir, 'node_modules')
            ],
            alias: {
              '@shared': 'src/app/modules/shared'
            }
          },
          

          component.ts:

          import { FooService } from '@shared/services/foo.service'
          import { BarService } from '@shared/services/bar.service'
          import { BazService } from '@shared/services/baz.service'
          

          为了更简洁,我在 services 文件夹中添加了一个index.d.ts,并从那里导出了我的所有服务,如下所示:

          index.d.ts:

          export * from './foo.service';
          export * from './bar.service';
          export * from './baz.service';
          

          现在在任何组件中:

          import { FooService, BarService, BazService } from '@shared/services';
          

          【讨论】:

          • 如果你的项目是一个库怎么办?您如何将这些映射公开给客户端应用程序?
          • @Stephane 看看this 问题。
          猜你喜欢
          • 1970-01-01
          • 2020-01-18
          • 1970-01-01
          • 1970-01-01
          • 2018-08-26
          • 2020-11-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多