Angular Uncaught(承诺):ChunkLoadError:加载块 XXX 失败

Cro*_*csx 10 javascript deployment service-worker angular

我正在使用 Angular 12,并使用 Service Worker 来部署新版本。

看起来每次我将新版本部署到生产环境时(并且由于某种原因不在暂存阶段)。一些用户收到一堆错误,例如

未捕获(承诺):ChunkLoadError:加载块 XXX 失败。

关于这个问题有很多帖子,但在我看来,解决方案是个案的。

与 stg 相比,我在生产方面的差异只是而已。

我打电话 enableProdMode();

我的服务人员设置如下:

    ServiceWorkerModule.register('ngsw-worker.js', {
      enabled:
        environment.env === Environment.PRODUCTION || environment.env === Environment.STAGING,
      registrationStrategy: 'registerWhenStable:30000',
    }),
Run Code Online (Sandbox Code Playgroud)

我的配置看起来像

{
  "$schema": "../../node_modules/@angular/service-worker/config/schema.json",
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": ["/favicon.ico", "/index.html", "/manifest.webmanifest", "/*.css", "/*.js"]
      }
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "lazy",
      "resources": {
        "files": ["/assets/**", "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"]
      }
    }
  ]
}

Run Code Online (Sandbox Code Playgroud)

这就是我显示更新的方式(基本上是一个可以忽略的横幅):

@Component({
  selector: 'app-live-update-notifier',
  templateUrl: './live-update-notifier.component.html',
  styleUrls: ['./live-update-notifier.component.scss'],
})
export class LiveUpdateNotifierComponent implements OnDestroy {
  hasUpdate = false;
  isIgnored = false;

  private subscription = new SubSink();

  constructor(
    @Inject(DOCUMENT) private document: Document,
    private swUpdate: SwUpdate,
    private appRef: ApplicationRef,
    private changeDetectorRef: ChangeDetectorRef
  ) {
    const appIsStable$ = this.appRef.isStable.pipe(first((isStable) => isStable === true));
    const everySixHours$ = interval(6 * 60 * 60 * 1000);
    const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$);

    if (swUpdate.isEnabled) {
      this.subscription.add(
        everySixHoursOnceAppIsStable$.subscribe(() => swUpdate.checkForUpdate()),
        this.swUpdate.available.subscribe((evt) => {
          if (evt.type === 'UPDATE_AVAILABLE') {
            this.hasUpdate = true;
            this.changeDetectorRef.detectChanges();
          }
        })
      );
    }
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }

  updateApp() {
    this.document.location.reload();
  }

  skipNotification() {
    this.isIgnored = true;
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您有任何可以指导解决方案的线索,谢谢。

编辑 :

我的应用程序中有一堆延迟加载的模块。我认为原因是某些模块在新版本之前没有加载,当用户在部署后导航到它们时,他们会遇到这个块问题。但我尝试通过以下方式模拟这个问题

  • 编辑模块A和B
  • 部署
  • 导航至模块 A
  • 编辑模块A和B
  • 部署
  • 从旧A导航到旧模块B,因此无需更新APP RES的版本:旧B仍然正常加载

所以我不认为这是这个问题

Mah*_*rei 8

这可能是由不同的原因引起的。但由于spock123 ,我几个月前使用了一种解决方法。

我引用他的话:

当然,我们使用 Service Worker 服务swUpdate来在新版本可用时获取通知。然而,当有新的软件版本时,有时似乎并非所有延迟加载的块都会更新。

基本上,解决方法是在遇到bundle not found导致错误的错误时重新加载应用程序ChunkLoadError

您必须全局监听错误,如果应用程序遇到此错误,您只需重新加载页面即可。

设置全局错误处理程序的说明


更新:

我从angular.io引用:

处理不可恢复的状态

在某些情况下,服务工作线程用于为客户端提供服务的应用程序版本可能处于损坏状态,如果不重新加载整页,则无法恢复该状态。

例如,想象以下场景:

  • 用户首次打开应用程序,Service Worker 会缓存该应用程序的最新版本。假设应用程序的缓存资源包括index.htmlmain.<main-hash-1>.jslazy-chunk.<lazy-hash-1>.js
  • 用户关闭应用程序并且暂时没有打开它。
  • 一段时间后,应用程序的新版本将部署到服务器。这个较新的版本包括文件index.htmlmain.<main-hash-2>.jslazy-chunk.<lazy-hash-2>.js(请注意,哈希值现在不同,因为文件的内容发生了变化)。旧版本在服务器上不再可用。
  • 与此同时,用户的浏览器决定lazy-chunk.<lazy-hash-1>.js从缓存中删除。浏览器可能决定从缓存中逐出特定(或全部)资源,以回收磁盘空间。
  • 用户再次打开应用程序。Service Worker 提供此时已知的最新版本,即旧版本 (index.htmlmain.<main-hash-1>.js)。
  • 在稍后的某个时刻,应用程序请求惰性捆绑包lazy-chunk.<lazy-hash-1>.js.
  • 服务工作人员无法在缓存中找到资产(请记住浏览器已将其驱逐)。它也无法从服务器检索它(因为服务器现在只能lazy-chunk.<lazy-hash-2>.js从较新的版本获取)。

在前面的场景中,服务工作线程无法提供通常会被缓存的资产。该特定应用程序版本已损坏,并且无法在不重新加载页面的情况下修复客户端的状态。在这种情况下,Service Worker 通过发送UnrecoverableStateEvent事件来通知客户端。订阅SwUpdate#unrecoverable即可收到通知并处理这些错误。

处理不可恢复状态.service.ts:

@Injectable()
export class HandleUnrecoverableStateService {
  constructor(updates: SwUpdate) {
    updates.unrecoverable.subscribe(event => {
      notifyUser(
        'An error occurred that we cannot recover from:\n' +
        event.reason +
        '\n\nPlease reload the page.'
      );
    });
  }
}
Run Code Online (Sandbox Code Playgroud)