Skip to content

Commit dda2211

Browse files
Add service worker
1 parent cae6a9c commit dda2211

File tree

7 files changed

+101
-3
lines changed

7 files changed

+101
-3
lines changed

src/ProjectTemplates/BlazorWasm.ProjectTemplates/BlazorWasm-CSharp.Client.csproj.in

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,25 @@
1111
<PackageReference Include="Microsoft.AspNetCore.Blazor.DevServer" Version="${MicrosoftAspNetCoreBlazorDevServerPackageVersion}" PrivateAssets="all" />
1212
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="${MicrosoftAspNetCoreBlazorHttpClientPackageVersion}" />
1313
</ItemGroup>
14+
1415
<!--#if Hosted -->
1516
<ItemGroup>
1617
<ProjectReference Include="..\Shared\BlazorWasm-CSharp.Shared.csproj" />
1718
</ItemGroup>
19+
1820
<!--#endif -->
21+
<!--#if PWA -->
22+
<Target Name="PublishServiceWorker" AfterTargets="CopyFilesToPublishDirectory">
23+
<!-- Use the "published" version of the service worker in the output -->
24+
<PropertyGroup>
25+
<ServiceWorkerMoveFrom>$(PublishDir)$(BlazorPublishDistDir)service-worker.published.js</ServiceWorkerMoveFrom>
26+
<ServiceWorkerMoveTo>$(PublishDir)$(BlazorPublishDistDir)service-worker.js</ServiceWorkerMoveTo>
27+
</PropertyGroup>
28+
<Move SourceFiles="$(ServiceWorkerMoveFrom)" DestinationFiles="$(ServiceWorkerMoveTo)" />
1929

30+
<!-- Append a unique version number that will trigger installation of updates -->
31+
<WriteLinesToFile File="$(ServiceWorkerMoveTo)" Lines="const serviceWorkerVersion = '$([System.Guid]::NewGuid())'" />
32+
</Target>
33+
34+
<!--#endif -->
2035
</Project>

src/ProjectTemplates/BlazorWasm.ProjectTemplates/content/BlazorWasm-CSharp/.template.config/dotnetcli.host.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
"longName": "no-restore",
66
"shortName": ""
77
},
8-
"Hosted": {
9-
"longName": "hosted"
10-
},
8+
"Hosted": {
9+
"longName": "hosted"
10+
},
11+
"PWA": {
12+
"longName": "pwa"
13+
},
1114
"Framework": {
1215
"longName": "framework"
1316
}

src/ProjectTemplates/BlazorWasm.ProjectTemplates/content/BlazorWasm-CSharp/.template.config/template.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@
7474
"exclude": [
7575
"*.sln"
7676
]
77+
},
78+
{
79+
"condition": "(!PWA)",
80+
"exclude": [
81+
"Client/wwwroot/service-worker*.js"
82+
]
7783
}
7884
]
7985
}
@@ -147,6 +153,12 @@
147153
"fallbackVariableName": "HttpsPortGenerated"
148154
},
149155
"replaces": "44300"
156+
},
157+
"PWA": {
158+
"type": "parameter",
159+
"datatype": "bool",
160+
"defaultValue": "false",
161+
"description": "If specified, produces a Progressive Web Application (PWA) supporting installation and offline use."
150162
}
151163
},
152164
"tags": {

src/ProjectTemplates/BlazorWasm.ProjectTemplates/content/BlazorWasm-CSharp/.template.config/vs-2017.3.host.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@
2525
"text": "ASP.NET Core _hosted"
2626
},
2727
"isVisible": "true"
28+
},
29+
{
30+
"id": "PWA",
31+
"name": {
32+
"text": "_Progressive Web Application"
33+
},
34+
"isVisible": "true"
2835
}
2936
]
3037
}

src/ProjectTemplates/BlazorWasm.ProjectTemplates/content/BlazorWasm-CSharp/Client/wwwroot/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
<a class="dismiss">🗙</a>
2020
</div>
2121
<script src="_framework/blazor.webassembly.js"></script>
22+
<!--#if PWA -->
23+
<script>navigator.serviceWorker.register('service-worker.js');</script>
24+
<!--#endif -->
2225
</body>
2326

2427
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// See service-worker.published.js for the offline support logic.
2+
// This is not enabled in development as it would make development more difficult
3+
// (changes would not be reflected on the first load after each change).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Caution! Be sure you understand the caveats before publishing an application with
2+
// offline support. See https://aka.ms/blazor-offline-considerations
3+
//
4+
// This service worker implements a cache-first policy. For offline support to work,
5+
// you must ensure that 'resourcesAvailableOffline' lists all the resources needed
6+
// by your application (except for .NET assemblies and dotnet.wasm).
7+
8+
const resourcesAvailableOffline = [
9+
'index.html',
10+
'_framework/blazor.boot.json',
11+
'_framework/blazor.webassembly.js',
12+
'_framework/wasm/dotnet.js',
13+
'css/site.css',
14+
'css/bootstrap/bootstrap.min.css',
15+
'css/open-iconic/font/css/open-iconic-bootstrap.min.css',
16+
'css/open-iconic/font/fonts/open-iconic.woff'
17+
];
18+
19+
const cacheNamePrefix = 'offline-cache-';
20+
const cacheName = () => `${cacheNamePrefix}${serviceWorkerVersion}`;
21+
22+
self.addEventListener('install', event => event.waitUntil(onInstall(event)));
23+
self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
24+
self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
25+
26+
async function onInstall(event) {
27+
console.info('Service worker: Install');
28+
const cache = await caches.open(cacheName());
29+
await cache.addAll(resourcesAvailableOffline);
30+
}
31+
32+
async function onActivate(event) {
33+
console.info('Service worker: Activate');
34+
35+
// Delete unused caches
36+
const cacheKeys = await caches.keys();
37+
return Promise.all(cacheKeys
38+
.filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName())
39+
.map(key => caches.delete(key)));
40+
}
41+
42+
async function onFetch(event) {
43+
let cachedResponse = null;
44+
if (event.request.method === 'GET') {
45+
// For all navigation requests, try to serve index.html from cache
46+
// If you need some URLs to be server-rendered, edit the following check to exclude those URLs
47+
const shouldServeIndexHtml = event.request.mode === 'navigate';
48+
49+
const request = shouldServeIndexHtml ? 'index.html' : event.request;
50+
const cache = await caches.open(cacheName());
51+
cachedResponse = await cache.match(request);
52+
}
53+
54+
return cachedResponse || fetch(event.request);
55+
}

0 commit comments

Comments
 (0)