当前位置: 首页 > 知识库问答 >
问题:

通过Angular 6 Service Worker中的新鲜度缓存资产

徐高懿
2023-03-14

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

我试图实现的是首先通过网络加载特定的资产,如果请求超时或无法访问,它将通过缓存提供服务。就像缓存API调用时的新鲜策略一样。但似乎没有可能为在Angular项目中作为资产加载的JS文件配置这种新鲜加载机制。我设置了一个示例项目进行测试:https://github.com/philipp-schaerer-lambdait/angular-service-worker-test

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

\_ 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配置。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"]
            }
        }
    ]
}

是否可以通过对资产使用installMode和updateMode来实现像freshness策略这样的缓存行为?

我尝试将其从资产缓存中排除,并通过网络加载,但显然在脱机后服务人员不会提供。

之后,我尝试通过数据组再次将其包括在内,并将策略设置为新鲜度,但似乎一旦资产从资产配置中排除,它就不会再次被缓存。此外,我认为数据组设置不能用于此文件。

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

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

编辑

我试图将其移动到缓存资产目录之外,并将其包含在数据组设置中,但也没有成功。

共有2个答案

宗冷勋
2023-03-14
匿名用户

我也有同样的问题。我发现总是有最新的js和css文件的解决方案只是排除索引。来自缓存资产的html。

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

确保将“outputHashing”:“all”,添加到角度构建配置中。这样,当您对代码进行更改时,它将生成一个具有不同名称的文件。然后,它会自动将脚本标记(或链接标记)添加到html文件中(服务人员将忽略该文件),并在您将更改推送到生产时,立即添加索引。html将指向您的新js和css文件。

当然,这很糟糕:你的指数。html不会被服务人员缓存,但至少它允许返回的用户直接拥有最新的文件。

我真的希望有一种方法可以为资产提供“新鲜度”选项...

胡星汉
2023-03-14

带有Service Worker的新应用程序

该命令将如下所示:

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

使用此service worker标志,Angular CLI 1.6将为我们实现一些自动化:

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

无论如何,即使在CLI 1.6发布之后,知道如何再现这些步骤也很好,因为我们必须手动执行这些步骤才能将NGSW支持添加到现有应用程序中。让我们将角度服务人员添加到pWater。

将Angular Service Worker添加到现有应用程序

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

1、安装NGSW

npm install @angular/service-worker --save

2、启用构建支持(仅适用于Angular CLI 1.6,请参见下面的注意事项)

ng set apps.0.serviceWorker=true

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

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

3.在您的AppModule中注册NGSW。这是它在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生成。

{
  "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,使用生产构建很重要!):

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

将NGSW本身从npm\U模块包文件夹复制到我们的dist文件夹。

要使用一个简单的命令生成具有NGSW支持的生产构建,让我们添加一些npm脚本:

{
  ...
  "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文件夹中获得角度PWA。或者,我们可以通过运行npm run serve prod ngsw,使用最简单的http服务器为其提供服务。

重要!不要使用ng service来测试您的Angular Service Worker。此开发服务器并非旨在与PWA流协作工作。始终构建应用程序的生产版本,并使用任何静态Web服务器从您的分发文件夹中提供它。

应用程序外壳

如果我们执行上述操作并运行npm run build prod ngsw — 默认形式的角度PWA已经为我们准备好了!部署应用程序或使用任何静态web服务器在本地运行它(在我的情况下,您可以运行npm run serve prod ngsw来构建和服务)。

我们脱机后,应用程序将正常工作。为什么?因为NGSW缓存了配置文件assetgroups部分中列出的所有资源,现在它负责从缓存存储中为它们提供服务,而缓存存储中现在充满了记录:

服务工作者已注册并处于活动状态

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

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

NGSW存储类型

  • 带有后缀的条目:缓存 — 实际HTTP响应
  • 带有后缀的条目:meta — 存储版本控制元信息。稍后,这种存储的数据可能会移动到indexedDB

如果您使DevTools保持打开状态,那么在服务工作者端的每个操作之后,缓存存储部分中的条目很可能不会自动更新。如果希望查看实际数据,请右键单击并选择“刷新缓存”。

对。NGSW配置文件的默认形式对于我们的案例来说是不够的,因为我们使用的是材质图标网络字体。显然,这些资源(对应的CSS和WOFF2文件)没有被NGSW缓存,但我们可以通过在assetGroup中添加一个组来轻松修复它除了默认的app资产的。让我们称之为fonts

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

使用globs语法指定这些资源是有意义的,因为字体文件的确切URL可能会不时更改以支持webfont版本控制。此外,您可能会注意到,我们既没有指定installMode,也没有指定updateMode。一方面,在生成的NGSW控制文件中,两者都将设置为预取,因为这是默认值。另一方面,它们只有在被请求后才会被缓存,因为URL的细节是列出资源的方式。

重建、运行并切换到脱机模式后,我们将看到应用程序的正常状态以及所有图标。

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

NGSW生成的存储

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

assetGroupdataGroup之间存在根本区别。

  • 资产组正在跟踪应用程序[外壳]版本
  • 数据组独立于应用程序版本。它们使用自己的缓存策略进行缓存,这是处理API响应的适当部分

运行时缓存

对我的时间线APIendpoint使用网络优先策略,对收藏夹endpoint使用缓存优先策略。src/ngsw config中的相应设置。json将如下所示:

{
  ...
  "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。对于网络优先策略,它是新鲜度,对于缓存优先 — <代码>性能

现在,构建、服务、单击加载我的时间线和加载我的收藏夹按钮以获取和缓存API响应,并切换到脱机。

关于在线模式的优化。返回联机并单击一次或两次时间线/收藏夹。很明显,收藏夹会立即加载,因为我们跳过了整个网络旅行,从缓存中获取数据。使用“缓存配置”(cacheConfig)部分中的设置指定缓存的时间 — 我们在那里有细粒度的控制。

NGSW在一些真正智能的网络优化方面帮助了我们很多,只需要我们提供一些JSON配置。

 类似资料:
  • 嗨,我正在使用https://tools.pingdom.com来测试我的wordpress网站速度,我有一个杠杆浏览器缓存的F,它说: 以下可缓存资源的新鲜度寿命很短。为以下资源指定至少一周的到期日: https://ssl.google-analytics.com/ga.js https://fonts.googleapis.com/css?family=Droid桑 https://font

  • 我有一个基于service worker的离线应用程序,允许用户离线下载pdf文件。 有一个文本文件,其中包含pdf文件的下载路径和特定格式的文件标题(以及css、js和图像路径),应用程序通过ajax读取此文本文件并绘制所有可用pdf文件的列表(通过显示标题和下载链接) 在安装过程中,工作人员读取相同的文件,并将所有pdf文件与文本文件一起放入缓存中,以便这些文件可以离线访问。 当我用一些新的p

  • 问题内容: 我的任务是利用SpringCache作为我们的一项服务,以减少数据库查找的次数。在测试实现时,我注意到一些可缓存操作通过日志语句多次调用。调查显示,如果在可缓存的方法中调用了可缓存的操作,则嵌套操作根本不会被缓存。因此,嵌套操作的后续调用将导致进一步的查找。 下面列出了描述问题的简单单元测试: 这两种方法的实际工作对于测试用例本身并不重要,因为仅应测试缓存。 我以某种方式理解了为什么不

  • 问题内容: 我们希望在生产部署中缓存崩溃,但不要浪费大量时间来弄清楚这样做的系统。我的想法是将具有当前版本号的paras应用于css和js文件的末尾: 两个问题:这会有效地打破缓存吗?由于参数表明这是动态内容,因此该参数会导致浏览器从不缓存该URL的响应吗? 问题答案: 参数表示查询字符串,因此浏览器将认为这是从到的新路径。因此导致它从文件而不是从缓存加载。如你所愿。 而且,浏览器将假定下次调用时

  • 问题内容: 我们希望在生产部署中缓存崩溃,但不要浪费大量时间来弄清楚这样做的系统。我的想法是将具有当前版本号的paras应用于css和js文件的末尾: 两个问题:这会有效地打破缓存吗?由于参数表明这是动态内容,因此该参数会导致浏览器从不缓存该URL的响应吗? 问题答案: 参数表示查询字符串,因此浏览器将认为这是从到的新路径。因此导致它从文件而不是从缓存加载。如你所愿。 而且,浏览器将假定下次调用时

  • 我有一个spring/hibernate项目,我试图通过ehcache和terracotta将二级缓存添加到hibernate。一切似乎都很好,我甚至可以在terracota控制台中看到我试图缓存的实体的条目。但根据数据库的统计数据和日志,根本没有缓存任何内容! 负载命中率是0%,负载统计也是0。我做错了什么? 这是我所做的,我通过maven添加了所需的罐子。 更改了我的Hibernate属性以启