发布于 2026-01-06 6 阅读
0

在 Nx 工作区中开发小型 Angular 应用程序项目

在 Nx 工作区中开发小型 Angular 应用程序项目

封面照片由John Moeses Bauan拍摄,来自 Unsplash。

原发布日期:2020年3月23日。

本文是 Angular 架构模式系列文章的一部分。

在 Nx 工作区中,我们可以采取一种策略,尽可能保持 Angular 应用项目的精简,从而减少修改应用项目的理由,并实现通用代码的重用。我们通过将业务逻辑和配置封装在工作区库中来实现这一点。

该策略的一个具体方法是使用shell 库模式来编排初始化、配置和路由。对于像这样只有一个应用程序的工作区来说,功能型 shell 库是一个不错的选择。

这种 shell 库变体也是应用程序中逻辑最少的,非常适合我们的需求。不过,本文不会详细介绍如何创建这种类型的库。

相反,让我们更进一步,提取静态资源、样式和环境的工作区库。

我们将逐步讲解如何设置完整的 Nx Angular 工作区并应用微型应用项目策略。之后,我们将讨论应用微型应用项目策略时所使用的不同策略和技巧的优势。

使用 Angular 应用程序创建 Nx 工作区

为了演示这一点,我们将创建一个包含单个 Angular 应用程序的 Nx 工作区。执行清单 1 中的命令。

npx create-nx-workspace workspace --cli=angular --preset=angular --appName=tiny-app --style=scss

nx update @angular/cli @angular/core
Enter fullscreen mode Exit fullscreen mode
清单 1. 使用单个 Angular 应用程序创建和更新 Nx 工作区。

我们将创建工作区库,应用程序可以通过作用域导入这些@workspace库。

提取资源工作区库

当我们生成一个 Angular 应用程序时,它会包含一个空assets目录,用于存放静态文件资源,例如图标、图像和 Web 字体。我们可以使用绝对路径从 DOM 元素属性和样式表中引用这些资源,例如 `<link>`<img src="/assets/images/logo.png" />和`<style> .twitter { background-image: url('/assets/icons/twitter.png'); }`。

生成的 Angular 应用程序还包含一个静态文件,favicon.ico该文件在 . 中被引用index.html。我们将生成一个 assets 工作区库,将我们的静态资源提取到其中,配置工作区并更新引用以使用该 assets 库。

生成一个干净的工作区库

第一步是生成一个工作区库并对其进行清理,因为它不包含 TypeScript 文件,只包含静态文件。

nx generate library assets --directory=shared --tags="scope:shared,type:assets" --style=scss

npx rimraf ./apps/tiny-app/src/assets ./libs/shared/assets/*.js ./libs/shared/assets/*.json ./libs/shared/assets/src/*.* ./libs/shared/assets/src/lib

"# shared-assets" > ./libs/shared/assets/README.md
Enter fullscreen mode Exit fullscreen mode
清单 2. 生成共享资源库并清除其中的 TypeScript 文件和配置。

执行清单 2 中的命令,然后编辑angular.json以从项目中删除所有架构目标,shared-assets以匹配清单 3 中的配置结构。

{
  "//": "angular.json",
  "projects": {
    "shared-assets": {
      "architect": {}
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
清单 3. 从资产库中移除架构师目标。

设置常用资源文件夹并移动网站图标

现在我们有了一个干净的工作区库文件夹结构,让我们创建常用资源文件夹,并通过执行清单 4 中的命令将 favicon 文件移动到我们的资源库中。

npx mkdirp ./libs/shared/assets/src/assets/fonts ./libs/shared/assets/src/assets/icons ./libs/shared/assets/src/assets/images

"" > ./libs/shared/assets/src/assets/fonts/.gitkeep

"" > ./libs/shared/assets/src/assets/icons/.gitkeep

"" > ./libs/shared/assets/src/assets/images/.gitkeep

mv ./apps/tiny-app/src/favicon.ico ./libs/shared/assets/src
Enter fullscreen mode Exit fullscreen mode
清单 4. 创建公共资源文件夹并移动网站图标。

要配置 Angular 应用程序项目以使用工作区库中的资源,我们导航到tiny-app:build架构目标angular.json,并将选项替换assets为清单 5 中的条目。

{
  "//": "angular.json",
  "projects": {
    "tiny-app": {
      "architect": {
        "build": {
          "options": {
            "assets": [
              {
                "glob": "favicon.ico",
                "input": "libs/shared/assets/src",
                "output": "./"
              },
              {
                "glob": "**/*",
                "input": "libs/shared/assets/src/assets",
                "output": "assets"
              }
            ]
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
清单 5. 配置应用程序资产。

我们指示 Angular CLIdist/apps/tiny-app在构建应用程序时将 favicon 文件复制到指定文件夹。此外,构建过程libs/shared/assets/src/assets还会将该文件夹中的所有文件和文件夹复制到dist/apps/tiny-app/assets指定位置。这样可以确保应用程序的资源链接在非本地环境(例如我们的测试和生产 Web 服务器)中都能正常工作。

不妨在本地试试。

请继续,在本地 Webpack 开发服务器上进行测试nx serve --open。执行清单 6 中的命令来构建生产环境的应用程序包,并使用本地静态 Web 服务器提供服务。确保网站图标(favicon)在两个地方都能正常显示。

nx build --prod

npx http-server dist/apps/tiny-app -o
Enter fullscreen mode Exit fullscreen mode
清单 6. 构建生产包并使用静态 Web 服务器在本地提供服务。

捆绑资产

Nx 生成的 Angular 应用程序会在其应用程序组件中显示 Nx 徽标,如图 1 顶部所示。

由 Nx 生成的 Angular 应用程序的部分首页。

图 1. Nx 生成的 Angular 应用程序中默认主页的顶部。

如果打开app.component.html,我们可以看到该徽标是从以下位置链接的https://nx.dev/assets/images/nx-logo-white.svg

让我们将徽标添加到应用程序包中,方法是将其包含在资源库中,并更新应用程序组件模板中的图像属性。

执行清单 7 中的命令,下载 Nx 徽标并将其存储在资源库中。

npx -p wget-improved nwget https://nx.dev/assets/images/nx-logo-white.svg -O ./libs/shared/assets/src/assets/images/nx-logo-white.svg
Enter fullscreen mode Exit fullscreen mode
清单 7. 下载 Nx 标志并将其存储在资源库中。

现在让我们更新图像元素,使其引用资源库中的徽标。app.component.html按照清单 8 所示进行编辑。

<!-- app.component.html -->
<img
  alt="Nx logo"
  width="75"
  src="/assets/images/nx-logo-white.svg"
/>
Enter fullscreen mode Exit fullscreen mode
列表 8. 图像元素引用了资源库中的徽标。

好了。我们已经提取了资源工作区库并打包了静态文件。请再试一次,确保一切设置正确。

提取样式工作区库

Angular 应用会生成一个名为 `<global_stylesheet>` 的全局样式表styles.css,或者在本例中styles.scss,由于我们使用 Sass,所以会生成一个全局样式表。全局样式表可以包含通用样式、元素类型样式、CSS 对象和实用样式。

随着应用程序的演进,全局样式表会变得越来越大、越来越复杂。在使用 Sass 时,我们可以将样式表拆分成 Sass partials,这些 partials 的名称通常以下划线 ( ) 为前缀_,例如_global.scss

Sass 局部文件通过 import 语句打包,例如:`import 's partials'` @import './lib/global';。请注意,Sass 使用约定来查找文件,无论文件名是否以下划线前缀。

与原生 CSS 不同,Sass 的导入语句并非逐个异步加载,至少在引用应用程序的静态资源时并非如此。相反,它们会被打包到一个单独的样式表中。这类似于我们使用 Webpack 和 Browserify 等工具打包 JavaScript 和 TypeScript 文件的方式。

我们将通过提取样式工作区库、将其转换styles.scss为 Sass partial、将其打包为工作区库样式表的一部分,并将我们的应用程序项目配置为链接到此样式表,来使我们的 Angular 应用程序项目更小。

生成一个干净的工作区库

就像我们在前一章中所做的那样,我们首先生成一个工作区库并对其进行清理,因为它只会包含样式表,而不会包含 TypeScript 文件。

nx generate library styles --directory=shared --tags="scope:shared,type:styles" --style=scss

npx rimraf ./libs/shared/styles/*.js ./libs/shared/styles/*.json ./libs/shared/styles/src/*.* ./libs/shared/styles/src/lib/*.*

"# shared-styles" > ./libs/shared/styles/README.md
Enter fullscreen mode Exit fullscreen mode
清单 9. 生成共享样式库并清除 TypeScript 文件和配置。

执行清单 9 中的命令,然后进行编辑angular.json,从项目中删除所有架构目标,shared-styles以匹配清单 10 中的配置结构。

{
  "//": "angular.json",
  "projects": {
    "shared-styles": {
      "architect": {}
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
清单 10. 从样式库中移除 architect 目标。

设置入口点样式表

有了清晰的工作区文件夹结构,我们就可以创建一个index.scss样式表,作为我们样式工作区库的入口点。

同时,我们将应用程序样式表(styles.scss)转换为 Sass partial,方法是重命名并将其移动到样式库中。这可以通过执行清单 11 中的命令来完成。

mv ./apps/tiny-app/src/styles.scss ./libs/shared/styles/src/lib/_global.scss

"@import './lib/global';" > ./libs/shared/styles/src/index.scss
Enter fullscreen mode Exit fullscreen mode
清单 11. 将应用程序样式表转换为 Sass partial 并创建入口点样式表。

只剩最后一件事要做。编辑以将建筑师目标选项angular.json替换为清单 12A 结构中所示的条目。stylestiny-app:build

{
  "//": "angular.json",
  "projects": {
    "tiny-app": {
      "architect": {
        "build": {
          "options": {
            "styles": [
              "libs/shared/styles/src/index.scss"
            ]
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
清单 12A. 配置应用程序以包含样式库的入口点样式表。

请注意,如果我们使用 Karma 并编写依赖于全局样式的组件测试,则必须向testUI 工作区库的 architect 目标添加类似的选项,如清单 12B 中的示例所示。

{
  "//": "angular.json",
  "projects": {
    "ui-buttons": {
      "architect": {
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "styles": [
              "libs/shared/styles/src/index.scss"
            ]
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
示例 12B. Karma `test` 架构目标,带有全局样式。

如果一个 UI 库在多个应用程序之间共享,并且有依赖于它们各自全局样式的测试,那么我们将不得不test为该项目创建多个配置,如清单 12C 所示。

{
  "//": "angular.json",
  "projects": {
    "ui-buttons": {
      "architect": {
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "configuration": {
            "booking": {
              "styles": [
                "libs/booking/shared/styles/src/index.scss"
              ]
            },
            "check-in": {
              "styles": [
                "libs/check-in/shared/styles/src/index.scss"
              ]
            }
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
示例 12C. Karma `test` 架构目标,具有多个全局样式配置。

不妨在本地试试。

Angular CLI 现在已链接index.scssindex.html本地​​开发服务器和已部署的环境中,其中样式表是应用程序包的一部分。

务必进行测试。添加全局样式并验证它们是否已应用。

nx build --prod

npx http-server dist/apps/tiny-app -o
Enter fullscreen mode Exit fullscreen mode
清单 6(重复)。构建生产环境软件包,并使用静态 Web 服务器在本地提供服务。

运行nx serve --open以在本地测试全局样式,或者运行清单 6 中的命令以在本地静态 Web 服务器上提供生产包。

提取环境工作区库

在启动我们的 Angular 应用程序之前,我们会根据对象的布尔属性是否已设置或已清除main.ts来有条件地调用。enableProdModeproductionenvironment

在生产模式下,运行enableProdMode禁用了额外的运行时变更检测周期。在开发模式下,正是这个额外的周期触发警告ExpressionChangedAfterItHasBeenCheckedError

在开发模式下,Angular 的核心部分会进行额外的运行时断言。

生成工作区库

尽管我们将提取的工作区库非常小且非常专业,但它确实包含 TypeScript,因此lint架构test目标仍然有用。

nx generate library environments --directory=shared --tags="scope:shared,type:environments" --style=scss

npx rimraf ./libs/shared/environments/src/lib/*.*
Enter fullscreen mode Exit fullscreen mode
清单 13. 生成共享环境库并清除其中生成的内容。

src/lib清单 13 显示,我们首先生成环境库。然后,我们删除库子文件夹中生成的文件。

移动环境文件并配置应用程序依赖项

在环境库中创建一个空lib文件夹后,我们将环境文件从应用程序项目移出,通过库的入口点公开这些文件,最后删除environments应用程序项目的文件夹。所有这些操作都可以通过执行清单 14 中的命令来完成。

mv ./apps/tiny-app/src/environments/*.* ./libs/shared/environments/src/lib

"export * from './lib/environment';" > ./libs/shared/environments/src/index.ts

npx rimraf ./apps/tiny-app/src/environments
Enter fullscreen mode Exit fullscreen mode
清单 14. 移动环境文件并设置库入口点。

要配置 Angular 应用程序项目以使用基于构建配置的工作区库中的环境文件,我们导航到tiny-app:buildarchitect 目标,并将配置选项angular.json替换为清单 15 中的条目。fileReplacementsproduction

{
  "//": "angular.json",
  "projects": {
    "tiny-app": {
      "architect": {
        "build": {
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "libs/shared/environments/src/lib/environment.ts",
                  "with": "libs/shared/environments/src/lib/environment.prod.ts"
                }
              ]
            }
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
清单 15. 配置应用程序的生产构建配置,以使用 environments 库中的生产环境文件。

只剩最后一件事要做。我们需要更新导入语句,main.ts使其使用如清单 16 所示的 environments workspace 库。

// main.ts
import { enableProdMode } from '@angular/core';
import { environment } from '@workspace/shared/environments';

if (environment.production) {
  enableProdMode();
}
Enter fullscreen mode Exit fullscreen mode
清单 16. 从 environments 工作区库导入 `environment` 对象。

不妨在本地试试。

Angular CLI 现在在生产包中替换了environment.tsenvironment.prod.ts即使我们的应用程序项目仅对有传递依赖environment.ts

请务必尝试一下。运行后请查看浏览器控制台,应该会输出nx serve --open相关信息。Angular is running in the development mode. Call enableProdMode() to enable the production mode.

nx build --prod

npx http-server dist/apps/tiny-app -o
Enter fullscreen mode Exit fullscreen mode
清单 6(重复)。构建生产环境软件包,并使用静态 Web 服务器在本地提供服务。

当使用清单 6 中的命令在本地运行生产包时,浏览器控制台中不应输出任何消息。

向库添加编译时配置

我们可以使用 environments 库来配置应用程序的依赖项,因为它允许在编译时配置方法中使用我们的环境配置。

通常我们会添加一个环境提供程序,供服务、可声明对象和 Angular 模块注入,但这对于返回值的方法来说是不可能的ModuleWithProviders<T>,例如forRootAngular 模块上的静态方法。

Angular 模块导入也是如此。如果我们想在开发模式下加载某些 Angular 模块,但在生产模式下不加载,就不能依赖提供的环境变量值。我们需要静态访问该值,因为它是在编译时计算的。

如果工作区库依赖于应用程序项目,那将是一个糟糕的想法。这违背了结构良好架构中依赖关系的原则,并可能导致循环依赖。

添加并配置 NgRx Store

作为用例,我们将使用ng add清单 17 中所示的原理图来添加 NgRx Store 及其开发工具。

nx add @ngrx/store --minimal false

nx add @ngrx/store-devtools
Enter fullscreen mode Exit fullscreen mode
清单 17. 添加 NgRx Store 和 NgRx Store 开发工具。

我们将把 NgRx Store 配置从 `<module>` 迁移AppModule到 `<module>` CoreModule,因为这是传统 Angular 应用项目中配置根注入器的首选方法。` CoreModule<module>` 由 `<module>` 导入AppModule,可以在清单 18 中看到。

// core.module.ts
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '@workspace/shared/environments';

import { metaReducers, reducers } from './reducers';

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, {
      metaReducers,
    }),
    StoreDevtoolsModule.instrument({
      logOnly: environment.production,
      maxAge: 25,
    }),
  ],
})
export class CoreModule {}
Enter fullscreen mode Exit fullscreen mode
清单 18. NgRx Store 已配置为我们核心 Angular 模块中的根注入器。

在传统的 Angular 工作区中,这样做没问题,但我们希望通过最大限度地减少应用程序项目中包含的逻辑量​​来维护一个小型应用程序项目。

提取共享数据访问库

我们希望将 NgRx 特有的根注入器配置保留在工作区库中。NgRx 规定了一种数据访问工作区库类型,因此让我们生成一个并将配置逻辑提取到其中。

nx generate library data-access --directory=shared --tags="scope:shared,type:data-access" --style=scss

mv ./apps/tiny-app/src/app/reducers ./libs/shared/data-access/src/lib
Enter fullscreen mode Exit fullscreen mode
清单 19. 生成共享数据访问库,然后移动生成的 reducer 文件夹和文件。

执行清单 19 中的命令,生成共享数据访问库,并将src/app/reducers添加 NgRx Store 时生成的子文件夹移动到该库。

找到libs/shared/data-access/src/lib/shared-data-access.module.ts并编辑该文件,使其包含清单 20 中的文件内容。

// shared-data-access.module.ts
import { ModuleWithProviders, NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '@workspace/shared/environments';

import { metaReducers, reducers } from './reducers';

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, {
      metaReducers,
    }),
    StoreDevtoolsModule.instrument({
      logOnly: environment.production,
      maxAge: 25,
    }),
  ],
})
export class SharedDataAccessRootModule {}

@NgModule({})
export class SharedDataAccessModule {
  static forRoot(): ModuleWithProviders<SharedDataAccessRootModule> {
    return {
      ngModule: SharedDataAccessRootModule,
    };
  }
}
Enter fullscreen mode Exit fullscreen mode
清单 20. Root 注入器数据访问配置模块。

我们遵循此forRoot模式,表明导入此 Angular 模块时提供的依赖项是针对根注入器的。这是通过创建一个返回ModuleWithProviders<T>对象的静态方法来实现的。

SharedDataAccessRootModule包含 providers 对象的模块所引用的配置,是在我们创建此库之前存在的配置CoreModule

最后,找到apps/tiny-app/src/app/core.module.ts并编辑该文件的内容,使其与清单 21 中的内容一致。

// core.module.ts
import { NgModule } from '@angular/core';
import { SharedDataAccessModule } from '@workspace/shared/data-access';

@NgModule({
  imports: [
    SharedDataAccessModule.forRoot(),
  ],
})
export class CoreModule {}
Enter fullscreen mode Exit fullscreen mode
示例 21. 一个简单的 Angular 核心模块,仅导入工作区库模块。

重组之后,我们最终得到了如图 2 所示的工作区依赖关系图。

图 2. 添加共享数据访问库后的工作区依赖关系图。

如果没有提取共享环境库,我们就无法在共享数据访问库中导入环境文件。首先,它tiny-app没有作用域路径映射。其次,库项目绝不能依赖于应用程序项目。

添加一个仅用于开发模式的元 reducer

现在我们可以使用环境对象来配置注入器。生成的 NgRx Store 配置代码在另一个地方执行此操作,即在 reducers 文件中,如清单 22 所示,其中定义了元 reducers。

// reducers/index.ts
import { ActionReducerMap, MetaReducer } from '@ngrx/store';
import { environment } from '@workspace/shared/environments';

export interface State {}

export const reducers: ActionReducerMap<State> = {};

export const metaReducers: MetaReducer<State>[] =
  !environment.production ? [] : [];
Enter fullscreen mode Exit fullscreen mode
列表 22. Meta reducers 默认是生产模式感知的。

让我们使用 NgRx 文档中的一个示例来添加一个仅用于开发的调试元 reducer。

// reducers/debug.ts
import { ActionReducer } from '@ngrx/store';

export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
  return (state, action) => {
    console.log('state', state);
    console.log('action', action);

    return reducer(state, action);
  };
}
Enter fullscreen mode Exit fullscreen mode
清单 23. 调试元 reducer。

清单 23 中的调试元 reducer 会在每次 action 即将被 reduce 时记录 NgRx Store 的状态和已分发的 action。

// reducers/index.ts
import { ActionReducerMap, MetaReducer } from '@ngrx/store';
import { environment } from '@workspace/shared/environments';

import { debug } from './debug';

export interface State {}

export const reducers: ActionReducerMap<State> = {};

export const metaReducers: MetaReducer<State>[] =
  !environment.production ? [debug] : [];
Enter fullscreen mode Exit fullscreen mode
清单 24. 调试元 reducer 在开发模式下启用,但在生产模式下未启用。

清单 24 展示了如何在开发模式下添加调试元 reducer。请注意,我们从 environments 库导入了 environment 对象。

// shared-data-access.module.ts
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';

import { metaReducers, reducers } from './reducers';

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, {
      metaReducers,
    }),
  ],
})
export class SharedDataAccessRootModule {}
Enter fullscreen mode Exit fullscreen mode
清单 25(节选)。Root 注入器数据访问配置模块。注意:请勿使用此部分内容覆盖您的文件。

导出的metaReducers数组用于配置根存储,如清单 25 所示。

图 3. 共享数据访问库文件和文件夹结构。

图 3 显示了我们共享数据访问库的文件和文件夹结构,其中包含根存储配置和元归约器。

配置 Nx 工作区依赖项

Nx 工作区具有工作区配置,可用于设置对内部依赖项的限制,并指示 Nx 了解在应用程序和库 TypeScript 文件中不可见的依赖项。

{
  "//": "nx.json",
  "projects": {
    "tiny-app": {
      "implicitDependencies": [
        "shared-assets",
        "shared-styles"
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
清单 25. 配置应用程序项目的隐式依赖项。

清单 25 展示了我们如何配置应用程序项目,使其隐式依赖于资源库和样式库。这是必要的,因为没有 TypeScript 导入语句引用这两个工作区库。

环境库已导入main.ts,因此它具有明确的依赖项,Nx 可以自行获取该依赖项。

配置这些依赖项可确保 Nx 的affected:*命令能够获取资源库和样式库中所做的更改。

这将在运行时触发应用程序项目重建nx affected:build。它还会触发应用程序单元测试和端到端测试的运行nx affected:testnx affected:e2e最后,在运行时会显示已更改和受影响的工作区项目nx affected:dep-graph

Angular Tiny App 工作区依赖关系图。共享样式库影响了应用程序项目及其端到端测试项目。

图 4. 更改全局样式后的依赖关系图。为简洁起见,省略了共享数据访问库。

_global.scss当我们对并运行进行更改时nx affected:dep-graph,我们会得到如图 4 所示的依赖关系图。突出显示的节点(项目)受到更改的影响。

一个小型 Angular 应用程序项目

在重组我们的应用程序工作区之后,我们的依赖关系图是一个有向无环图(通常缩写为 DAG),依赖关系指向正确的方向,如图 5 所示。

工作区依赖关系图。

图 5. 工作区依赖关系图。为简洁起见,省略了共享数据访问库。

端到端测试项目tiny-app-e2e依赖于应用程序项目,这意味着它会受到应用程序项目变更的影响,因此其测试需要重新运行。

该应用程序项目tiny-app依赖于共享工作空间库shared-environmentsshared-assets并受其变更的影响shared-styles。当其中一个库发生变更时,应用程序必须重新构建并重新运行其测试套件。图 2 展示了一个示例,其中shared-styles发生了变更。

工作区库不应依赖于应用程序项目。必须始终如此,否则就是我们做错了。

我们的应用程序项目逻辑极简,几乎没有任何需要修改的理由。也几乎没有任何理由需要再次修改这个应用程序项目。

nx affected:dep-graph在拉取请求中,通过查看文件更改的工作区库文件夹名称,或者像我们在前一章中看到的那样运行命令,很容易就能看到哪些内容正在被更改或扩展。

图 6. 默认的 Nx Angular 应用程序项目文件和文件夹结构。

图 6 显示了 Nx 生成的 Angular 应用程序的默认文件和文件夹结构。图中省略了配置文件tsconfig.jsontslint.json因为本文演示的技术不会修改这些文件。

图 7. 小型应用程序项目文件和文件夹结构。

在小型应用程序项目中,src/app与默认应用程序项目相比,子文件夹中的文件保持不变,只是我们在创建共享数据访问库时添加了CoreModule一个。core.module.ts

如图 7 所示,src除 之外, 的所有子文件夹都已移动src/app

共享资产工作区库

如图 8 所示,assets文件夹已从应用程序项目中移至工作区库中。shared-assets

图 8. 共享资产工作区库文件和文件夹结构。

我们创建了公共资源文件夹fontsicons和,images并将 Nx 徽标打包在一起,如src/assets/images资源库的子文件夹中所示。

这些.gitkeep文件是空的占位符文件,用于在 Git 仓库中保持文件夹结构不变,即使其中没​​有实际文件。当文件被放入文件夹并纳入版本控制后,就可以删除这些占位符文件。例如,src/assets/images/.gitkeep既然我们已经将文件添加nx-logo-white.svg到同一个父文件夹中,那么删除这些占位符文件就没问题了。

网站图标位于src默认应用程序项目的子文件夹中。我们也把该文件移动到了资源库的src子文件夹中。

tiny-app:build架构目标中的 Glob 模式angular.json确保资源工作区库中的文件在应用程序构建过程中被打包。

该库没有 TypeScript 配置文件,因为它只包含静态文件。

共享样式工作区库

如图 9 所示,全局样式表styles.scss已从应用程序项目的src子文件夹移动到工作区库中。shared-styles

图 9. 共享样式工作区库文件和文件夹结构。

styles.scss为了将其转换为 Sass 局部模板,已将其重命名_global.scss。该 Sass 局部模板位于src/lib样式工作区库的子文件夹中。它由index.scss该子文件夹中的入口点样式表导入src

该库不包含 TypeScript 配置文件,因为它只包含样式表和 Sass 局部模板。

共享环境工作区库

如图 10 所示,环境文件已从应用程序项目的src/environments子文件夹移动到我们的环境工作区库的子文件夹中。src/lib

图 10. 共享环境工作区库文件和文件夹结构。

环境对象由环境库的入口点(也称为其公共 API)重新导出,该入口点定义在index.ts

TypeScript、TSLint 和 Jest 的配置文件以及架构目标都会被保留linttest因为工作区库包含 TypeScript。

结论

我们已经创建了一个包含单个 Angular 应用的 Nx 工作区。即使在添加任何功能之前,我们也可以提取工作区库以遵循单一职责原则。

资源库

共享资源工作区库包含静态文件,例如网页字体、图标和图像。它还包含网站图标(favicon)。Web 应用程序清单也会添加到此处。

我们看到了一个示例,演示如何向该库添加图像文件,并在应用程序项目中引用它。当然,这种方法也适用于 UI 工作区库和功能库。

通过将静态文件放在单独的工作区库中,我们降低了在添加、删除或修改静态文件时破坏整个应用程序的风险。

样式库

有了专门用于全局样式的工作区库,我们就不必因为用几十个 Sass 局部视图污染应用程序项目而感到内疚,也不必冒着意外破坏应用程序设置的风险。

共享样式工作区库还可以公开组件样式或 UI 工作区库之间共享的 Sass mixin、函数和局部模型。

环境库

将环境文件提取到共享工作区库中,我们可以有条件地从工作区库(例如我们创建的共享数据访问库)配置注入器,以便在根注入器中配置 NgRx Store。

在实际应用中,我们可以添加一个功能外壳库,使其成为由 `<module>`AppModule或 `<module>`导入的编排 Angular 模块CoreModule

如果没有现成的功能外壳库,我们就必须修改应用程序项目才能进一步配置根注入器或添加应用程序用例。这存在风险。为了安心起见,大多数情况下最好不要修改应用程序项目。

共享工作区库

本文示例中,我们将提取的工作区库放入shared库分组文件夹并添加了scope:shared标签。对于仅包含单个应用程序的工作区,可能无需执行此操作。

然而,随着应用程序的增长,我们会庆幸当初在项目初期就使用了分组文件夹。应用程序范围的工作区库位于shared分组文件夹中,而我们使用子域分组文件夹来对功能库及其相关的数据访问、域和 UI 工作区库进行分组。

或者,我们最终会在该libs文件夹内得到几十个甚至上百个库文件夹,每个文件夹的名称都会越来越长。

如果将来我们需要向工作区添加其他应用程序,我们会将需要在应用程序之间共享的工作区库放在shared库分组文件夹中。而那些我们可能想要或不想在应用程序之间共享的库,则可以放在以应用程序名称命名的库分组文件夹中,例如,libs/tiny-app/shared用于存放应用程序项目特有的应用程序级库tiny-app

资源

欢迎在 GitHub 上克隆LayZeeDK/nx-tiny-app-project该项目,体验完整的解决方案

观看 Oscar Lagatta 对本文的视频讲解

在Nacho Vázquez 的《使用 Nx 和 Monorepo 架构的 Shell 库模式》一书中,学习如何实现功能 shell 库。

同行评审员

感谢Nacho Vazquez对本文提出的宝贵意见,以及我们之间许多有趣的讨论,这些讨论让我们对建筑设计有了共同的见解🙇‍♂️

文章来源:https://dev.to/this-is-angular/tiny-angular-application-projects-in-nx-workspaces-229a