从Angular 7升级到Angular 8(包括附属工具)

首先

这篇文章是 Angular Advent Calender 2月份的第13天(星期五)的文章。
昨天12/12(星期四)是由@noxi515撰写的关于调试Angular视图渲染的文章。

最近在一个Angular项目中,我遇到了从v7升级到v8的情况,所以我将写下这个过程。
由于很快就会发布v9版本,可能有很多人想在它变得不再受支持之前升级,是吧?

虽然可以说只是简单地说“我升级了Angular的版本!”这已经有很多文章散落在各个地方了,不过为了让它更有趣,我打算写到与周围工具一起进行版本维护的地方。

项目的组成

在开始本题之前,我会先解释一下我最近对Angular进行升级的项目。
在这个项目中,我对默认配置进行了一些修改。主要的配置如下:

angular/core v7.2

angular/material v7.2

NgRx v7.4

jest v24.7

jest-preset-angular v7.1

codelyzer v4.5

storybook v4.1

从默认项目来看,主要变更包括将单元测试框架从 karma + jasmine 更改为 jest,同时引入了 Angular material、NgRx 和 Storybook 等内容。回顾一下,这些版本都相当陈旧呢…但是不能置之不理,所以整体进行版本升级。

进行的事情 de

在进行Angular版本升级时非常方便的是Angular升级指南网站(https://update.angular.io/)。
如下图所示,只需输入当前版本、目标版本以及其他一些信息,该网站会将版本升级所需的操作制作成一个检查列表。
在选择应用程序复杂度时可能会有些犹豫,但我选择先设为高级(Advanced),这样可以跳过与此无关的步骤。
(相对于跳过必要的步骤,多走一些额外的步骤更好些,这是一种更可行的方案)

image.png

基本上,只要按照這個列表進行操作即可。但是,當我執行 ng udpate @angular/cli @angular/core 時,出現了下面的錯誤。

Package "@storybook/angular" has an incompatible peer dependency to "zone.js" (requires "^0.8.26", would install "0.9.1").

据说当升级 angular 版本后,storybook 的 peerDependencies 就无法满足了。
这样,通过添加到项目中的附属工具或库可能会产生必须先解决的依赖关系。
因此,我们先暂时绕个弯,先升级 storybook 版本。

提升storybook的版本

基本上,我们将根据这篇博客文章和存放在GitHub代码库中的迁移指南进行操作。因为与Angular无直接关联,所以我们会简单地跳过它。

回退至 Angular 的旧版本

由于storybook的版本已经成功升级到5系并解决了依赖关系的问题,因此我将回归到Angular的版本升级。尽管升级指南中有以下内容,但我在这里遇到了困难。

我们已经从本地的Sass编译器切换到JavaScript编译器。要切换回本地版本,请将其安装为devDependency:npm install node-sass –save-dev。

只有将App Complexity将提升到Advanced才会出现这个选项,而且Angular团队改变的意思是为了好,所以没有必要再改回来…一开始看起来似乎特别没必要做任何事情。

但是事实上,storybook方面依赖于node-sass,所以这样下去storybook将无法启动。

因此,我们需要在devDependencies中添加node-sass,然后将sass编译器还原。

当然,如果您没有使用依赖于node-sass的包,那么这个步骤是不需要的。这次只是偶然需要这样的设置。

还有一些可能会引起问题的项目,例如 @ViewChild / @ContentChild 的规格变更。

只需要一种选择,以下是中文的同义改写:

我是参考了这份幻灯片,解决了问题。我参加了这次发表会,并直接听到了讲话,所以能够很顺利地解决问题。(事实上,这份内容大致已经涵盖了全部。)

升级ngrx的版本

下一步是将ngrx的版本升级到8系。
直到实际进行时,我都不知道ngrx实际上也受到angular-cli的支持,所以下面的命令也有效。

$ ng update @ngrx/store

虽然如此说,但是由于存在一些重大变动,因此我们需要参考下面的链接来进行处理。
https://ngrx.io/guide/migration/v8

为了开玩笑,调整项目的结构

由于将单元测试框架更换为Jest,因此我们需要对此进行维护,以确保其正常工作。为了引入Jest,我们使用了jest-preset-angular。在我们进行此操作的那一天,v8.0.0版本的这个软件包已经发布了(尽管刚刚提升了主要版本,有点令人担心),但既然已经到了这个时候,我们就来进行追踪吧!升级这个版本后,假设以angular-cli v8生成的目录结构为前提。

因为未来很可能其他工具也会基于新的目录结构进行前提,所以我们决定进行调整。
发生变化的是 tsconfig.{app|spec}.json 和 tslint.json,还有 browserslist 的位置。

root
|- ...
|- src/
|  |- ...
|  |- browserslist
|  |- tsconfig.app.json
|  |- tsconfig.spec.json
|  |- tslint.json
|
|- tsconfig.json
|- tslint.json
|- ...
root
|- ...
|- src/
|
|- browserslist
|- tsconfig.app.json
|- tsconfig.spec.json
|- tsconfig.json
|- tslint.json
|- ...

因为 tslint.json 被合并为一个文件,所以将 root/src/tslint.json 中的配置合并到 root/tslint.json 中。
对于 tsconfig.app.json 和 tsconfig.spec.json,由于这些文件中的路径与当前文件或 angular.json 中的路径不一致,因此需要根据新的路径进行调整。

顺便提一下,我在写这篇文章的过程中,意外发现项目中的browserslist竟然无声无息地消失了。通过输出才能意识到这种情况…。

激活 Ivy

完成到这一步,我觉得满足了,但是这样下去似乎无法使用现在流行的 Ivy Renderer。
如果是用 ng new –enable-ivy 创建的项目,那么 Ivy 就会默认启用,但是如果从 v7 升级过来的话,就需要自己编写设置,所以我会在这里进行设置。

按照步骤,只需要在tsconfig.app.json中做一些添加,具体详见这里(https://angular.io/guide/ivy)。

{
  // ...
  "angularCompilerOptions": {
    "enableIvy": true
  }
}

只需一种选择来将以下句子进行汉语本地化重述:
当只加入此设置时,尝试执行 ng build 会显示如下消息:”由于AoT构建变得更快,因此推荐在开发构建中启用它”(在上述链接中的步骤中也有写明)。
因此,我们将编辑 angular.json 文件以始终进行AoT构建。

{
  "projects": {
    "my-app-name": {
      "architect": {
        "build": {
          "options": {
            "aot": true, // <-- false になっていれば true に変更する。なければ追加する。
            // ...
          },
          "configurations": {
            "production": {
              "aot": true, // <-- こっちは本番環境用。デフォルトなら true になっていると思うのでそのままにする。
              // ...

使用 AoT 编译的注意事项

当启用AoT编译并运行ng serve时,每次编辑文件都可能导致构建失败。很可能是AoT编译与ng serve不兼容。(我似乎也见过相关问题,但已经不记得了…)因此,我们只在运行ng serve时不使用AoT编译。

{  
  "scripts": {
    "serve": "ng serve --aot=false"
  }
}

也许如果引入Bazel可能会解决问题吧…。我抱着一丝淡淡的期望。

重新审视lint的配置

我在升级Angular版本的同时,也将codelyzer版本从4.5升至5.2。结果出现了以下警告。

Could not find implementations for the following rules specified in the configuration:
    use-input-property-decorator
    use-output-property-decorator
    use-host-property-decorator
Try upgrading TSLint and/or ensuring that you have all necessary custom rules installed.
If TSLint was recently upgraded, you may have old rules configured which need to be cleaned up.

根据 Codelyzer 上提到的问题,似乎在主版本升级时有一些规则名称发生了变化。
(稍后发现在发布说明中有明确写明)

contextual-life-cycle => 上下文生命周期
no-conflicting-life-cycle-hooks => 无冲突的生命周期钩子
no-life-cycle-call => 不使用生命周期调用
use-life-cycle-interface => 使用生命周期接口
decorator-not-allowed => 不允许使用装饰器
enforce-component-selector => 强制使用组件选择器
no-output-named-after-standard-event => 不使用标准事件命名的输出
use-host-property-decorator => 不使用宿主元数据属性装饰器
use-input-property-decorator => 不使用输入元数据属性装饰器
use-output-property-decorator => 不使用输出元数据属性装饰器
no-queries-parameter => 不使用查询元数据属性
pipe-impure => 不使用不纯净的管道
use-view-encapsulation => 使用组件视图封装
i18n => 模板国际化
banana-in-box => 模板中的香蕉盒子
no-template-call-expression => 不使用模板调用表达式
templates-no-negated-async => 不使用否定的异步模板
trackBy-function => 使用track by函数
no-attribute-parameter-decorator => 不使用属性装饰器
max-inline-declarations => 组件内联声明的最大数量

因此,根据这个规则,我们将修改tslint.json文件中的规则名称为新的规则。

结果 (jié guǒ)

最终,我们成功地进行了版本升级,如下所示。

angular/core v7.2 → 8.2

angular/material v7.2 → 8.2

NgRx v7.4 → 8.4

jest v24.7 (変化なし)

jest-preset-angular v7.1 → 8.0

codelyzer v4.5 → 5.2

storybook v4.1 → 5.2

通常我們看到的文章都會說只需對Angular進行版本升級就完成了!簡單易行!但在實際項目中,還需要處理相關工具,這可能會更麻煩。我在這裡所描述的步驟本身可能不太有用,但如果能傳達整個項目版本維護的氛圍,我會感到高興。

总结

虽然是私人事务,但今天12/13(星期五)是我现任工作的最后一天。我写这篇文章是带着希望这次职业转变能成为我个人的升级。希望读过这篇文章的大家也能迎来美好的升级。

明天是12/14(周六),是@TomoyukiAota先生!请多多关照!

bannerAds