通过Angular 6 Service Worker中的新鲜度缓存资产 [英] Cache asset via freshness in Angular 6 Service Worker

查看:94
本文介绍了通过Angular 6 Service Worker中的新鲜度缓存资产的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Angular Service Worker集成到现有项目中.如果我正确理解的话,有两种情况下如何在Angular SW中缓存数据.可以预取或延迟更新资产数据,并缓存特定的API调用和其他XHR请求.

I'm trying to integrate the Angular Service Worker into a existing project. If I understood it correctly there are two cases how data gets cached in Angular SW. It is possible to prefetch or lazyupdate the asset data and to cache specific API calls and other XHR requests.

我要实现的目标是首先通过网络加载特定资产,如果请求超时或无法访问,则将通过缓存对其进行处理.就像在缓存API调用时使用freshness策略一样. 但是似乎没有办法为Angular项目中作为资产加载的JS文件配置这种新鲜度加载机制. 我已经设置了一个示例项目进行测试: https://github.com/philipp-schaerer-lambdait/angular-service-worker-test

What I'm trying to achieve is to load an specific asset first via network, if the request runs into a timeout or is not accessible it will be served via the cache. Just like the freshness strategy when caching API calls. But it seems that there's no possible way to configure such a freshness loading mechanism for a JS file which is loaded as an asset in the Angular project. I've setup an example Project for testing: https://github.com/philipp-schaerer-lambdait/angular-service-worker-test

以下示例是标准的Angular App,它不包含我正在使用的实际项目,但显示了我要缓存的元素,其结构如下所示:

The following example is a standard Angular App and does not contain the actual project I'm working with but shows the elements I'd like to cache, the structure looks like this:

\_ Angular root  
 |_ src/
   |_ index.html <----------- links to excluded_asset.js
   |_ app/
   |_ assets/
     |_ excluded_asset.js <-- this one is excluded in ngsw-config.json
     |_ included_asset.js
     |_ ...

以下是相关配置:

ngsw-config.json

ngsw-config.json

{
    "index": "/index.html",
    "assetGroups": [
        {
            "name": "app",
            "installMode": "prefetch",
            "resources": {
                "files": ["/favicon.ico", "/index.html", "/*.css", "/*.js"]
            }
        },
        {
            "name": "assets",
            "installMode": "lazy",
            "updateMode": "prefetch",
            "resources": {
                "files": ["/assets/**", "!/assets/excluded_asset.js"]
            }
        }
    ]
}

是否可以通过对资产使用installModeupdateMode来实现类似于freshness策略的缓存行为?

Is it possible to achieve a caching behavior like the freshness strategy by using the installMode and updateMode for the assets?

我试图将其从资产缓存中排除,并且它是通过网络加载的,但显然在下线后服务人员不会提供它.

I've tried to exclude it from the asset cache and it was loaded via network but obviously won't be delivered by the service worker after going offline.

之后,我尝试通过dataGroups再次将其包括在内,并将策略设置为freshness,但是一旦资产从资产配置中排除后,该资产似乎就不会再次被缓存.另外,我不认为dataGroups设置可用于此文件.

After that I've tried to include it again via dataGroups and setting the strategy to freshness but it seems that the asset won't get cached again once it is excluded from the asset configuration. Also I don't think that the dataGroups settings can be used for this file.

"dataGroups": [
    {
        "name": "config",
        "urls": ["assets/excluded_asset.js"],
        "cacheConfig": {
            "maxSize": 10,
            "maxAge": "1d",
            "timeout": "100",
            "strategy": "freshness"
        }
    }
}

我错过了什么吗?还是没有办法通过freshness策略来缓存资产?最好不要移动文件或更改请求文件的方式.

Did I miss something or is there no way to cache an asset via the freshness strategy? It would be preferable not to move the file or to change how the file is being requested.

编辑

我试图将其移到缓存的资产目录之外,并将其包含在dataGroups设置中,但也无法正常工作.

I tried to move it outside the cached assets directories and include it with the dataGroups setting, didn't work either.

推荐答案

服务工作者与新应用

命令如下:

ng new myApp --service-worker (or using the alias — -sw )

具有此服务工作者标志的Angular CLI 1.6将为我们做一些自动化:

Having this service worker flag, Angular CLI 1.6 will do some automation for us:

  1. 将安装Angular Service Worker软件包.
  2. 将启用对NGSW的构建支持.
  3. NGSW将为您的应用程序注册.
  4. 将使用一些智能默认值创建NGSW配置文件.

无论如何,即使在发布CLI 1.6之后,还是很高兴知道如何重现这些步骤,因为我们必须手动执行这些步骤才能将NGSW支持添加到现有应用中.让我们将Angular Service Worker添加到PWAtter中.

Anyway, even after CLI 1.6 will be released, it’s good to know how to reproduce these steps, because we have to perform them manually to add NGSW support to the existing app. Let’s go to add Angular Service Worker to PWAtter.

将Angular Service Worker添加到现有应用中

让我们从上方手动执行相同的4个步骤:

Let’s manually perform the same 4 steps from above:

1.安装NGSW

npm install @angular/service-worker --save

2.启用构建支持(仅适用于Angular CLI 1.6,请参见下面的通知)

ng set apps.0.serviceWorker=true

或手动在.angular-cli.json文件中添加/编辑此参数.

or manually add/edit this parameter in .angular-cli.json file.

重要!目前,当我们使用Angular CLI 1.5时,请确保 确保您在.angular-cli.json中没有此属性,它将 导致构建错误.了解如何在Angular CLI 1.5中模拟此步骤 在下面.

Important! For the moment, when we use Angular CLI 1.5, please make sure that you don’t have this property in .angular-cli.json, it will cause build errors. See how to emulate this step in Angular CLI 1.5 below.

3.在您的AppModule中注册NGSW .这就是它在Angular中的外观 CLI 1.6:

3. Register NGSW in your AppModule. This is how it will look in Angular CLI 1.6:

import { ServiceWorkerModule } from '@angular/service-worker'
import { environment } from '../environments/environment';

...

@NgModule({
  imports: [
    ...
    environment.production ? ServiceWorkerModule.register('/ngsw-worker.js') : []
  ],
  ...
})
export class AppModule { }

4.创建NGSW 配置文件(默认名称为src/ngsw-config.json).这是Angular CLI 1.6生成的默认内容.

4. Create NGSW configuration file (default name is src/ngsw-config.json). Here is the default content will be generated by Angular CLI 1.6.

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

目前,在使用Angular CLI 1.5时,我们还必须模拟步骤2中的构建支持.实际上,除了ng build --prod命令之外,还应该执行2个额外的操作(使用生产构建来使用NGSW!):

At the moment, while using Angular CLI 1.5 we also have to emulate build support from the step 2. Actually, there are 2 extra actions should perform in addition to ng build --prod command (it’s important to use production build in order to use NGSW!):

使用NGSW CLI ngsw-config基于NGSW配置文件src/ngsw-config.json生成NGSW控制(清单)文件ngsw.json.

Generate NGSW control (manifest) file ngsw.json based on NGSW configuration file src/ngsw-config.json using NGSW CLI ngsw-config.

将NGSW 本身从npm_modules软件包文件夹复制到我们的dist文件夹.

Copy NGSW itself from the npm_modules package folder to our dist folder.

要使用一个简单的命令来生成具有NGSW支持的生产版本,请添加一些npm脚本:

To have one simple command to generate production build with NGSW support let’s add some npm scripts:

{
  ...
  "scripts": {
    ...
    "ngsw-config": "node_modules/.bin/ngsw-config dist src/ngsw-config.json",
    "ngsw-copy": "cp node_modules/@angular/service-worker/ngsw-worker.js dist/",
    "build-prod-ngsw": "ng build --prod && npm run ngsw-config && npm run ngsw-copy",
    "serve-prod-ngsw": "npm run build-prod-ngsw && http-server dist -p 8080"
  }
}

现在,如果我们运行npm run build-prod-ngsw,则在dist文件夹中将有Angular PWA. (可选)我们可以通过运行npm run serve-prod-ngsw使用最简单的http-server为其提供服务.

Now if we run npm run build-prod-ngsw we’ll have Angular PWA in the dist folder. Optionally, we could serve it using the simplest http-server by running npm run serve-prod-ngsw.

重要!不要使用ng serve测试您的Angular Service Worker. 该开发服务器并非旨在与以下服务器协同工作 PWA流.始终构建应用的生产版本并提供服务 使用任何静态Web服务器从您的分发文件夹中访问.

Important! Do not use ng serve to test your Angular Service Worker. This development server was not designed to work in collaboration with PWA flow. Always build a production version of the app and serve it from your distributive folder using any static web server.

应用程序外壳

如果执行上述操作并运行npm run build-prod-ngsw-default Angular PWA的默认格式已准备就绪!部署该应用程序或仅使用任何静态Web服务器在本地运行该应用程序(在本例中为http-server包,您运行npm run serve-prod-ngsw进行构建和服务).

If we perform the above actions and run npm run build-prod-ngsw — the Angular PWA in its default form is ready for us! Deploy the application or just run it locally using any static web server (http-server package in my case, you run npm run serve-prod-ngsw to build and serve).

我们脱机后该应用程序将正常运行.为什么?由于NGSW缓存了配置文件"assetGroups"部分中列出的所有资源,现在它负责从缓存存储"中为它们提供服务,缓存存储"现在已充满了记录:

The application will be working after we went offline. Why? Because NGSW cached all the resources listed in theassetGroups section of the configuration file, and now it’s responsible for serving them from the Cache Storage, which is full of records now:

Service Worker已注册并处于活动状态

Service Worker is registered and active

我们可以查看缓存的响应的内容(目前仅在Chrome Canary中可用)

We can view the content of cached response (available only in Chrome Canary at the moment)

NGSW使用缓存存储来存储HTTP响应数据和一些元数据来处理版本控制:

NGSW uses Cache Storage to store both HTTP responses data and some metadata to handle versioning:

NGSW的存储类型

  • 带有后缀:cache的条目-实际的HTTP响应.
  • 带有后缀:meta的条目-用于存储版本控制元信息.以后,这种存储的数据可能会移到indexedDB.
  • Entries with postfix :cache — actual HTTP responses.
  • Entries with postfix :meta — to store the versioning meta information. Later this kind of stored data might be moved to indexedDB.

如果打开DevTools,则高速缓存存储"部分中的条目 每次执行以下操作后,极有可能不会自动更新 服务人员方面.如果您希望查看实际数据,请右键单击 并选择刷新缓存.

If you keep DevTools open, the entries inside Cache Storage section most likely will not be updated automatically after each action from service worker side. If you wish to see the actual data, right-click and choose Refresh Caches.

对. NGSW配置文件的默认格式不足以满足我们的要求,因为我们使用的是Material Icons webfont.显然,这些资源(对应的CSS和WOFF2文件)不是由NGSW缓存的,但是我们可以通过在默认的appassets之外的assetGroups中再添加一个组来轻松地修复它.我们称之为fonts:

Right. The default form of NGSW configuration file is not enough for our case because we use Material Icons webfont. Obviously, these resources (corresponding CSS and WOFF2 files) were not cached by NGSW, but we can easily fix it by adding one more group to assetGroups in addition to default app and assets ones. Let’s call it fonts:

{
  ...
  "assetGroups": [
   ...
   {
    "name": "fonts",
    "resources": {
      "urls": [
        "https://fonts.googleapis.com/**",
        "https://fonts.gstatic.com/**"
      ]
    }
  }]
}

使用globs语法指定这些资源很有意义,因为字体文件的确切URL可能会不时更改以支持Webfont版本控制.另外,您可能会注意到我们未指定installModeupdateMode.一方面,这将在生成的NGSW控制文件中均设置为prefetch,因为这是默认值.另一方面,由于urls列出资源的方式的详细信息,它们将仅在被请求后才被缓存.

It makes sense to specify these resources using globs syntax because the exact URL of the font file could change from time to time to support webfont versioning. Also, you may notice that we have specified neither installMode nor updateMode. On the one hand, both will be set as prefetch in the resulting NGSW control file as this is a default value. On the other hand, they will be cached only after they were requested because the specifics of urls-way to list the resources.

重建,运行并切换到离线模式后,我们将看到应用程序的正常状态,所有图标都在该位置.

After we rebuild, run and switch to offline mode we will see the normal state of the application with all the icons in the place.

在缓存存储中,我们将看到两个新条目:

In the Cache Storage we’ll see two new entries:

NGSW生成的存储空间

Storages generated by NGSW

我们甚至可以预览缓存的字体:

We can even preview the cached font:

assetGroupsdataGroups之间有根本的区别.

There is a fundamental difference between assetGroups and dataGroups.

  • assetGroups正在跟踪应用程序[shell]版本.
  • dataGroups与应用程序版本无关.他们使用缓存 他们自己的缓存策略,这是处理我们的适当部分 API响应.
  • assetGroups are keeping track of the app [shell] version.
  • dataGroups are independent of the app version. They are cached using their own cache policies, and it’s the proper section to handle our API responses.

运行时缓存

要对我的/timeline API端点使用网络优先策略,对/favorites端点使用缓存优先策略. src/ngsw-config.json中的相应设置如下所示:

To use Network-First strategy for my /timeline API endpoint and Cache-First strategy for the /favorites endpoint. The corresponding setup in src/ngsw-config.json will look like:

{
  ...
  "dataGroups": [{
      "name": "api-freshness",
      "urls": [
        "/timeline"
      ],
      "cacheConfig": {
        "strategy": "freshness",
        "maxSize": 100,
        "maxAge": "3d",
        "timeout": "10s"
      }
    },
    {
      "name": "api-performance",
      "urls": [
        "/favorites"
      ],
      "cacheConfig": {
        "strategy": "performance",
        "maxSize": 100,
        "maxAge": "3d"
      }
    }
  ]
}

有一个主开关定义了NGSW的行为:cacheConfig / strategy.对于网络优先策略,它是freshness,对于高速缓存优先-performance.

There is a main switch defining the behavior of NGSW: cacheConfig / strategy. For network-first strategy, it’s freshness, for cache-first — performance.

现在构建,投放,点击加载我的时间轴"和加载我的收藏夹"按钮以获取并缓存API响应,然后切换到离线状态.

Now build, serve, click Load my timeline and Load my favorites buttons to get and cache API responses, and switch to offline.

关于在线模式的优化.返回在线并单击Timeline / Favorites一次或两次.很明显,收藏夹会立即加载,这是因为我们跳过了整个网络行程,并从缓存中获取了数据.要指定要缓存多长时间,请使用cacheConfig部分中的设置-我们在那里具有细粒度控制.

About the optimization for online mode. Return back to online and click Timeline / Favorites once or twice. It’s clearly visible that Favorites are loaded immediately, just because we skip the whole network trip and get the data from the cache. To specify for how long to cache Using settings in cacheConfig section — we have the fine-grain control there.

NGSW进行了一些非常智能的网络优化,对我们有很大帮助,只需要我们提供一些JSON配置即可.

NGSW helped us a lot with some really smart network optimizations, requiring only some JSON configuration from us.

这篇关于通过Angular 6 Service Worker中的新鲜度缓存资产的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆