从 Javascript 强制完全刷新 Blazor WebAssembly PWA 应用程序

问题描述 投票:0回答:3

此代码位于index.html中。我使用最新版本的 Blazor WebAssembly PWA 应用程序调用

updateVersion
。第一行是 Service Worker 的原始注册,它是 Blazor 应用模板的一部分。剩下的都是我加上去的。

navigator.serviceWorker.register('service-worker.js');

function updateVersion(newVersion) {
    var key = 'x-photish-version';

    var oldVersion = localStorage.getItem(key);

    if (oldVersion == null) {
        localStorage.setItem(key, newVersion);
    }
    else if (newVersion != oldVersion) {
        localStorage.setItem(key, newVersion);

        // Reload service worker
        navigator.serviceWorker.register('service-worker.js').then(function (registration) {

            caches.delete("blazor-resources-/").then(function (e) {
                console.log("'blazor-resources-/' cache deleted");
            });

            registration.update();

            window.location.reload(); 
        }).catch(function (error) {
            // registration failed
            console.log(`Registration failed with ${error}`);
        });
    }
}

版本部分有效。它检测到版本是新的,并正确输入代码的

newVersion != oldVersion
部分,我想确保应用程序完全刷新。

为了测试它,我发布了应用程序的新版本,并对应用程序进行了一些细微的更改,它检测到它是新版本并重新加载页面。我的小应用程序更改不会出现。它显示了应用程序的旧版本。

我必须找到一种从代码中执行此操作的方法,因为我不希望用户在每次页面加载时检索最新内容。仅当我实际部署了新版本的代码时。

如何确保 serviceworker 刷新并且 blazor 应用本身的缓存不被缓存?

更新:我认为将代码更改为以下内容后就解决了,但我仍然看到一些不起作用的情况。

navigator.serviceWorker.register('service-worker.js');

function updateVersion(newVersion) {
    var key = 'x-photish-version';

    var oldVersion = localStorage.getItem(key);

    if (oldVersion == null) {
        localStorage.setItem(key, newVersion);
    }
    else if (newVersion != oldVersion) {
        localStorage.setItem(key, newVersion);

        caches.delete("blazor-resources-/").then(function (e) {
            console.log("'blazor-resources-/' cache deleted");
        });

        // Reload service worker
        navigator.serviceWorker.register('/service-worker.js', { updateViaCache: 'none' }).then(function (registration) {

            window.location.reload(); 

        }).catch(function (error) {
            // registration failed
            console.log(`Registration failed with ${error}`);
        });
    }
}

仍然希望有人可以修复代码并使其防弹,或者干脆声明由于某种原因这在技术上是不可能的。

blazor progressive-web-apps service-worker blazor-webassembly
3个回答
5
投票

我找到了一个解决方案,并在几天内确认它有效。它也可以在我加载到 iOS 中的 PWA 上运行。

如果与 wwwroot/service-worker.published.js 中更新的 const CACHE 相结合,我现有的问题函数就可以工作。

我的构建后 Powershell 脚本如下所示:

$currentDate = get-date -format yyyy.MM.dd.HHmm;

# Update service worker
$curDir = Get-Location
$inputFile = $curDir.Path +"\wwwroot\service-worker.published.js"
$findString = "const CACHE_VERSION =.+"
$replaceString = "const CACHE_VERSION = '$currentDate'"
(Get-Content $inputFile) | ForEach-Object { $_ -replace $findString , $replaceString } | Set-Content $inputFile

Write-Host "Service Worker Updated:     $currentDate"

为了让它工作,我必须手动将此行添加到 service-worker.published.js:

const CACHE_VERSION = '2022.08.10.2222'

我还使用以下构建后 Powershell 脚本来更新 version.txt 中的版本,我一直知道它会更新。然后我还更新了 csproj 内的程序集版本。这样我就可以比较这两个值,看看我是否真的在运行最新的代码:

param([string]$ProjectDir, [string]$ProjectPath);

$currentDate = get-date -format yyyy.MM.dd.HHmm;

# Update version.txt
$versionFilePath = $ProjectDir + "/wwwroot/version.txt"
Set-Content -Path $versionFilePath -Value $currentDate -NoNewline

Write-Host "version.txt Updated:        $currentDate"

# Update actual assembly version
$find = "<Version>(.|\n)*?</Version>";
$replace = "<Version>" + $currentDate + "</Version>";
$csproj = Get-Content $ProjectPath
$csprojUpdated = $csproj -replace $find, $replace

Set-Content -Path $ProjectPath -Value $csprojUpdated

Write-Host "Assembly Version Updated:   $currentDate"

供您参考,我在C#中检查了这样的汇编版本:

assemblyVersion = Assembly.GetExecutingAssembly()?.
            GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.
            InformationalVersion;

我通过简单的 http 调用检查最新版本,但在 C# 中指示无缓存。

var message = new HttpRequestMessage
{
    Method = HttpMethod.Get,
    RequestUri = new Uri(baseUri + "version.txt?nocache=" + DateTime.Now.ToString("yyyyMMddHHmmss"))
};
message.Headers.CacheControl = new CacheControlHeaderValue
{
    NoCache = true
};

var versionResponse = await http.SendAsync(message);
var version = await versionResponse.Content.ReadAsStringAsync();

return version;

我在 Blazor 中使用以下行调用 index.html 中的函数:

await js.InvokeAsync<string>("updateVersion", state.Version);

最后是index.html 中的javascript,它将清除缓存并刷新服务工作线程。

navigator.serviceWorker.register('service-worker.js');

function updateVersion(newVersion) {
    var key = 'x-photish-version';

    var oldVersion = localStorage.getItem(key);

    if (oldVersion == null) {
        localStorage.setItem(key, newVersion);
    }
    else if (newVersion != oldVersion) {
        localStorage.setItem(key, newVersion);

        caches.delete("blazor-resources-/").then(function (e) {
            console.log("'blazor-resources-/' cache deleted");
        });

        // Reload service worker
        navigator.serviceWorker.register('/service-worker.js', { updateViaCache: 'none' }).then(function (registration) {

            window.location.reload(); 

        }).catch(function (error) {
            // registration failed
            console.log(`Registration failed with ${error}`);
        });
    }
}

第一行包含在标准 Blazor 模板中。剩下的就是从 Blazor 中的互操作中调用的函数。

瞧:只需编码。在每个版本中,版本号都会更新。如果用户打开过时的生产代码,页面将自动重新加载,然后运行最新的代码。


1
投票

嘿,这对你有用,尝试一次

window.updateAvailable = new Promise((resolve, reject) => {
  if (!('serviceWorker' in navigator)) {
    const errorMessage = `This browser doesn't support service workers`;
    console.error(errorMessage);
    reject(errorMessage);
    return;
  }

  navigator.serviceWorker.register('/service-worker.js')
    .then(registration => {
      console.info(`Service worker registration successful (scope: ${registration.scope})`);

      registration.onupdatefound = () => {
        const installingServiceWorker = registration.installing;
        installingServiceWorker.onstatechange = () => {
          if (installingServiceWorker.state === 'installed') {
            resolve(!!navigator.serviceWorker.controller);
          }
        }
      };
    })
    .catch(error => {
      console.error('Service worker registration failed with error:', error);
      reject(error);
    });
});

window.registerForUpdateAvailableNotification = (caller, methodName) => {
  window.updateAvailable.then(isUpdateAvailable => {
    if (isUpdateAvailable) {
      caller.invokeMethodAsync(methodName).then();
    }
  });
};

也检查参考:https://gist.github.com/huysentruitw/24b23ec49ebd38c9ff891ffb83f06088#file-service-worker-js


0
投票

这是另一种具有最佳实践的方法

https://whuysentruit.medium.com/blazor-wasm-pwa-adding-a-new-update-available-notification-d9f65c4ad13

链接只是因为它很多

© www.soinside.com 2019 - 2024. All rights reserved.