Angular +Workbox = build ChunkLoadError: Loading chunk # and Refused to execute script because its MIME

Angular +Workbox = build ChunkLoadError: Loading chunk # and Refused to execute script because its MIME

我在第一次生产部署中将 Workbox 添加到 Angular 一切正常,但是在更新模块并重建 angular 并注入 Workbox 然后访问站点后,我看到服务工作者更新了新版本并刷新页面,但现在尝试使用更新的模块时出现错误

Refused to execute script from 'https://example.com/8-es2015.203674bf0547eff7ff27.js'
because its MIME type ('text/html') is not executable,

并且启用了严格的 MIME 类型检查。

main-es2015.45ba4a512f87eefb1b3a.js:1 ERROR Error: Uncaught (in promise): ChunkLoadError:   
Loading chunk 8 failed.(error: https://example.com/8-es2015.203674bf0547eff7ff27.js)
ChunkLoadError: Loading chunk 8 failed......

我查看了 chrome 中的网络,发现文件 8-es2015.203674bf0547eff7ff27.js 正在从(磁盘缓存)提供服务与 (ServiceWorker) 提供的其他文件不同,它的内容是 index.html 文件我不知道它来自哪里,它甚至不是新构建的一部分? chrome 将其放在脚本下的顶部框架部分

这个错误的原因是什么,在 angular.json 我有 "outputHashing": "all",我删除了所有内容并重建但仍然存在此错误,直到我清除浏览器现金删除 ServiceWorker 并硬刷新错误停止发生,直到我重新加载页面并且它 returns。我是否需要在每次更新后删除所有缓存,我认为 Workbox 会这样做 automatically.Do 我在 sw.js

中添加了类似的内容
self.addEventListener('activate', event => event.waitUntil(
   caches.keys().then(cacheNames => cacheNames.forEach(name => caches.delete(name)))
  )
);

我正在使用 express,所以我将 sw.js 上的 maxAge 设置为 0,甚至将 public 到静态文件的路由更改为深层路由,但什么都没有

app.use('/sw.js', express.static(path.resolve('./public/dist/static/sw.js'), {maxAge: 0}));
app.use('/', express.static(path.resolve('./public/dist/static/'), {maxAge: 86400000}));

工具:angular 8.2.4 - 工作箱 4.3.1

更新 删除了工作箱并且该应用程序运行正常,我猜测其原因是他们的新包 workbox-window 或我尝试使用它的方式。我将它放在从 app.module 加载的模块服务中,然后从 AppComponent ngOnInit 调用该服务。这可能是错误的初始化方式。

代码设置:

import {Workbox} from 'workbox-window';
@Injectable()
export class WorkerService {
  supportWorker: boolean;
  supportPush: boolean;    
  constructor(@Inject(WINDOW) private window: any, private loggerService: LoggerService) {
    this.supportWorker = ('serviceWorker' in navigator);
    this.supportPush = (this.supportWorker && 'PushManager' in window);
  }

  initWorker() {
    if (this.supportWorker && environment.production) {
      const wb = new Workbox('sw.js');
      if (wb) {
        wb.addEventListener('installed', event => {
          if (event.isUpdate) {
            // output a toast translated message to users
            this.loggerService.info('App.webWorkerUpdate', 10000);
            setTimeout(() => this.window.location.reload(), 10000);
          }
        });
        wb.addEventListener('activated', event => {
          if (!event.isUpdate) {
            this.loggerService.success('App.webWorkerInit', 10000);
          }
        });
        wb.register();
      }
    }
  }
}

这是应用程序组件,我认为最好在 bootstrapModule.then() 之后将其添加到 main.ts,但我不知道如何在此方法中注入服务

 @Component({
      selector: 'app-root',
      template: '<route-handler></route-handler>'
    })
    export class AppComponent implements OnInit {
      constructor(private ws: WorkerService) {
      }

      ngOnInit(): void {
        this.ws.initWorker();
      }
    }

在以不同的方式设置 Workbox 后,问题甚至影响 chrome,在测试时每次构建后未能清除所有缓存,不得不使用隐身模式以确保一切正常。

这里是解决方案,感谢 Ralph Schaer 一篇必读的文章。他的方法不是缓存-Bust angular 构建生成的块,他还将应用程序使用的工作箱的所有生产脚本放入构建文件夹中,最后在 index.html 他调用工作箱- window 注册 service-worker。