Angular服务人员处于SAFE_MODE

时间:2019-01-31 07:38:08

标签: angular angular7 angular-service-worker

我有一个Angular PWA。直到我从Angular 5.0升级到7.2之前,它的服务人员都可以正常工作

升级后,我在/ ngsw / state中看到以下错误

  

驱动程序状态:SAFE_MODE(由于错误而初始化失败:违反不变式(初始化):最新的哈希空值未知)   清单initialize / <@https:// {{domain}} .com / ngsw-worker.js:2227:27   履行@https:// {{domain}} .com / ngsw-worker.js:1772:52)最新   清单杂凑:无最后更新检查:永不

应用背景

  • 角版本为7.2.0
  • 服务工作者版本为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

  • 我发现有相同的问题here。我在这里看不到任何适当的解决方案。
  • 我尝试选择“重新加载时更新”,这可以暂时解决此问题。取消选择后再次出现相同的错误。

Screenshot2

在Microsoft Edge中

  • 令人惊讶的是,升级后一切正常。

我的想法和期望

  • 由于该应用程序在MS Edge上运行正常,因此我怀疑Service Worker配置或我轮询更新的方式是否有问题
  • 我希望在/ ngsw / state中看到“驱动器状态”为“正常”

1 个答案:

答案 0 :(得分:1)

更新

此问题将从Angular 8.2.14版本开始修复。仅较旧版本才需要以下解决方法。


<8.2.14

的旧解决方法

这似乎是Angular服务工作者中的一个众所周知的错误,并且我们可能会在某个时候希望有补丁/工作版本。如issue 25611所述,可以在shobhit vaish中找到大多数信息。

但是,如果您现在正在寻找解决方案,或者您将坚持使用较旧的Angular 7/8版本,而该版本可能不会很快得到修补,那么我将尝试总结当前已知的解决方法。 (而且,它们可能不符合“适当的解决方案”的条件。)

修补ngsw-worker.js

您可以在ngsw-worker.js之后修补ng run app:build:production文件,该文件通常位于项目内的www文件夹中(如果您未更改Angular {{1} }。或者,您可以在outputPath内进行构建之前对其进行修补。

取决于您构建应用的频率,您可以简单地手动进行操作(即使用您选择的文本编辑器),也可以例如借助sed编写脚本。

现在您有两个选择:

1。修补node_modules/@angular/service-worker

搜索

handleMessage()

并替换为

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

根据您的 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(),但希望/可能永远不会达到{{1} }仍然阻止。
此修补程序基本上是a comment by gkalpak中建议的修补程序,官方修补程序很可能也是这样的。

2。修补catch

搜索

catch

并替换为

initialize()

这样,您将确保 try { // Read them from the DB simultaneously. [manifests, assignments, latest] = yield Promise.all([ table.read('manifests'), table.read('assignments'), table.read('latest'), ]); 的{​​{1}}块将实际运行,并防止服务工作者输入 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...'); 。但是,由于此问题,它可能不如第一个补丁那么可靠,但对于已经在catch中的服务工作者也可以使用。它是在a comment by hsta中提出的。

在Angular应用中解决问题

如果您不想弄乱initialize(),可以尝试通过从Angular应用程序中获取SAFE_MODE以及它是否位于{{1 }}(例如,可以通过简单的SAFE_MODE搜索来检查),您可以尝试通过从缓存存储中删除所有项目然后取消注册服务工作者来重置它。这个想法是在a comment by mattlewis92中提出的,并在a comment by gkalpak中被认为是可行的hack。

临时手动解决问题

正如已经发现shobhit vaish一样,您也可以手动解决此问题。除了原始帖子中已经说明的可能性之外,您还可以在基于Chrome的浏览器的开发工具中的“应用程序”->“清除存储”下,选择“取消注册服务人员”,然后单击“清除站点数据”。显然,该问题可以并且很可能会在将来的更新中重新出现,并且对普通用户没有太大帮助。但是,如果您作为开发人员现在只想快速解决它,这可能会很方便。