You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular12使用Service Worker部署生产环境后出现ChunkLoadError问题求助

问题描述

我使用Angular 12,通过Service Worker来部署新版本。
每次我向生产环境部署新版本时都会出现该问题(但不知为何staging环境无此问题),部分用户会收到一系列如下报错:

Uncaught (in promise): ChunkLoadError: Loading chunk XXX failed.

关于这个问题的相关帖子不少,但看起来解决方案需要结合具体场景定制。
我这边生产环境和stg环境的差异只有以下几点:

  • 生产环境调用了enableProdMode();

我的service worker注册配置如下:

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

对应的ngsw配置文件内容如下:

{
  "$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)"]
      }
    }
  ]
}

我的版本更新提示逻辑如下(本质是一个可以被用户忽略的提示横幅):

@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;
  }
}

补充说明:
我的应用中存在大量懒加载模块,我最初怀疑问题原因是部分模块在新版本部署前未被加载,用户部署后访问对应模块时就会出现chunk加载错误。但我通过以下步骤尝试复现该问题:

  • 修改模块A和模块B
  • 部署版本
  • 访问模块A
  • 再次修改模块A和模块B
  • 部署新版本
  • 从旧版本的模块A页面跳转访问旧版本的模块B,不更新应用版本,结果:旧版本的模块B依然可以正常加载

因此我认为懒加载模块未提前加载不是该问题的诱因。
希望能得到相关的解决思路指引,非常感谢。


解决思路

1. 优先检查生产环境静态资源缓存配置

这是生产和staging环境最常见的差异点,重点检查三类文件的缓存规则:

  • ngsw-worker.js、ngsw.json、index.html 这三个文件绝对不能设置强缓存,必须配置为Cache-Control: no-cache或者max-age=0,如果这几个文件被CDN/浏览器强缓存,Service Worker会长期无法检测到版本更新,用户一直使用旧版本应用,旧版本chunk被清理后就会触发加载错误。
  • 带hash的chunk资源建议设置1年以上的强缓存,部署时不要删除旧版本的chunk资源,至少保留24小时以上,给还在使用旧版本的用户预留缓冲时间。

2. 调整Service Worker注册时机

当前你使用的registerWhenStable:30000 是应用稳定后30秒才注册Service Worker,如果用户在这30秒内跳转访问懒加载模块,刚好赶上新版本部署,旧chunk已经被清理,此时请求没有被Service Worker拦截,直接访问服务器就会报错。可以根据业务场景调整注册时机,比如改为应用稳定后立即注册,或者在首屏加载完成后就提前注册。

3. 新增全局ChunkLoadError捕获降级

不管什么原因触发chunk加载失败,都可以在全局错误处理器中统一捕获降级,避免用户直接看到报错:

@Injectable()
export class GlobalErrorHandler extends ErrorHandler {
  handleError(error: any): void {
    if (error?.message?.includes('ChunkLoadError') || error?.originalError?.message?.includes('ChunkLoadError')) {
      // 加标记避免重复刷新死循环
      if (!sessionStorage.getItem('hasReloadedForChunkError')) {
        sessionStorage.setItem('hasReloadedForChunkError', 'true');
        window.location.reload();
        return;
      }
    }
    // 其他错误的处理逻辑
    super.handleError(error);
  }
}

使用时在AppModule的providers中注册即可:

{ provide: ErrorHandler, useClass: GlobalErrorHandler }

4. 优化版本更新提示逻辑

当前的更新提示用户可以手动忽略,对于高优先级的版本更新,可以增加强制更新逻辑,或者把6小时的检查周期缩短到更短的时间,比如1小时,更快感知到版本更新。


内容的提问来源于stack exchange,提问作者Crocsx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 16:36:03