Angular服务工作者处于SAFE_MODE模式下。

34

我有一个Angular PWA。在我从Angular 5.0升级到7.2之前,它的服务工作程序完美运行。

升级后,在/ngsw/state中出现以下错误

Driver state: SAFE_MODE (Initialization failed due to error: Invariant violated (initialize): latest hash null has no known
manifest initialize/<@https://{{domain}}.com/ngsw-worker.js:2227:27
fulfilled@https://{{domain}}.com/ngsw-worker.js:1772:52 ) Latest
manifest hash: none Last update check: never

应用程序背景

  • Angular 版本为 7.2.0
  • Service worker 版本为 7.2.0
  • 我正在使用 SwUpdate 服务手动检查更新。

检查更新的代码

if (this.updates.isEnabled) {
      const appIsStable$ = this.appRef.isStable.pipe(first(isStable => isStable === true));
      const every21600Ms$ = interval(6 * 60 * 60);
      const every21600MsOnceAppIsStable$ = concat(appIsStable$, every21600Ms$);
      // poll the service worker to check for updates
      every21600MsOnceAppIsStable$.subscribe(() =>
        this.updates.checkForUpdate()
      );
    }

我的研究和故障排除步骤:

在 Chrome 中

  • 服务工作者已经注册,没有任何错误
  • 我查看了网络选项卡,并发现服务工作者从未下载“ngsw.json”。当应用程序在 Angular 5.0 时,我曾看到过“ngsw.json”被下载。

Screenshot1

  • 我发现同样的问题已经在这里报告。但我没有看到任何适当的解决方案。
  • 我尝试选择“重新加载时更新”,这暂时解决了问题。但是当我取消选择时,相同的错误再次出现。

Screenshot2

在 Microsoft Edge 中

  • 令人惊讶的是,在升级后,一切都在 Edge 中正常工作。

我的想法和期望

  • 由于应用程序在 MS Edge 中运行良好,我怀疑服务工作者配置或我轮询更新的方式存在问题。
  • 我的期望是在/ngsw/state中看到驱动器状态为正常。


3
如能提供帮助,关于此问题在 angular/angular 上有一个公开的问题。 - marcXandre
谢谢您的回复!我之前看过这个链接。问题仍然没有解决 :( - shobhit vaish
1个回答

2

更新

从Angular版本8.2.14开始,这个问题将被修复。以下解决方法仅适用于旧版本。

 


 

旧版解决方法 < 8.2.14

似乎这是Angular服务工作者中一个众所周知的错误,我们可能会在某个时候期望有一个补丁/可用版本。大部分信息可以在 issue 25611 中找到,正如shobhit vaish已经说明的那样。

然而,如果你现在正在寻找一个解决方案,或者你将长时间使用旧版的Angular 7/8,可能不会很快得到修补,我将尝试总结目前已知的解决方法。(它们也许不符合“正确的解决方案”...)

修补ngsw-worker.js

你可以在ng run app:build:production之后修补你的ngsw-worker.js文件,在项目中它通常位于www文件夹中(如果你没有改变Angular的outputPath)。或者你可以在node_modules/@angular/service-worker中的构建之前修补它。

根据你构建应用程序的频率,你可以简单地手动完成(即使用你选择的文本编辑器),或者你可以编写一个脚本,例如借助sed的帮助。

现在你有两个选项:

1. 修补handleMessage()

搜索:

        handleMessage(msg, from) {
            return __awaiter$5(this, void 0, void 0, function* () {

And replace it with

        handleMessage(msg, from) {
            return __awaiter$5(this, void 0, void 0, function* () {
                if (this.initialized === null) {
                    this.initialized = this.initialize();
                }
                try {
                    yield this.initialized;
                }
                catch (e) {
                    this.state = DriverReadyState.SAFE_MODE;
                    this.stateMessage = `Initialization failed due to handleMessage() error: ${errorToString(e)}`;
                }

根据您的@angular/service-worker版本,handleMessage()的签名可能会有所不同,您可以编写更复杂的catch,但希望/可能它永远不会到达catch块。这个补丁基本上是gkalpak的评论中建议的内容,很可能官方修复程序也将类似于此。

2. 对initialize()进行修补

搜索

                try {
                    // Read them from the DB simultaneously.
                    [manifests, assignments, latest] = yield Promise.all([
                        table.read('manifests'),
                        table.read('assignments'),
                        table.read('latest'),
                    ]);

And replace it with

                try {
                    // Read them from the DB simultaneously.
                    [manifests, assignments, latest] = yield Promise.all([
                        table.read('manifests'),
                        table.read('assignments'),
                        table.read('latest'),
                    ]);
                    if (latest.latest === null) throw new Error('Error latest.latest is null for what ever reason...');

通过这种方法,您将确保initialize()catch块实际运行,并防止服务工作者进入SAFE_MODE。然而,这可能不像第一个补丁那么可靠,但对于已经出现SAFE_MODE问题的服务工作者也可能有效。这个想法是由hsta在评论中提出的

解决Angular应用程序中的问题

如果您不想深入了解ngsw-worker.js,可以尝试通过从Angular应用程序内部检索your-app.domain/ngsw/state来检测服务工作者的状态,如果它处于SAFE_MODE(例如可以使用简单的regex搜索进行检查),则可以尝试通过删除缓存存储中的所有项目然后注销服务工作者来重置它。这个想法是由mattlewis92在评论中提出的,并在gkalpak的评论中被批准为可能有效的hack

手动暂时解决问题

正如shobhit vaish已经发现的那样,您还可以手动解决此问题。除了原帖中已经提到的可能性外,您还可以在基于Chrome的浏览器的开发工具中选择"应用程序" -> "清除存储",选择"注销服务工作者"并点击"清除站点数据"。显然,这个问题可能会在未来的更新中再次出现,并且对于普通用户不会有太大帮助。但是,如果您作为开发人员只想快速解决它,那么这可能很方便。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接