Angular 8 升级之旅及新特性详述

Upgrade To Angular 8

原文链接

1. Upgrade Angular

  1. 确保 angular-cli 已经安装
    npm install -g @angular/cli

  2. 执行 ng update 获取当前项目可用的更新
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iqotlai9-1576941188359)(evernotecid://7D5162EA-5D37-473F-9C81-E2FEC23DD3B2/appyinxiangcom/18499762/ENResource/p405)]

  3. 执行 ng update --all 尝试更新
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F0OllsHg-1576941188362)(evernotecid://7D5162EA-5D37-473F-9C81-E2FEC23DD3B2/appyinxiangcom/18499762/ENResource/p406)]

  4. 处理异常依赖, 解决错误.

一起更新可能会存在冲突, 逐个更新相应组件

ng update @angular/cli @angular/core  --allow-dirty
ng update @angular/cdk @angular/material --allow-dirty

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TGNJryCx-1576941188363)(evernotecid://7D5162EA-5D37-473F-9C81-E2FEC23DD3B2/appyinxiangcom/18499762/ENResource/p407)]

  1. 删除 node_modules 重新编译. 处理错误.
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AKWVm0rK-1576941188364)(evernotecid://7D5162EA-5D37-473F-9C81-E2FEC23DD3B2/appyinxiangcom/18499762/ENResource/p408)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wqW8OsMq-1576941188365)(evernotecid://7D5162EA-5D37-473F-9C81-E2FEC23DD3B2/appyinxiangcom/18499762/ENResource/p409)]

Upgrade Document
Angular Change Log
Useful Blog

2. Angular 8 新特性

2.1 Ivy 编译器

  • Ivy 是新的 Angular 编译器,也是新的渲染管道。Ivy 有可能产生相当小 bundle,它使渐进式编译更容易,也是 Angular 领域未来创新的基础。
  • 在 Angular 8 中 Ivy 的预览版现在可供测试。此版本的目标是获得早期反馈。因此,Angular 团队建议不要把 Ivy 用于生产环境,而是继续使用经典视图引擎(图1)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CI548AMu-1576941188365)(evernotecid://7D5162EA-5D37-473F-9C81-E2FEC23DD3B2/appyinxiangcom/18499762/ENResource/p410)]

  • 值得一提的是通过 ng build 创建的程序的大小。等到 Angular 9 发布时 Ivy 最终应该会默认激活(目前最新版本 8.2.14–2019/12/15)。在此之前,Angular 团队计划采取进一步措施以确保与旧版本的兼容性.
    想尝鲜的人儿可以尝试一下未来的 Ivy API。目前这些 API 仍然被标记为私有。你可以通过查看它的类和函数来进行判断:它们以特殊字符 ɵ 开头。

如果你想尝试 Ivy,可以通过 enable-ivy 开关生成一个新项目:
ng new ivy-project --enable-ivy
或者在你心有的项目的 tsconfig.app.json 文件中添加:

"angularCompilerOptions": { 
        "enableIvy": true 
}

2.2 差异加载

目前将程序编译成旧 ECMAScript 5 代码仍然是很常见的,因为“古老的 JavaScript ”在今天仍然在到处运行。这意味着 IE 11 和 Google 搜索引擎后面的网络爬虫都可以执行这些代码。
但是,新的 ECMAScript 2015 及其后续版本更加高效:这些版本允许更紧凑的 bundle 包,浏览器也可以更有效地解释它们。

Angular 8 提供了一个名为差异加载的功能。其背后的想法是提供两组 bundle:一组基于 ECMAScript 5 并且针对较旧的浏览器,另一组基于较新的 ECMAScript 版本,例如 ECMAScript 2015,以此为现代浏览器提供优势。

激活差异加载

  • tsconfig.json 文件中修改版本信息:
    "target": "es2015",
  • 提供 browserlist 配置:
    defaults config:
# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For IE 9-11 support, please uncomment the last line of the file and adjust as needed
> 0.5% # 市场占有率
last 2 versions # 最新的两个版本
Firefox ESR # 延长支持版本
not dead # 不满足市场占有率要求, 且两年内没有官方支持与维护.
# IE 9-11 # 默认不支持 IE 9-11

2.3 懒加载

Angular 路由垃圾加载自 Angular 诞生就支持. 如下:

{
    path: "monitor",
    loadChildren: "./monitor/em-monitor.module#EmMonitorModule"

“#”号之前的值表示通向模块实现的文件的路径;之后的值代表其中包含的类。这种写法也适用于 Angular 8,但是已经被弃用了,现在支持动态 ECMAScript 导入:

{
    path: "monitor",
    loadChildren: () => import("./monitor/em-monitor.module").then(m => m.EmMonitorModule)
},

新的书写风格中仍然包含文件名作为魔术值。但是由于许多IDE支持导入,因此无效值将立即返回错误。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aLh2alwG-1576941188366)(evernotecid://7D5162EA-5D37-473F-9C81-E2FEC23DD3B2/appyinxiangcom/18499762/ENResource/p411)]

2.4 ViewChild 和 ContentChild

ViewChild 和 ContentChild 的使用方式发生了重大变化,但遗憾的是,过去并不总是表现出一致的行为。虽然它们在早期版本中被用于组件请求不在结构指令内的元素,如 ngIf 或 ngFor,但查询结果已在 ngOnInit 中可用。否则,程序代码或过早的可以在 ngAfterViewInit(或 ngAfterContentInit for ContentChild )中访问它。对于以后因数据绑定而仅加载到 DOM 中的元素,程序代码必须分别插入 ngAfterViewChecked 或 ngAfterContentChecked。
由于这种行为十分令人困惑,所以现在组件必须指定何时应该进行解决:

@ViewChild("info", { static: false })
elemRef: ElementRef;

如果 static 的值为 true,则 Angular 会在初始化组件时尝试查找该元素。这只在不在结构指令中时才有效。使用 static:false 时,在启动或刷新视图后进行解析。

ng update 命令 会自动尝试在此处输入正确的值。如果无法做到这一点,则会在其位置添加带有 TODO 的注释。

设置static: true将不允许您从动态模板分辨率(例如ngIf)获得结果。

与相关装饰器 ViewChildren 和 ContentChildren 的查询不受此更改的影响。他们总是表现出 static:false 意义上的动态行为。

如果需要在 construct, nginit…等方法中访问, 就设置为 true, 否则设置为 false.

2.5 upgrade: Location

Location 服务中添加了用于监视URL更改的新方法 onUrlChange 以及其他修改:

export class AppComponent {
  constructor(loc: Location, pLoc: PlatformLocation) {
    loc.onUrlChange((url) => console.debug('url change', url));
    console.debug('hostname: ', pLoc.hostname);
  }
}

PlatformLocation 服务提供对 URL 各个部分的附加访问.

2.6 SVG Template

您现在可以将SVG文件用作模板。到目前为止,我们只能选择使用内联HTML或外部HTML作为模板.

@Component({
  selector: "app-icon",
  templateUrl: "./icon.component.svg",
  styleUrls: ["./icon.component.css"]
})
export class AppComponent {...}

2.7 Web worker

根据定义,JavaScript 是单线程的。因此,对于数据调用等较大任务异步处理是很常见的。不用说,这对计算密集型没有帮助。特别是那些广泛的 JavaScript 解决方案变得越来越普遍,这就是为什么现在几乎所有的浏览器都支持支持 Web worker。它们是浏览器在自己的线程中运行的脚本。通过发送消息与浏览器选项卡中的线程进行通信。

虽然 Web worker 本身与 Angular 无关,但在构建过程中必须考虑它们。目标是为每个 Web worker 提供一个 bundle 包。此任务由新的 Angular CLI 完成。

通过以下命令添加一个 Worker:
ng generate webWorker workerName

接口:
var myWorker = new Worker(aURL, options);

options:

  • type: A DOMString specifying the type of worker to create. The value can be classic or module. If not specified, the default used is classic.
  • credentials: A DOMString specifying the type of credentials to use for the worker. The value can be omit, same-origin, or include. If not specified, or if type is classic, the default used is omit (no credentials required).
  • name: A DOMString specifying an identifying name for the DedicatedWorkerGlobalScope representing the scope of the worker, which is mainly useful for debugging purposes.
/// <reference lib="webworker" />

addEventListener('message', ({ data }) => {
  const response = `worker response to ${data}`;
  postMessage(response);
});

在 app.component.ts 中

if (typeof Worker !== 'undefined') {
   // Create a new
   const worker = new Worker('./workerName-worker.worker', { type: 'module' });
   worker.onmessage = ({ data }) => {
      console.log(`page got message: ${data}`);
   };
   worker.postMessage('hello');
} else {
   console.log("===Web Workers are not supported in this environment.==");
}

Web Worker 官方指南

Web Worker Angular 使用手册

2.8 Bazel

Bazel是谷歌开源的另一款工具。Bazel已经在内部使用了很长时间,现在可供所有人使用。您可以参考 Angular 的 Bazel 文档,并了解如何将其与Angular一起使用。

你可能想知道:“Bazel准备好了吗?”简答:还没有。目前,它处于“选择预览”模式。Bazel可作为选择加入,预计将包含@angular/cli在第9版中。

  • 要为选择的为现有应用添加它,请运行
    ng add @angular/bazel

  • 要在新的应用中使用 Bazel,首先要全局安装@angular/bazel
    npm install -g @angular/bazel
    然后使用下列命令创建新的应用
    ng new --collection=@angular/bazel

在某些情况下,你会想要绕过 Angular CLI 的构建器,并直接运行Bazel CLI。 Bazel CLI 位于 @bazel/bazel npm 包中。你可以全局安装它,以便你能通过路径获取 bazel 命令,或者用 $(npm bin)/bazel 代替下面的 bazel。
Bazel 的常用命令有:

  • bazel build [targets]:编译指定目标的默认输出成果。
  • bazel test [targets]:对于那些符合 *_test 模式的目标,运行测试。
  • bazel run [target]:编译目标所代表的程序,然后运行它。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cECQGnWb-1576941188369)(evernotecid://7D5162EA-5D37-473F-9C81-E2FEC23DD3B2/appyinxiangcom/18499762/ENResource/p412)]

2.9 BUILDERS/Architect

"projects": {
    "angboot-web": {
      "root": "",
      "sourceRoot": "src",
      "projectType": "application",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "../server/build/resources/main/static/app/",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.app.json",
            "showCircularDependencies": false,
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css",
              "./node_modules/bootstrap/dist/css/bootstrap.css",
              "src/styles.scss"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "extractCss": true,
              "namedChunks": false,
              "aot": true,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true
            }
          }
        },
        "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "angboot-web:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "angboot-web:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "angboot-web:build"
          }
        },
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "main": "src/test.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "src/tsconfig.spec.json",
            "karmaConfig": "./karma.conf.js",
            "styles": [
              "./node_modules/@angular/material/prebuilt-themes/pink-bluegrey.css",
              "src/styles.scss"
            ],
            "scripts": [],
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ]
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "src/tsconfig.app.json",
              "src/tsconfig.spec.json"
            ],
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }
    },
    "angboot-web-e2e": {
      "root": "e2e/",
      "projectType": "application",
      "architect": {
        "e2e": {
          "builder": "@angular-devkit/build-angular:protractor",
          "options": {
            "protractorConfig": "e2e/protractor.conf.js",
            "devServerTarget": "angboot-web:serve"
          }
        },
        "lint": {
          "builder": "@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": "e2e/tsconfig.e2e.json",
            "exclude": [
              "**/node_modules/**"
            ]
          }
        }
      }

从现在开始,我们可以创建自定义构建器, 基本上,构建器只是一个带有一组命令的函数,您可以createBuilder()从@angular-devkit/architect包传递给方法。

import { createBuilder } from '@angular-devkit/architect';
function customBuild(options, context) { 
  return new Promise((resolve, reject) => {
    // set of commands
  })
}
createBuilder(customBuild); 

Angular 内置 Builders

2.10 表单改进

  • 添加了markAllAsTouched方法以标记所有的控件FormGroupas as touched。如果要触发一个表单组中所有控件的验证,这个方法将是非常有用的。之前我们不得不使用下面的代码片段来实现相同的功能:
validateFormAndDisplayErrors(form: FormGroup) {
  Object.keys(form.controls).map((controlName) => {
    form.get(controlName).markAsTouched({onlySelf: true});
  });
}
  • 从 FormArray 中清除所有元素
formArray.clear()

以前要删除所有元素,formArray 我们必须循环删除第一个元素直到空:

while(formArray.length){ 
  formArray.removeAt(0); 
}

2.11 弃用的API

  • 从 @angular/platform-browser中删除了已弃用的DOCUMENT
从@angular/platform-browser中移除了DOCUMENT。如果您使用DOCUMENT from @angular/platform-browser,则应从此处开始导入@angular/common。
  • @angular/http
@angular/http在Angular 5中不推荐使用package,但由于@angular/platform-server依赖于它,所以仍然可用。从现在它已从包列表中删除。
  • Angular Material工程重命名为Angular Components。包还是跟以前保持一样的。

最后

Angular 9 目前已经在筹备当中, 如果有兴趣, 可以关注 GitHub, 查看并了解最新进展

发布了25 篇原创文章 · 获赞 36 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/DreamLi1314/article/details/103651796