diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 81b6e23d..aa46e6e8 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "dotnet-serve": { - "version": "1.10.193", + "version": "1.10.194", "commands": [ "dotnet-serve" ], diff --git a/eng/IndexHtmlGeneration.targets b/eng/IndexHtmlGeneration.targets index c7a4669d..2a409201 100644 --- a/eng/IndexHtmlGeneration.targets +++ b/eng/IndexHtmlGeneration.targets @@ -2,7 +2,8 @@ $(MSBuildThisFileDirectory)index.template.html - $(MSBuildProjectDirectory)\wwwroot\index.html + wwwroot\index.html + $(MSBuildProjectDirectory)\$(IndexHtmlOutputRelativePath) _framework/blazor.js / + - + diff --git a/eng/build.sh b/eng/build.sh index 7df8c136..351c80b3 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -6,3 +6,4 @@ chmod +x dotnet-install.sh ./dotnet/dotnet --version ./dotnet/dotnet workload install wasm-tools wasm-experimental ./dotnet/dotnet publish -o output src/WebAssembly +./dotnet/dotnet run --file eng/check-publish-output.cs -- output diff --git a/eng/check-publish-output.cs b/eng/check-publish-output.cs new file mode 100755 index 00000000..3d9df552 --- /dev/null +++ b/eng/check-publish-output.cs @@ -0,0 +1,40 @@ +#!/usr/bin/env dotnet + +using System.Text.Json.Nodes; + +if (args is not [{ Length: > 0 } arg]) +{ + Console.Error.WriteLine("Usage: check-publish-output.cs "); + return 1; +} + +if (!Directory.Exists(arg)) +{ + Console.Error.WriteLine($"Error: Directory '{arg}' does not exist."); + return 1; +} + +var serviceWorkerAssetsFile = Path.Join(arg, "wwwroot", "service-worker-assets.js"); +if (!File.Exists(serviceWorkerAssetsFile)) +{ + Console.Error.WriteLine($"Error: Service worker assets file not found at '{serviceWorkerAssetsFile}'."); + return 1; +} + +var serviceWorkerAssetsContent = File.ReadAllText(serviceWorkerAssetsFile); +const string prefix = "self.assetsManifest = "; +if (!serviceWorkerAssetsContent.StartsWith(prefix, StringComparison.Ordinal)) +{ + Console.Error.WriteLine($"Error: Unexpected content in service worker assets file. Expected it to start with '{prefix}'."); + return 1; +} + +var serviceWorkerAssetsJson = serviceWorkerAssetsContent[prefix.Length..].TrimEnd(';', ' ', '\r', '\n'); +if (JsonNode.Parse(serviceWorkerAssetsJson)!["assets"]!.AsArray().SingleOrDefault(a => a!["url"]!.GetValue() == "index.html") == null) +{ + Console.Error.WriteLine("Error: index.html is not listed in the service worker assets manifest."); + return 1; +} + +Console.Error.WriteLine("OK: index.html is listed in the service worker assets manifest."); +return 0; diff --git a/src/WebAssembly/WebAssembly.csproj b/src/WebAssembly/WebAssembly.csproj index f3845df5..037ccfa2 100644 --- a/src/WebAssembly/WebAssembly.csproj +++ b/src/WebAssembly/WebAssembly.csproj @@ -8,7 +8,7 @@
- For faster loading, use the + Consider using more capable and performant diff --git a/src/WebAssembly/wwwroot/service-worker.published.js b/src/WebAssembly/wwwroot/service-worker.published.js index de070b15..dfb70a26 100644 --- a/src/WebAssembly/wwwroot/service-worker.published.js +++ b/src/WebAssembly/wwwroot/service-worker.published.js @@ -21,7 +21,7 @@ const offlineAssetsExclude = [ /^service-worker\.js$/ ]; // Replace with your base path if you are hosting on a subfolder. Ensure there is a trailing '/'. const base = "/"; const baseUrl = new URL(base, self.origin); -const manifestUrlList = self.assetsManifest.assets.map(asset => new URL(asset.url, baseUrl).href); +const manifestUrlSet = new Set(self.assetsManifest.assets.map(asset => new URL(asset.url, baseUrl).href)); async function onInstall() { console.info('Service worker: Install'); @@ -80,31 +80,37 @@ async function onFetch(event) { return new Response('', { headers: { Refresh: '0' } }); } - let cachedResponse = null; - if (event.request.method === 'GET') { - // For all navigation requests, try to serve index.html from cache, - // unless that request is for an offline resource. - // If you need some URLs to be server-rendered, edit the following check to exclude those URLs - const shouldServeIndexHtml = event.request.mode === 'navigate' - && !manifestUrlList.some(url => url === event.request.url); - - if (shouldServeIndexHtml) { - console.debug(`Service worker: serving index.html for ${event.request.url}`); + const fetchResponse = fetch(event.request); + try { + // First try network / disk cache (it's usually faster than the service worker cache). + return await fetchResponse; + } catch { + let cachedResponse = null; + if (event.request.method === 'GET') { + // For all navigation requests, try to serve index.html from cache, + // unless that request is for an offline resource. + // If you need some URLs to be server-rendered, edit the following check to exclude those URLs + const shouldServeIndexHtml = event.request.mode === 'navigate' + && !manifestUrlSet.has(event.request.url); + + if (shouldServeIndexHtml) { + console.debug(`Service worker: serving index.html for ${event.request.url}`); + } + + const request = shouldServeIndexHtml ? 'index.html' : event.request; + + const cache = await caches.open(cacheName); + // We ignore search query (so our pre-cached `app.css` matches request `app.css?v=2`), + // we have pre-cached the latest versions of all static assets anyway. + cachedResponse = await cache.match(request, { ignoreSearch: true }); } - const request = shouldServeIndexHtml ? 'index.html' : event.request; - - const cache = await caches.open(cacheName); - // We ignore search query (so our pre-cached `app.css` matches request `app.css?v=2`), - // we have pre-cached the latest versions of all static assets anyway. - cachedResponse = await cache.match(request, { ignoreSearch: true }); - } + if (!cachedResponse) { + console.debug(`Service worker: cache miss for ${event.request.url}`); + } - if (!cachedResponse) { - console.debug(`Service worker: cache miss for ${event.request.url}`); + return cachedResponse || fetchResponse; } - - return cachedResponse || fetch(event.request); } /**