Angular ';意外标记<';在每个新的角度生产PWA构建上,直到站点刷新

Angular ';意外标记<';在每个新的角度生产PWA构建上,直到站点刷新,angular,typescript,azure,azure-web-app-service,progressive-web-apps,Angular,Typescript,Azure,Azure Web App Service,Progressive Web Apps,我知道有一些类似的问题,但它实际上并没有回答我的问题 基本上,我有一个angular应用程序,它是一个PWA,现在每次我第一次访问网站时,我都会遇到这样的错误 然后只要我刷新页面,网站就会正常工作 这在任何浏览器/设备上都会发生 现在我怀疑,每次更新应用程序时,主捆绑js文件都会发生变化,PWA缓存了旧文件,而应用程序仍在尝试使用新文件 我的项目结构如下 我有一个根模块延迟加载其他模块,现在加载的第一个模块是我的帐户模块,用户可以登录 这是我的根路由.module.ts import { Ng

我知道有一些类似的问题,但它实际上并没有回答我的问题

基本上,我有一个angular应用程序,它是一个PWA,现在每次我第一次访问网站时,我都会遇到这样的错误

然后只要我刷新页面,网站就会正常工作

这在任何浏览器/设备上都会发生

现在我怀疑,每次更新应用程序时,主捆绑js文件都会发生变化,PWA缓存了旧文件,而应用程序仍在尝试使用新文件

我的项目结构如下

我有一个根模块延迟加载其他模块,现在加载的第一个模块是我的帐户模块,用户可以登录

这是我的根路由.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';

const routes: Routes = [
    { path: '', redirectTo: '/account/login', pathMatch: 'full' },
    {
        path: 'account',
        loadChildren: 'account/account.module#AccountModule',
        data: { preload: true }
    }
];

@NgModule({
    imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })],
    exports: [RouterModule],
    providers: []
})
export class RootRoutingModule {
@import { SwUpdate } from '@angular/service-worker'
...

export class...

constructor(
    private _sw: SwUpdate
) {
    if (this._sw.isEnabled) {
        this._sw.available
            .subscribe(() => {
                this._sw.activateUpdate()
                    .then(() => {
                        window.location.reload(true);
                    });
            });
    }
}     
                    .then(() => {
                        window.location.reload(true);
                    });

}

因此,从技术上讲,用户访问的第一个模块是account模块,但显然它必须从根模块重定向

所以我做的是在我的根组件模块中检查服务人员是否需要像这样更新

root.component.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';

const routes: Routes = [
    { path: '', redirectTo: '/account/login', pathMatch: 'full' },
    {
        path: 'account',
        loadChildren: 'account/account.module#AccountModule',
        data: { preload: true }
    }
];

@NgModule({
    imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })],
    exports: [RouterModule],
    providers: []
})
export class RootRoutingModule {
@import { SwUpdate } from '@angular/service-worker'
...

export class...

constructor(
    private _sw: SwUpdate
) {
    if (this._sw.isEnabled) {
        this._sw.available
            .subscribe(() => {
                this._sw.activateUpdate()
                    .then(() => {
                        window.location.reload(true);
                    });
            });
    }
}     
                    .then(() => {
                        window.location.reload(true);
                    });

现在应该检查是否有更新,然后刷新页面。。但它不起作用。

这是我的ngsw config.json

{
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "App",
      "installMode": "prefetch",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.html",
          "/*.css",
          "/*.js",
          "!/main*.js"
        ]
      }
    }, {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": [
          "/assets/**",
          "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
        ]
      }
    }
  ]
}
正如您所看到的,我排除了
main.js
chunk文件,它应该可以消除这个问题但它没有

现在,当我在新构建之后检查网络选项卡时,这就是我得到的结果

这张图片是在我排除main.js文件之前出现的

这就是我从
ngsw.config

然后我想用我的哨兵错误处理程序来捕捉这个错误,就像这样

export class RavenErrorHandler implements ErrorHandler {
  handleError(err: any): void {
    console.log('error', err);
    if (err.toLowerCase().includes('token <')) {
        window.location.reload(true);
    } else {
        Raven.captureException(err);
    }
  }
}
导出类RavenErrorHandler实现ErrorHandler{
handleError(错误:任意):无效{
console.log('error',err);

if(err.toLowerCase())包括('token当请求的资源返回404,而不是请求的JS文件时,我通常会遇到这种情况,你会收到带有标记的index.html,因此,'请仔细检查你的缓存头。Chrome并不总是侦听无缓存。如果你最近访问过该站点,Chrome将从缓存加载index.html。导致错误

我们已经将index.html改为no store,这似乎解决了这个问题。

我不是角度问题专家。我能做的最好的事情就是帮你解决问题,帮你调试

  • 如果您只是想消除错误(并且您可以控制为您的
    index.html
    提供服务的服务器),我很确定可以通过设置以下http响应头()来解决此问题:
  • 然而,这样的设置或多或少在一开始就超越了PWA的观点。PWA允许用户在离线状态下使用您的站点,他们必须能够首先访问
    index.html
    ,因此必须缓存
    index.html

  • 缓存
    index.html
    是正确的做法。您的旧
    .js
    和其他资产的缓存控制设置可能存在一些问题。我不确定哪部分出错,但预期的行为是:这些资产应该像
    index.html
    一样缓存,404从bro开始就不应该发生wser应该从本地缓存中读取


  • 要快速“掩盖”问题,您可以做的一件事就是将以前版本的所有旧资产也保留在服务器上。这样,缓存
    index.html
    ref到旧资产,它们仍然可以访问,没有404,因此没有“意外令牌”我在延迟加载模块时遇到了这个错误

    这是一个角度/标志性的PWA,与缺失的导入相关:

    import { SharedModule } from '@shared/shared.module';
    
    另见:


    该问题是由安装的
    ServiceWorker
    引起的,它干扰并缓存所有响应,包括您刚刚更新的响应

    关于服务工作者的更多信息:MDN-使用服务工作者

    这就是为什么
    window.location.reload()
    不起作用的原因,因为它确实发出了一个新的请求,但是这个请求被安装的
    ServiceWorker劫持了,而不是让真正的请求进入真正的服务器并获取真正的响应(更新了main.js和assets),它只会将缓存响应返回到应用程序,这是旧的main.js,而不是更新的main.js,这就是它失败的原因

    更具体地说,
    ServiceWorker
    正在缓存
    main.js
    和其他资产,这些资产是在您每次更改code.main.js时生成的。加载后,它会延迟加载(向)应用程序的其他块(例如5.xxxxx.js)


    当您对代码进行更改时,即使您的所有块都得到更新,包括
    main.js
    5.xxxxxx.js
    块,浏览器仍在运行较旧的
    main.js
    。此较旧的
    main.js
    引用了不再存在的较旧的
    5.xxxxxx.js
    。在本po如果执行重新加载()操作,则为int在编程方面,已安装的
    ServiceWorker
    响应较旧的缓存
    main.js
    ,该缓存试图从不存在的服务器延迟加载较旧版本的
    5.xxxxx.js
    ,因此得到404 html错误的响应。因此
    我有一个解决方案

    获取应用程序
    angular.json
    文件,并将输出权限值全部更改为媒体

               "architect": {
                    "build": {
                        ...
                        "configurations": {
                            "production": {
                                ...
                                "outputHashing": "media", // "all"
                            }
                        }
                    }
                }
    

    添加此
    是否足以解决此问题?不幸的是,此操作不起作用,仍然会出现相同的错误。您是否使用了除“/”之外的base href?我隐约记得在github页面上托管并使用base href作为