gpt4 book ai didi

angular - 每个新的 Angular 生产PWA版本上的“意外 token <”,直到站点刷新

转载 作者:太空狗 更新时间:2023-10-29 17:06:29 25 4
gpt4 key购买 nike

我知道有一些类似的问题,比如sounexpected token after angular 2 production build但它并没有真正回答我的问题。
基本上我有一个角度应用程序和它的一个pwa,现在每当我做一个新的生产建设,我第一次访问网站时,我得到一个这样的错误
enter image description here
然后我一刷新页面,网站就会正常工作。
在任何浏览器/设备上都会发生这种情况
现在我的怀疑是,每次更新应用程序时,主捆绑的js文件都会发生变化,pwa已经缓存了旧的js文件,而应用程序仍在尝试使用新的js文件。
我的项目结构如下
我有一个懒加载其他模块的根模块,现在加载的第一个模块是我的帐户模块,这样用户就可以登录
这是我的根路由.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 {

}
所以从技术上来说,用户得到的第一个模块是account模块,但显然它必须从根模块重定向。
所以我所做的是在我的根组件模块中检查服务工作者是否需要像这样更新…
根组件
@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);
});
});
}
}

现在应该检查是否有更新,然后刷新页面。但没用。
这是我的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块文件…但它没有
现在,当我在一个新的构建之后检查network选项卡时,这就是我得到的
enter image description here
在我排除main.js文件之前
这就是我的 main.js调用在从 ngsw.config中排除后的样子。
enter image description here
然后我想试着用我的哨兵错误处理程序来捕捉这个错误。
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);
}
}
}

但这不起作用,我在哨兵的错误,但应用程序没有重新加载??
现在我做了一些测试,如果你在私有模式下重新构建之后访问站点,你将永远不会得到错误,只有在你以前访问过站点的情况下才会出现这种情况,这使我认为这是一个缓存问题
我的应用程序托管在azure上,我的应用程序使用的是angular 7.27
任何帮助都将不胜感激!

最佳答案

这个问题是由安装的ServiceWorker引起的,它干扰和缓存所有的响应,包括刚才更新的那些。
有关服务工作者的更多信息:mdn-使用服务工作者
https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers
这就是为什么window.location.reload()不起作用的原因,因为它确实发出了一个新的请求,但是这个请求被安装的ServiceWorker劫持了,而不是让真正的请求通过真正的服务器并获取真正的响应(更新的main.js和assets),它只是返回给你的应用一个缓存的响应,这是旧的main.js,而不是更新的main.js,这就是它失败的原因。
更具体地说,ServiceWorker缓存了每次更改代码时生成的main.js和其他资产。js依次加载时,它会延迟加载应用程序的其他块(例如5.xxxxx.js)。
当你对代码进行更改时,即使所有的块都被更新,包括main.js5.xxxxxx.js块,浏览器仍然运行旧的main.js。这个旧的main.js有一个引用,旧的对5.xxxxxx.js不再存在。在这一点上,如果你做了一个重新加载(),安装的ServiceWorker用旧的缓存main.js响应,它试图从不存在的服务器中懒惰地加载旧版本的5.xxxxx.js,因此得到404 HTML错误的响应。因此,'<'标记异常(它实际上是404错误页标记的第一个字符)。
从网络面板截图可以明显看出这一点。如果您检查截图,您将看到main.js和所有其他资产都是从(from service worker)传递的,这意味着那些是缓存的旧版本,并且不同于现在存在于Web服务器中的实际更新的文件。
为了解决这个问题,ServiceWorker必须被配置为不缓存main.js,而是总是让这个请求进入真实服务器以获取任何更新版本main.js,这将懒惰地加载现在在Web服务器中实际存在的更新的5.xxxx.js块。
下面是如何配置ngsw-config.jsonServiceWorker来特别不缓存main.js文件(假设它是main.xxxxxxx.js模式)以解决此问题:

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

运行 ng build --prod重新生成应用程序并测试它。
更新:
要确保这不是浏览器缓存问题,请将 true作为第一个参数传递给window.location.reload()方法。这指示浏览器在不使用缓存资源的情况下执行重新加载:
根组件
                    .then(() => {
window.location.reload(true);
});


更新2:
根据角度的文档,缓存在客户端浏览器上的服务工作者被缓存。如果更新服务工作人员代码(如您最近所做的那样),则必须在已安装的客户端的所有浏览器中更新新的服务工作人员代码。角度文档说明有定期检查,但不指定它,检查服务工作者本身是否需要更新,并将进行更新。
https://angular.io/guide/service-worker-devops#service-worker-updates
也许,只有在生产中,而不是在开发中,或者用私人浏览器模式(干净的浏览器SLAT,没有安装SW)的问题,似乎是这样的。
为了验证这一点,您应该使用Chrome的开发者工具来比较在页面上运行的现有浏览器的SW,以及应该安装的更新的SW代码。如果它们是不同的,那就意味着它还没有更新,这就是导致问题的原因。
你可以使用一个显示这个问题的Chrome浏览器,通过Chrome DeV工具>应用程序标签>服务人员(在左面板的顶部),将有在浏览器中注册的SW。单击源链接,它将打开软件的实际代码。逐行比较代码(或使用diff实用程序)与应该运行的更新的sw代码。

关于angular - 每个新的 Angular 生产PWA版本上的“意外 token <”,直到站点刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55155359/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com