我正在尝试将Angular Service Worker集成到现有项目中。如果我正确理解的话,有两种情况下如何在Angular SW中缓存数据。可以预取或延迟更新资产数据,并缓存特定的API调用和其他XHR请求。
我要实现的目标是首先通过网络加载特定资产,如果请求超时或无法访问,则将通过缓存对其进行处理。就像在缓存API调用时的freshness
策略一样。
但是似乎没有办法为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-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"]
}
}
]
}
是否可以通过对资产使用freshness
和installMode
来实现类似updateMode
策略的缓存行为?
我尝试将其从资产缓存中排除,并且它是通过网络加载的,但显然在离线后服务人员不会提供它。
此后,我尝试通过dataGroups
再次将其包括进来,并将策略设置为freshness
,但是一旦资产从资产配置中排除后,该资产似乎就不会再次被缓存。另外,我不认为dataGroups
设置可用于此文件。
"dataGroups": [
{
"name": "config",
"urls": ["assets/excluded_asset.js"],
"cacheConfig": {
"maxSize": 10,
"maxAge": "1d",
"timeout": "100",
"strategy": "freshness"
}
}
}
我错过了什么吗,还是没有办法通过freshness
策略来缓存资产?最好不要移动文件或更改请求文件的方式。
编辑
我试图将其移到缓存的资产目录之外,并将其包含在dataGroups
设置中,但也无法正常工作。
答案 0 :(得分:3)
与服务人员合作的新应用
命令如下:
ng new myApp --service-worker (or using the alias — -sw )
具有此服务工作者标志的Angular CLI 1.6将为我们做一些自动化:
无论如何,即使在发布CLI 1.6之后,也要知道如何重现这些步骤,因为我们必须手动执行这些步骤才能将NGSW支持添加到现有应用中。让我们将Angular Service Worker添加到PWAtter中。
将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 CLI ngsw-config基于NGSW配置文件src / ngsw-config.json生成NGSW 控制(清单)文件ngsw.json。
将NGSW 本身从npm_modules软件包文件夹复制到我们的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
文件夹中有Angular PWA。 (可选)我们可以通过运行http-server
使用最简单的npm run serve-prod-ngsw
为它提供服务。
重要!不要使用
ng serve
测试您的Angular Service Worker。 该开发服务器并非旨在与以下服务器协同工作 PWA流。始终构建应用的生产版本并提供服务 使用任何静态Web服务器从分发文件夹中访问。
应用程序外壳
如果我们执行上述操作并运行npm run build-prod-ngsw
- Angular PWA的默认格式已经可以使用!部署应用程序或仅使用任何静态Web服务器在本地运行它(在我的情况下,http-server
软件包,您运行npm run serve-prod-ngsw
进行构建和提供服务)。
我们脱机后该应用程序将正常运行。为什么?由于NGSW缓存了配置文件“ assetGroups”部分中列出的所有资源,现在它负责从“缓存存储”中为它们提供服务,“缓存存储”现在已充满了记录:
Service Worker已注册并处于活动状态
我们可以查看缓存的响应的内容(目前仅在Chrome Canary中可用)
NGSW使用缓存存储来存储HTTP响应数据和一些元数据来处理版本控制:
NGSW的存储类型
:cache
的条目-实际的HTTP响应。:meta
的条目-用来存储版本控制元信息。以后,这种存储的数据可能会移动到indexedDB
。如果打开DevTools,则“缓存存储”部分中的条目 每次执行以下操作后,极有可能不会自动更新 服务人员方面。如果您想查看实际数据,请右键单击 并选择刷新缓存。
对。 NGSW配置文件的默认格式不足以满足我们的要求,因为我们使用的是Material Icons webfont。显然,这些资源(对应的CSS和WOFF2文件)不是由NGSW缓存的,但是我们可以通过在默认的assetGroups
和app
之外的assets
上再添加一个组来轻松地对其进行修复。 。我们称之为fonts
:
{
...
"assetGroups": [
...
{
"name": "fonts",
"resources": {
"urls": [
"https://fonts.googleapis.com/**",
"https://fonts.gstatic.com/**"
]
}
}]
}
使用globs语法指定这些资源很有意义,因为字体文件的确切URL可能会不时更改以支持Webfont版本控制。另外,您可能会注意到我们未指定installMode
或updateMode
。一方面,两者都将在生成的NGSW控制文件中设置为prefetch
,因为这是默认值。另一方面,它们仅在被请求后才被缓存,因为urls
的方式列出了资源。
重建,运行并切换到离线模式后,我们将看到应用程序的正常状态,所有图标都在该位置。
在缓存存储中,我们将看到两个新条目:
NGSW生成的存储空间
我们甚至可以预览缓存的字体:
assetGroups
和dataGroups
之间有根本的区别。
assetGroups
正在跟踪应用程序[shell]版本。dataGroups
与应用程序版本无关。他们使用缓存
他们自己的缓存政策,这是处理我们的适当部分
API响应。运行时缓存
要对我的/timeline
API端点使用网络优先策略,对/favorites
端点使用缓存优先策略。 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
。对于网络优先策略,它是freshness
,对于高速缓存优先— performance
。
现在构建,投放,单击“加载我的时间轴”和“加载我的收藏夹”按钮以获取并缓存API响应,然后切换到离线状态。
关于在线模式的优化。返回在线并单击Timeline / Favorites
一次或两次。很明显,收藏夹会立即加载,这是因为我们跳过了整个网络行程,并从缓存中获取了数据。要指定要缓存多长时间,请使用cacheConfig
部分中的设置-我们在那里具有细粒度控制。
NGSW进行了一些非常智能的网络优化,对我们有很大帮助,只需要我们提供一些JSON配置即可。
答案 1 :(得分:1)
我遇到了同样的问题。我发现始终拥有最新的js和css文件的解决方案只是将index.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文件中(服务工作者将忽略该脚本文件),一旦将更改推送到生产环境,index.html将指向新的js和css文件。
当然,这很明显是很糟糕的:您的index.html不会被服务工作者缓存,但是至少它可以使回头客直接获取最新鲜的文件。
我真的希望有一种对资产也有“新鲜”选项的方法...