3 回答
TA贡献1847条经验 获得超11个赞
对于仍然遇到此问题的任何人,这是我为减少延迟所做的事情:
在 APP_INITIALIZER 而不是 AppComponent 中检查更新,以便更早完成检查
使用
checkForUpdate方法
在你app.module.ts添加一个初始化函数:
{ provide: APP_INITIALIZER, useFactory: checkForUpdates, multi: true, deps: [SwUpdate /* Add whatever dependency is required here */] },该函数应如下所示:
export const checkForUpdates = (swUpdate: SwUpdate): (() => Promise<any>) => {
return (): Promise<void> =>
new Promise((resolve) => {
swUpdate.checkForUpdate();
swUpdate.available.subscribe(() => {
window.location.reload();
});
resolve();
});
};
我不确定是否需要 APP_INITIALIZER 和 checkForUpdate,但这样我将延迟减少到 1-2 秒(而不是 5-10 秒甚至更多)
TA贡献1893条经验 获得超10个赞
我使用 Carrm 和 NeNad 的两个答案在我的 Angular 应用程序中创建一个页面来管理更新。
我还使用@saithodev/ts-appversion包来管理版本。
稍后,我创建了一个脚本来更新每个构建的应用程序版本并将其显示在该页面上 (appversionupdate.mjs)。
然后,在 package.json 中,我将脚本设置为与 npm run 一起使用。
这样,当我构建和部署项目时,版本会根据需要进行更新。
我知道 OP 并没有要求所有这些,但它可能对社区有用。
menu.component.html
<mat-toolbar color="accent" fxLayout="row" fxLayoutAlign="space-between center" class="top-bar">
<div fxLayout="row" fxLayoutAlign="start center">
<h1>Atualização do app</h1>
</div>
</mat-toolbar>
<main>
<div>
<h2>Versão do app instalada: {{versao}}</h2>
</div>
<h3>Status da atualização</h3>
<!-- lista sem numeração em HTML -->
<ul>
<li *ngFor="let mensagem of mensagens">
{{mensagem}}
</li>
</ul>
<button mat-raised-button color="accent" (click)="atualizarApp();" class="botao">Atualizar app</button>
</main>
menu.component.ts
import { Component, OnInit } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';
import { versions } from 'src/_versions';
@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.scss']
})
export class MenuComponent implements OnInit {
mensagens: string[] = [];
versao: string = 'Versão ainda não carregada pelo sistema.';
constructor(
private readonly swUpdate: SwUpdate,
) { }
ngOnInit(): void {
this.atualizarApp();
this.versao = versions.version;
}
async atualizarApp() {
this.mensagens?.push(`${this.getFormattedDate()} Iniciando atualização do app.`);
try {
// Check if Service Worker is supported by the Browser
if (this.swUpdate.isEnabled) {
this.mensagens?.push(`${this.getFormattedDate()} Verificado que este navegador suporta a atualização do app.`);
const isNewVersion = await this.swUpdate.checkForUpdate();
this.mensagens?.push(`${this.getFormattedDate()} Verificando se há nova versão a ser baixada.`);
// Check if the new version is available
if (isNewVersion) {
this.mensagens?.push(`${this.getFormattedDate()} Nova versão do app encontrada. Fazendo download.`);
const isNewVersionActivated = await this.swUpdate.activateUpdate();
// Check if the new version is activated and reload the app if it is
if (isNewVersionActivated) {
this.mensagens?.push(`${this.getFormattedDate()} Nova versão baixada e instalada.`);
window.location.reload();
}
} else {
this.mensagens?.push(`${this.getFormattedDate()} O Materiale app já está atualizado.`);
}
} else {
this.mensagens?.push(`${this.getFormattedDate()} Verificado que este navegador não suporta a atualização do app automática e outras funcionalidades.`);
this.mensagens?.push(`${this.getFormattedDate()} Por favor, atualize o navegador para a versão mais recente. Baixe preferencialmente o Google Chrome.`);
}
} catch (error) {
this.mensagens?.push(`${this.getFormattedDate()} Houve algum error ao tentar atualizar o app. Mensagem de erro: ${error}`);
this.mensagens?.push(`${this.getFormattedDate()} É possível que este navegador não seja compatível. Por favor, atualize o navegador para a versão mais recente. Baixe preferencialmente o Google Chrome.`);
this.mensagens?.push(`${this.getFormattedDate()} Mensagem de erro: ${error}`);
//window.location.reload();
}
}
getFormattedDate(): string {
var date = new Date();
var str = `${date.getDate()}/${(date.getMonth() + 1)}/${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
return str;
}
}
appversionupdate.mjs
import fs from 'fs';
//console.log("Atualizado versao do app");
var obj = JSON.parse(fs.readFileSync('package.json', 'utf8'));
var version = obj.version;
var major = version.split('.')[0];
var minor = version.split('.')[1];
var patch = version.split('.')[2];
var minor_updated = Number(minor) +1;
var version_updated = major + '.' + minor_updated + '.' + patch;
console.log("Nova versao: " + version_updated);
obj.version = version_updated;
let data = JSON.stringify(obj, null, 2);
fs.writeFileSync('package.json', data);
包.json
{
"name": "testeapp",
"version": "0.14.0",
"scripts": {
"ng": "ng",
"prestart": "ts-appversion",
"start": "ng serve",
"prebuild": "ts-appversion",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"bd": "node ./appversionupdate.mjs && npm run build && firebase deploy"
},
TA贡献1816条经验 获得超4个赞
问题
Angular 中的 Service Worker 有 4 种不同的注册策略,这决定了它何时向浏览器注册。
registerWhenStable:<timeout>: 应用程序稳定后立即注册(没有挂起的微/宏任务),但不迟于毫秒。如果应用程序在几毫秒后还没有稳定下来(例如,由于重复的异步任务),无论如何都会注册 ServiceWorker。如果省略,ServiceWorker 将仅在应用程序稳定后注册。registerImmediately: 立即注册。registerWithDelay:<timeout>: 注册延迟毫秒。例如,使用 registerWithDelay:5000 在 5 秒后注册 ServiceWorker。如果省略,则默认为 0,一旦所有待处理的微任务完成,它将尽快注册 ServiceWorker,但仍然是异步的。An Observable factory function: 一个返回 Observable 的函数。该函数将在运行时用于获取和订阅 Observable,并且只要发出第一个值,就会注册 ServiceWorker。
注意: Angular默认registerWhenStable:30000使用. 这意味着它将首先等待应用程序稳定,然后它会注册一个 Service Worker(或者如果应用程序在此之前没有稳定,它将在 30 秒后注册 Service Worker)。
解决方案
registerWhenStable:30000您可以设置registerImmediately策略而不是 default 。然后,您可以例如添加APP_INITIALIZER并在其中检查是否有新版本并加载它。在这种情况下,如果有新版本可用,用户将看不到旧版本。
app.module.ts
import { APP_INITIALIZER } from '@angular/core';
import { ServiceWorkerModule, SwUpdate } from '@angular/service-worker';
...
function initializeApp(): Promise<any> {
return new Promise(async (resolve, reject) => {
try {
// Check if Service Worker is supported by the Browser
if (this.swUpdate.isEnabled) {
const isNewVersion = await this.swUpdate.checkForUpdate();
// Check if the new version is available
if (isNewVersion) {
const isNewVersionActivated = await this.swUpdate.activateUpdate();
// Check if the new version is activated and reload the app if it is
if (isNewVersionActivated) window.location.reload();
resolve(true);
}
resolve(true);
}
resolve(true);
} catch (error) {
window.location.reload();
}
});
}
...
@NgModule({
...
imports: [
...,
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production,
registrationStrategy: 'registerImmediately',
}),
],
providers: [
...,
{ provide: APP_INITIALIZER, useFactory: initializeApp, deps: [SwUpdate], multi: true },
],
})
export class AppModule {}
添加回答
举报
