使用 Angular 6 构建 PWA

已发表: 2022-03-10
快速总结↬在本教程中,我们将使用 Angular 6 逐步构建一个渐进式 Web 应用程序,使用 Angular CLI v6 实现 PWA 的核心原则。

在本教程中,我们将使用最新的 Angular 6 通过实现构成 PWA 的核心原则来构建 PWA。 我们将首先创建一个使用 JSON API 的前端 Web 应用程序。 为此,我们将使用 Angular HttpClient模块将 HTTP 请求发送到从 Simplified JavaScript Jargon GitHub 存储库生成的静态 JSON API。 我们还将使用 Material Design 通过 Angular Material 包构建 UI。

接下来,我们将使用 Chrome DevTools 的“审核”面板(Lighthouse)来根据 PWA 的核心原则分析我们的 Web 应用程序。 最后,我们将根据 Lighthouse 报告中的“Progressive Web App”部分解释 PWA 功能并将其添加到我们的 Web 应用程序中。

在开始实施 PWA 之前,让我们先介绍一下 PWA 和 Lighthouse。

推荐阅读Native 和 PWA:选择,而不是挑战者!

什么是 PWA?

渐进式 Web 应用程序或 PWA 是一种 Web 应用程序,它具有一组功能(类似于原生应用程序),可为用户提供类似应用程序的体验。 PWA 需要满足我们接下来会看到的一组基本要求。 PWA 类似于原生应用,但通过 URL 从 Web 服务器部署和访问,因此我们不需要通过应用商店。

PWA 需要:

  • 进步
    为每个用户工作,无论选择何种浏览器,因为它们是以渐进增强为核心原则构建的。
  • 响应式
    适合任何外形尺寸、台式机、移动设备、平板电脑或其他任何设备。
  • 独立于连接
    增强服务人员以离线或在低质量网络上工作。
  • 类应用
    使用 app-shell 模型提供应用风格的导航和交互。
  • 新鲜的
    由于服务工作者更新过程,始终保持最新状态。
  • 安全的
    通过 HTTPS 提供服务,以防止窥探并确保内容未被篡改。
  • 可发现的
    由于 W3C 清单和服务工作者注册范围允许搜索引擎找到它们,因此可以识别为“应用程序”。
  • 可重新接合
    通过推送通知等功能轻松重新参与。
  • 可安装
    允许用户将他们认为最有用的应用程序“保留”在主屏幕上,而无需使用应用程序商店。
  • 可链接
    通过 URL 轻松共享,无需复杂的安装。
跳跃后更多! 继续往下看↓

介绍灯塔

Lighthouse 是由 Google 创建的开源审计工具,可用于审计网站和应用程序的可访问性性能、SEO、最佳实践和 PWA 功能。

您可以从 Chrome DevTools 中的Audit选项卡作为 Node.js 中的模块或 CLI 工具访问 Lighthouse。 您可以通过提供 URL 然后运行审核来使用 Lighthouse,这将为您提供包含审核结果的报告,这些结果基本上是关于如何改进 Web 应用程序的建议。

安装 Angular CLI v6 并生成项目

在本节中,我们将安装最新版本的 Angular CLI,然后我们将使用它来创建一个新的 Angular 6 项目。

Angular CLI 需要Node.js >= 8.9+ ,所以首先通过运行以下命令确保您安装了所需的版本:

 $ node -v 
Node.js 版本
检查节点版本。 (大预览)

如果您没有安装 Node.js,您可以直接前往官方 Node 下载页面并获取您系统的 Node 二进制文件。

现在,您可以通过运行以下命令继续安装最新版本的 Angular CLI:

 $ npm install -g @angular/cli

注意根据你的 npm 配置,你可能需要添加_sudo_来全局安装包。

您可以通过在终端中运行以下命令来生成 Angular 6 项目:

 $ ng new pwademo

这将创建一个结构如下的项目:

角项目结构
角项目结构。 (大预览)

完成的大部分工作都在包含应用程序源代码的src/文件夹中。

创建 Angular 应用程序

生成项目后,我们将构建一个使用 JSON API 并在主页上显示项目的 Web 应用程序。 我们将使用HttpClient服务来发送 HTTP 请求,并使用 Angular Material 来构建 UI。

添加角度材质

感谢 Angular CLI v6 和新的ng add命令,只需一个命令即可将 Angular Material 添加到您的项目中。 您只需要从终端运行以下命令:

 $ cd pwademo $ ng add @angular/material 
添加角度材质
添加角度材质。 (大预览)

您可以从屏幕截图中看到该命令从 npm 安装所需的包并更新一堆文件以在您的项目中设置 Angular Material,这些文件以前需要手动更新。

设置HttpClient并使用 JSON API

现在,让我们设置 Angular 项目以使用HttpClient发送 HTTP 请求。 首先,您需要在src/app/app.module.ts文件中的主应用程序模块中导入HttpClientModule模块:

 /*...*/ import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ AppComponent ], imports: [ /*...*/ HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

而已。 我们现在可以在属于主模块的任何组件或服务中注入和使用HttpClient

出于演示目的,我们将使用从Simplified JavaScript Jargon GitHub 存储库中静态生成的 JSON API。 如果您正在使用任何其他资源,请确保您启用了 CORS,以便浏览器不会因为Same Origin Policy而不允许读取远程资源。

让我们创建一个与 API 交互的服务。 在您的项目文件夹中,运行:

 $ ng g service api

这将在src/app/api.service.ts文件中创建一个名为ApiService的服务。

现在打开src/app/api.service.ts文件并更新它以反映以下更改:

 import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; export interface Item{ name: string; description: string; url: string; html: string; markdown: string; } @Injectable({ providedIn: 'root' }) export class ApiService { private dataURL: string = "https://www.techiediaries.com/api/data.json"; constructor(private httpClient: HttpClient) {} fetch(): Observable<Item[]>{ return <Observable<Item[]>this.httpClient.get(this.dataURL); } }

我们首先导入了HttpClientObservable类,然后将HttpClient作为httpClient注入到构造函数中,并添加了一个fetch()方法,该方法调用HttpClientget()方法(用于向我们的 JSON 端点发送 HTTP GET 请求)并返回一个 Observable我们可以稍后订阅。

我们还声明了一个Item接口,它表示返回的 JSON 数据的单个项目。

接下来从应用程序组件中导入此服务。 打开src/app/app.component.ts文件并添加:

 import { Component, OnInit } from '@angular/core'; import { ApiService } from './api.service'; import { Item } from './api.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit{ title = 'pwademo'; items: Array<Item>; constructor(private apiService: ApiService){ } ngOnInit(){ this.fetchData(); } fetchData(){ this.apiService.fetch().subscribe((data: Array<Item>)=>{ console.log(data); this.items = data; }, (err)=>{ console.log(err); }); } }

我们导入之前创建的ApiService其注入为apiService ,我们还导入了表示 JSON 数据的单个项目的Item类,我们声明了Array<Item>类型的items变量,它将保存获取的项目。

接下来,我们添加一个fetchData()方法,该方法调用我们在ApiService中定义的fetch()方法,该方法返回一个 Observable。 我们只需订阅这个 observable 以便向我们的 JSON 端点发送一个 GET 请求并获取我们最终分配给items数组的响应数据。

我们在ngOnInit()生命周期事件中调用fetchData()方法,因此一旦AppComponent组件初始化就会调用它。

添加应用程序 UI

我们的应用程序 UI 将包含一个导航栏和将使用 Angular Material 创建的页面框架。

在使用 Angular Material 组件之前,您需要导入它的模块。 每个 Material 组件都属于它自己的模块。

打开src/app/app.module.ts文件并添加以下导入:

 /*...*/ import { MatToolbarModule } from '@angular/material/toolbar'; import { MatCardModule } from '@angular/material/card'; import { MatButtonModule } from '@angular/material/button'; @NgModule({ declarations: [ AppComponent ], imports: [ /*...*/ MatToolbarModule, MatCardModule, MatButtonModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

我们为工具栏、卡片和按钮组件导入模块,并将它们添加到AppModule导入数组中。

接下来,打开src/app/app.component.html文件,删除其中的内容并添加:

 <mat-toolbar color="primary"> <mat-toolbar-row> <span>JS-jargon</span> </mat-toolbar-row> </mat-toolbar> <main> <mat-card *ngFor="let item of items"> <mat-card-header> <mat-card-title>{{item.name}}</mat-card-title> </mat-card-header> <mat-card-content> {{item.description}} </mat-card-content> <mat-card-actions> <a mat-raised-button href="{{item.url}}" color="primary">More</a> </mat-card-actions> </mat-card> </main>

我们使用 Material 组件来创建 UI。 <mat-toolbar>组件用于创建材质工具栏, <mat-card>组件用于创建材质卡等。

当组件初始化时,我们遍历由fetchData()方法填充的items数组,并将项目显示为 Material 卡片。 每张卡片都包含名称、描述和更多信息的链接(该链接使用mat-raised-button指令设置为材质按钮)。

这是应用程序的屏幕截图:

演示应用
演示应用程序。 (大预览)

构建生产应用程序

通常,在检查您的应用程序的 PWA 功能时,您应该首先将其构建用于生产,因为大多数 PWA 功能都没有在开发中添加。 例如,您不希望在开发中启用服务工作者和缓存,因为您需要定期更新文件。

让我们使用以下命令构建用于生产的应用程序:

 $ ng build --prod

生产版本可从dist/pwademo文件夹中获得。 我们可以使用像http-server这样的工具来服务它。

首先,使用以下命令安装http-server

 $ npm i -g http-server

然后,您可以使用以下命令运行它:

 $ cd dist/pwademo $ http-server -o

-o选项将自动打开系统中的默认浏览器并导航到我们的 Web 应用程序可用的https://127.0.0.1:8080/地址。

使用 Lighthouse 分析应用程序

现在让我们使用 Lighthouse 分析我们的应用程序。 首先,启动 Chrome 并访问我们的应用程序地址https://127.0.0.1:8080/

接下来,打开Developer Tools或按Ctrl + Shift + I并单击Audit面板。

执行审计
执行审计。 (大预览)

您最好需要将Emulation设置为Mobile而不是Desktop来模拟移动环境。 接下来,单击执行审核...蓝色按钮。 您将打开一个对话框,您需要在其中选择要对 Web 应用程序执行的审计类型。 取消选中除Progressive Web App之外的所有类型,然后单击运行审核按钮。

渐进式 Web 应用程序审计
渐进式 Web 应用程序审计。 (大预览)

等待 Lighthouse 生成报告。 这是此阶段结果的屏幕截图:

初始 PWA 报告
初步报告。 (大预览)

Lighthouse 执行一系列检查,以验证 PWA 清单指定的渐进式 Web 应用程序的各个方面。 我们得到36100的初始分数,这是因为我们通过了一些审核。

我们的应用程序有7次失败的审计,主要与 PWA 的核心方面Service WorkersProgressive EnhancementHTTPSWeb App Manifest相关。

注册 Service Worker

前两个失败的审计(“不注册服务工作者”和“离线时不响应 200”)与服务工作者和缓存有关。 那么什么是服务人员?

Service Worker 是现代浏览器上可用的一项功能,可用作网络代理,让您的应用程序拦截网络请求以缓存资产和数据。 这可用于实现 PWA 功能,例如离线支持和推送通知等。

要通过这些审核,我们只需要注册一个 service worker 并使用它在本地缓存文件。 离线时,软件应返回文件的本地缓存版本。 稍后我们将看到如何使用一个 CLI 命令添加它。

推荐阅读制作服务工作者:案例研究

渐进增强

第三次失败的审核(“当 JavaScript 不可用时不提供回退内容”)与渐进增强有关,这是 PWA 的一个重要方面,它只是指 PWA 在不同浏览器上运行但提供高级功能的能力,如果他们有空。 PE 的一个简单示例是使用<noscript> HTML 标签,它通知用户需要启用 JavaScript 以在未启用的情况下运行应用程序:

 <noscript> Please enable JavaScript to run this application. </noscript>

HTTPS

第四次失败的审计(“不将 HTTP 流量重定向到 HTTPS”)与 HTTPS 相关,这也是 PWA 的核心方面(服务工作者只能从安全的来源提供服务,除了 localhost)。 “使用 HTTPS”审核本身被认为已通过 Lighthouse,因为我们正在审核 localhost,但是一旦您使用实际主机,您就需要 SSL 证书。 您可以从 Let's Encrypt、Cloudflare、Firebase 或 Netlify 等不同服务获得免费 SSL 证书。

Web 应用清单

三个失败的审核(“不会提示用户安装 Web 应用程序”、“未为自定义启动画面配置”和“地址栏与品牌颜色不匹配”)与缺少的Web 应用程序清单有关,该清单是JSON 格式的文件,提供 PWA 所需的名称、描述、图标和其他信息。 它允许用户像本地应用程序一样在主屏幕上安装网络应用程序,而无需通过应用程序商店。

您需要提供一个 Web 应用清单,并使用<link>标记从index.html文件中引用它,并将rel属性设置为manifest 。 接下来我们将看到如何使用一个 CLI 命令自动执行此操作。

实现 PWA 功能

Angular CLI v6 允许您将 PWA 功能快速添加到现有的 Angular 应用程序中。 您只需在终端中从项目的根目录运行以下命令,即可将您的应用程序转换为 PWA:

 $ ng add @angular/pwa

该命令会自动将 PWA 功能添加到我们的 Angular 应用程序中,例如:

  • 一个manifest.json文件,
  • src/assets/icons文件夹中不同大小的图标,
  • ngsw-worker.js服务工作者。

打开包含生产版本的dist/文件夹。 您会找到各种文件,但让我们专注于与我们上面提到的 PWA 功能相关的文件:

添加了manifest.json文件,其中包含以下内容:

 { "name": "pwademo", "short_name": "pwademo", "theme_color": "#1976d2", "background_color": "#fafafa", "display": "standalone", "scope": "/", "start_url": "/", "icons": [ { "src": "assets/icons/icon-72x72.png", "sizes": "72x72", "type": "image/png" }, { "src": "assets/icons/icon-96x96.png", "sizes": "96x96", "type": "image/png" }, { "src": "assets/icons/icon-128x128.png", "sizes": "128x128", "type": "image/png" }, { "src": "assets/icons/icon-144x144.png", "sizes": "144x144", "type": "image/png" }, { "src": "assets/icons/icon-152x152.png", "sizes": "152x152", "type": "image/png" }, { "src": "assets/icons/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "assets/icons/icon-384x384.png", "sizes": "384x384", "type": "image/png" }, { "src": "assets/icons/icon-512x512.png", "sizes": "512x512", "type": "image/png" } ] }

如您所见,添加的manifest.json文件包含 PWA 所需的所有信息,例如名称、描述和start_url等。

角项目结构
角项目结构。 (大预览)

manifest.json文件,链接到不同大小的图标,这些图标也自动添加到assets/icons文件夹中。 当然,一旦您准备好构建 PWA 的最终版本,您就需要用自己的图标更改这些图标。

角项目结构
角项目结构。 (大预览)

index.html文件中, manifest.json文件通过以下方式引用:

 <link rel="manifest" href="manifest.json">

ngsw-worker.js文件也被自动添加,其中包含 service worker。 安装这个 service worker 的代码会自动插入到src/app/app.module.ts文件中:

 ... import { ServiceWorkerModule } from '@angular/service-worker'; @NgModule({ declarations: [ AppComponent ], imports: [ ... ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }) ],

@angular/service-workerng add命令安装并作为依赖项添加到pwademo/package.json

 "dependencies": { ... "@angular/service-worker": "^6.1.0" }

Service Worker 构建支持也在 CLI 中启用。 在angular.json文件中添加了一个"serviceWorker": true配置选项。

index.html文件中添加了一个值为#1976d2 theme_color theme-color元标记(它也对应于manifest.json文件中的主题颜色值):

 <meta name="theme-color" content="#1976d2">

主题颜色告诉浏览器为地址栏等 UI 元素着色的颜色。

将主题颜色添加到index.htmlmanifest.json文件修复了地址栏匹配品牌颜色审核。

Service Worker 配置文件

另一个文件src/ngsw-config.json已添加到项目中,但它不是 PWA 必需的文件。 它是一个配置文件,允许您指定 Angular 服务工作者应该缓存哪些文件和数据 URL,以及它应该如何更新缓存的文件和数据。 您可以从官方文档中找到有关此文件的所有详细信息。

注意在撰写本文时,使用最新的6.1.3之前的ng add @angular/pwa命令将失败并出现以下错误: Path “/ngsw-config.json” already exists ,因此目前的解决方案是降级@angular/cli@angular/pwa到版本6.0.8

只需在项目中运行以下命令:

 $ npm i @angular/[email protected] $ ng i @angular/[email protected] $ ng add @angular/pwa

现在让我们针对本地托管的本地 PWA 重新运行审计。 这是新的 PWA 分数:

初始 PWA 报告
PWA 报告。 (大预览)

Angular CLI 不会自动添加我们在渐进增强部分中提到的 JavaScript 后备代码,因此请打开src/index.html文件并添加它:

 <noscript> Please enable JavaScript to run this application. </noscript>

接下来,重建您的应用程序并重新运行审核。 这是现在的结果:

初始 PWA 报告
PWA 报告。 (大预览)

我们只有一项与 HTTPS 重定向相关的审核失败。 我们需要托管应用程序并配置 HTTP 到 HTTPS 重定向。

现在让我们针对 PWA 的托管和安全版本运行审计。

PWA 最终报告
PWA 最终报告。 (大预览)

我们得到100100的分数,这意味着我们已经成功实施了 PWA 的所有核心原则。

您可以从此 GitHub 存储库获取此演示 PWA 的最终代码。

结论

在本教程中,我们构建了一个简单的 Angular 应用程序,并使用 Angular CLI 将其转换为 PWA。 我们使用 Google 的 Lighthouse 来审核我们的应用程序的 PWA 功能,并解释 PWA 的各种核心原则,例如用于添加离线支持和推送通知的Service Workers 。 用于启用添加到主屏幕和启动屏幕功能、渐进增强以及HTTPSWeb 清单文件。

您可能还需要手动检查其他突出显示的项目(在“要手动检查的其他项目”部分下),但 Lighthouse 不会自动检查。 Google 的基准 PWA 清单要求这些检查。 它们不会影响 PWA 分数,但手动验证它们很重要。 例如,您需要确保您的网站可以跨浏览器运行,并且每个页面都有一个 URL,这对于在社交媒体上的可共享性很重要。

由于 PWA 还涉及其他方面,例如更好的感知性能和可访问性,您还可以使用 Lighthouse 来审核您的 PWA(或任何一般网站)的这些方面并根据需要对其进行改进。