如何让 Angular Universal 和 PWA 协同工作?
How to make Angular Universal and PWA work together?
我有一个 SSR Angular 应用程序,我正试图将其转换为 PWA。我希望它是为 SEO 和它提供的 "fast first rendering" 呈现的服务器端。
PWA 模式在与 SSR 结合时工作正常,但是一旦加载应用程序,当我们刷新它时,将加载客户端索引 HTML 文件而不是服务器端呈现的页面。
我深入研究了 ngsw-worker.js
的代码,我看到了这个:
// Next, check if this is a navigation request for a route. Detect circular
// navigations by checking if the request URL is the same as the index URL.
if (req.url !== this.manifest.index && this.isNavigationRequest(req)) {
// This was a navigation request. Re-enter `handleFetch` with a request for
// the URL.
return this.handleFetch(this.adapter.newRequest(this.manifest.index), context);
}
我无法控制此文件,因为它来自框架并且未向开发人员公开。
有人为此找到了解决方案或解决方法吗?
我找到了一个可行的解决方案,ngsw-config.json
的 navigationUrls
属性 包含包含或排除的导航列表 URL(带有感叹号),例如在 the documentation.
中解释
然后我这样配置:
"navigationUrls": [
"!/**"
]
这样,URL 中的 none 会重定向到 index.html
,并且 server-side 呈现的应用会在首次请求(或刷新)应用时发挥作用, 无论 URL 是什么。
更进一步,service worker管理的三种URL是:
- Non-navigation URLs:由 service worker 缓存并在生成的
ngsw.json
文件中列出的静态文件及其相应的哈希值
- 导航URLs:默认重定向到
index.html
,如果使用"!/**"
配置则转发到服务器
GET
向后端请求:转发给后端
为了区分 GET
XMLHttpRequest
和导航请求,service worker 使用 Request.mode 属性 和 Accept
header 在导航时包含 text/html
,在请求后端时包含 application/json, text/plain, */*
。
编辑:这实际上不是一个好的做法,原因有二:
- 根据网络质量,无法保证 server-side 版本的渲染速度会比缓存的浏览器版本快
- 它打破了“后台更新”机制。事实上,server-side 呈现的应用程序将始终引用 JavaScript 文件的最新版本
有关这方面的更多详细信息,请查看 Angular 的团队成员对我的功能请求的回答:https://github.com/angular/angular/issues/30861
更新 v11.0.0
Angular 现在有一个 navigationRequestStrategy
选项,可以优先考虑服务器的导航请求。更新日志摘录:
service-worker: add the option to prefer network for navigation
requests (#38565) (a206852), closes #38194
要明智地使用!此警告出现在文档中:
The freshness
strategy usually results in more requests sent to the
server, which can increase response latency. It is recommended that
you use the default performance strategy whenever possible.
我有一个 SSR Angular 应用程序,我正试图将其转换为 PWA。我希望它是为 SEO 和它提供的 "fast first rendering" 呈现的服务器端。
PWA 模式在与 SSR 结合时工作正常,但是一旦加载应用程序,当我们刷新它时,将加载客户端索引 HTML 文件而不是服务器端呈现的页面。
我深入研究了 ngsw-worker.js
的代码,我看到了这个:
// Next, check if this is a navigation request for a route. Detect circular
// navigations by checking if the request URL is the same as the index URL.
if (req.url !== this.manifest.index && this.isNavigationRequest(req)) {
// This was a navigation request. Re-enter `handleFetch` with a request for
// the URL.
return this.handleFetch(this.adapter.newRequest(this.manifest.index), context);
}
我无法控制此文件,因为它来自框架并且未向开发人员公开。 有人为此找到了解决方案或解决方法吗?
我找到了一个可行的解决方案,ngsw-config.json
的 navigationUrls
属性 包含包含或排除的导航列表 URL(带有感叹号),例如在 the documentation.
然后我这样配置:
"navigationUrls": [
"!/**"
]
这样,URL 中的 none 会重定向到 index.html
,并且 server-side 呈现的应用会在首次请求(或刷新)应用时发挥作用, 无论 URL 是什么。
更进一步,service worker管理的三种URL是:
- Non-navigation URLs:由 service worker 缓存并在生成的
ngsw.json
文件中列出的静态文件及其相应的哈希值 - 导航URLs:默认重定向到
index.html
,如果使用"!/**"
配置则转发到服务器 GET
向后端请求:转发给后端
为了区分 GET
XMLHttpRequest
和导航请求,service worker 使用 Request.mode 属性 和 Accept
header 在导航时包含 text/html
,在请求后端时包含 application/json, text/plain, */*
。
编辑:这实际上不是一个好的做法,原因有二:
- 根据网络质量,无法保证 server-side 版本的渲染速度会比缓存的浏览器版本快
- 它打破了“后台更新”机制。事实上,server-side 呈现的应用程序将始终引用 JavaScript 文件的最新版本
有关这方面的更多详细信息,请查看 Angular 的团队成员对我的功能请求的回答:https://github.com/angular/angular/issues/30861
更新 v11.0.0
Angular 现在有一个 navigationRequestStrategy
选项,可以优先考虑服务器的导航请求。更新日志摘录:
service-worker: add the option to prefer network for navigation requests (#38565) (a206852), closes #38194
要明智地使用!此警告出现在文档中:
The
freshness
strategy usually results in more requests sent to the server, which can increase response latency. It is recommended that you use the default performance strategy whenever possible.