引入 Angular Service Worker

首先

这篇文章是 Angular Advent Calendar 2017 第17天的文章。

在这篇文章中,我们将介绍如何将 Angular v5 中发布的 @angular/service-worker 引入现有的 Angular 项目中。

角度项目

我没有时间自己准备,所以我会利用这个很不错的示例应用程序来继续进行。

在注册Service Worker之前,让我们先在Lighthouse中进行分析。

$ npm i
$ ng build --prod
$ http-server dist
スクリーンショット 2017-12-18 01.05.30.png

引入 Angular Service Worker

在这篇日文文章中,laco在Angular CLI 1.5下的Angular Service Worker快速入门中表现得非常出色,我在这篇文章中也有很大的参考价值。

$ npm i @angular/service-worker
$ ng set apps.0.serviceWorker=true

这样在 .angular-cli.json 文件中将会添加参数 “serviceWorker”: true 的设置。

然后,Angular Service Worker使用了以下两个文件。

    • ngsw-worker.js: Angular Service Workerの本体

 

    ngsw.json: ngsw-worker.jsが使う設定ファイル

使用Angular CLI的资产功能,将ngsw-worker.js文件从node_modules目录下复制到输出目录的根目录。

  "assets": [
    "assets",
    "favicon.ico",
    "sitemap.xml",
    "googled41787c6aae2151b.html",
    "CNAME",
    {
      "input": "../node_modules/@angular/service-worker",
      "glob": "ngsw-worker.js",
      "output": "."
    }
  ],

通过使用 Angular Service Worker 提供的 ngsw-config 命令来生成 ngsw.json 文件。创建一个新的原始配置文件 src/ngsw-config.json。

{
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": ["/favicon.ico", "/index.html"],
        "versionedFiles": ["/*.bundle.css", "/*.bundle.js", "/*.chunk.js"]
      }
    }
  ]
}

在package.json中注册一个新的构建脚本。

  "scripts": {
    "build:ngsw": "ng build -prod && node_modules/.bin/ngsw-config dist src/ngsw-config.json"
  },

最后,我们需要将ngsw-worker.js文件作为Service Worker注册到应用程序中,为此我们需要在应用程序中引入ServiceWorkerModule。打开app.module.ts文件,并进行以下编辑。

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {FormsModule} from '@angular/forms';
// Import NGSW module
import {ServiceWorkerModule} from '@angular/service-worker';

import {APP_CONFIG, AppConfig} from './config/app.config';

import {AppRoutingModule} from './app-routing.module';
import {SharedModule} from './shared/modules/shared.module';
import {CoreModule} from './core/core.module';

import {AppComponent} from './app.component';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule} from '@angular/common/http';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {HttpLoaderFactory} from './app.translate.factory';
import {HeroTopComponent} from './heroes/hero-top/hero-top.component';
import {ProgressBarService} from './core/progress-bar.service';
import {ProgressInterceptor} from './shared/interceptors/progress.interceptor';
import {TimingInterceptor} from './shared/interceptors/timing.interceptor';

@NgModule({
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    FormsModule,
    HttpClientModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    }),
    SharedModule.forRoot(),
    CoreModule,
    AppRoutingModule,
    // Register ngsw-worker.js as SW
    ServiceWorkerModule.register('/ngsw-worker.js'),
  ],
  declarations: [
    AppComponent,
    HeroTopComponent
  ],
  providers: [
    {provide: APP_CONFIG, useValue: AppConfig},
    {provide: HTTP_INTERCEPTORS, useClass: ProgressInterceptor, multi: true, deps: [ProgressBarService]},
    {provide: HTTP_INTERCEPTORS, useClass: TimingInterceptor, multi: true}
  ],
  bootstrap: [AppComponent]
})

export class AppModule {
}

那么让我们现在试着在这个状态下运行应用程序。

$ npm run build:ngsw
$ http-server dist
スクリーンショット 2017-12-18 01.34.15.png
スクリーンショット 2017-12-18 01.34.38.png

当您使用DevTools或Lighthouse进行检查时,您将会发现已经注册了Service Worker。
并且根据在ngsw-config.json中设置的缓存配置,除了从外部API获取数据的部分之外,其余的离线支持也已经完成。现在就来试一试吧。

スクリーンショット 2017-12-18 01.57.42.png
スクリーンショット 2017-12-18 01.57.55.png

如果在选择「离线」后重新加载或页面转换,则外部的应用程序框架将保持不变,但是英雄信息将不会显示,加载状态将继续。

为了备用离线访问,也要将Hero的信息存入缓存中。

运行时缓存

为此,将使用与之前使用的assetGroups不同的dataGroups。

    • assetGroups

app [shell]のバージョンを追跡していて、グループのうち1つ以上のリソースが更新された場合、利用可能な新しいバージョンのアプリがあるとみなし、対応する更新フローを開始する

dataGroups

appのバージョンとは独立していて、独自のキャッシュポリシーを使ってキャッシュを行う。APIレスポンスを処理するのに適切

在ngsw-config.json中添加dataGroups配置,并进行如下编辑。

{
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.html"
        ],
        "versionedFiles": [
          "/*.bundle.css",
          "/*.bundle.js",
          "/*.chunk.js"
        ]
      }
    }
  ],
  "dataGroups": [
    {
      "name": "api-freshness",
      "urls": [
        "/",
        "/heroes"
      ],
      "cacheConfig": {
        "strategy": "freshness",
        "maxSize": 100,
        "maxAge": "3d",
        "timeout": "10s"
      }
    }
  ]
}
Untitled.gif

即使处于离线状态,英雄的信息也能够从缓存中成功显示出来!

参考资料

    • Angular CLI 1.5によるAngular Service Workerクイックスタート – lacolaco-blog – Medium

 

    • Automatic Progressive Web Apps using the Angular Mobile Toolkit by Maxim Salnikov

 

    • A new Angular Service Worker — creating automatic progressive web apps. Part 1: theory

 

    • A new Angular Service Worker — creating automatic progressive web apps. Part 2: practice

 

    https://angular.io/guide/service-worker-intro

最后

关于ngsw-config.json的设置,请参阅官方文档以获取详细信息,并尝试阅读该文档。

广告
将在 10 秒后关闭
bannerAds