SilverLABS.SilverSHELL.PWA 1.1.1
SilverLABS.SilverSHELL.PWA
Progressive Web App (PWA) support for SilverSHELL applications.
Features
- ✨ NEW: Ready-Made PWA Assets - Includes
pwa.jsandservice-worker.jsout of the box! - Offline Support - Work without internet connection
- Installable - Add to home screen on mobile/desktop
- Service Worker - Automatic caching and background sync with multiple strategies
- App Manifest - Configure PWA appearance and behavior
- Install Prompt - Custom installation UI with JavaScript interop
- Theme Customization - Brand colors and styling
- Update Notifications - Alert users of new versions
- Offline Detection - Automatic online/offline status tracking
Installation
dotnet add package SilverLABS.SilverSHELL.PWA
Quick Start
1. Configure PWA Services
using SilverSHELL.PWA.Extensions;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddSilverShellPWA(options =>
{
options.AppName = "My Application";
options.ShortName = "MyApp";
options.Description = "My awesome PWA application";
options.EnableOfflineSupport = true;
options.ShowInstallPrompt = true;
options.ThemeColor = "#2196F3";
options.BackgroundColor = "#ffffff";
});
await builder.Build().RunAsync();
2. Include PWA Scripts (✨ NEW in v1.1.0 - Automatically Included!)
Add these to your wwwroot/index.html before the closing </head> tag:
<!-- Service Worker & PWA Support -->
<script src="_content/SilverSHELL.PWA/service-worker.js"></script>
<script src="_content/SilverSHELL.PWA/pwa.js"></script>
That's it! The package now includes production-ready PWA assets. No need to create your own service worker!
3. Add Service Worker (Optional - Manual Approach)
If you prefer a custom service worker, create wwwroot/service-worker.js:
self.addEventListener('install', event => {
console.log('Service worker installing...');
self.skipWaiting();
});
self.addEventListener('activate', event => {
console.log('Service worker activating...');
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
3. Register Service Worker
In index.html:
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(reg => console.log('Service worker registered'))
.catch(err => console.log('Service worker registration failed'));
}
</script>
4. Add Web Manifest
Create wwwroot/manifest.json:
{
"name": "My Application",
"short_name": "MyApp",
"description": "My awesome PWA",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#2196F3",
"icons": [
{
"src": "icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
Link in index.html:
<link rel="manifest" href="manifest.json" />
<link rel="apple-touch-icon" href="icon-192.png" />
<meta name="theme-color" content="#2196F3" />
Configuration Options
PWAOptions
public class PWAOptions
{
/// <summary>
/// Full application name
/// </summary>
public string AppName { get; set; } = "SilverSHELL App";
/// <summary>
/// Short name for home screen
/// </summary>
public string ShortName { get; set; } = "SilverSHELL";
/// <summary>
/// Application description
/// </summary>
public string Description { get; set; } = "Progressive Web Application";
/// <summary>
/// Enable offline functionality
/// </summary>
public bool EnableOfflineSupport { get; set; } = true;
/// <summary>
/// Show install prompt to users
/// </summary>
public bool ShowInstallPrompt { get; set; } = true;
/// <summary>
/// Theme color (hex)
/// </summary>
public string ThemeColor { get; set; } = "#2196F3";
/// <summary>
/// Background color (hex)
/// </summary>
public string BackgroundColor { get; set; } = "#ffffff";
}
Advanced Features
1. Custom Install Prompt
@inject IJSRuntime JS
@inject IOptions<PWAOptions> PWAOptions
@if (showInstallPrompt && PWAOptions.Value.ShowInstallPrompt)
{
<div class="install-prompt">
<p>Install @PWAOptions.Value.AppName for a better experience!</p>
<button @onclick="InstallApp">Install</button>
<button @onclick="DismissPrompt">Not now</button>
</div>
}
@code {
private bool showInstallPrompt = true;
private async Task InstallApp()
{
await JS.InvokeVoidAsync("installPWA");
showInstallPrompt = false;
}
private void DismissPrompt()
{
showInstallPrompt = false;
}
}
2. Offline Detection
@inject IJSRuntime JS
<div class="@(isOnline ? "online" : "offline")">
@(isOnline ? "✅ Online" : "⚠️ Offline")
</div>
@code {
private bool isOnline = true;
protected override async Task OnInitializedAsync()
{
isOnline = await JS.InvokeAsync<bool>("navigator.onLine");
}
}
3. Update Notification
@if (updateAvailable)
{
<div class="update-notification">
<p>A new version is available!</p>
<button @onclick="ReloadApp">Update Now</button>
</div>
}
@code {
private bool updateAvailable = false;
private async Task ReloadApp()
{
await JS.InvokeVoidAsync("location.reload", true);
}
}
Service Worker Strategies
1. Cache-First Strategy
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
2. Network-First Strategy
self.addEventListener('fetch', event => {
event.respondWith(
fetch(event.request)
.catch(() => caches.match(event.request))
);
});
3. Stale-While-Revalidate
self.addEventListener('fetch', event => {
event.respondWith(
caches.open('dynamic').then(cache => {
return fetch(event.request).then(response => {
cache.put(event.request, response.clone());
return response;
}).catch(() => cache.match(event.request));
})
);
});
Best Practices
- Always test offline - Use Chrome DevTools to simulate offline mode
- Cache strategically - Only cache essential resources
- Version your cache - Update cache name on new releases
- Handle updates gracefully - Notify users of new versions
- Provide icons - Include 192x192 and 512x512 PNG icons
- Use HTTPS - PWAs require secure connections
Documentation
Support
- Issues: GitLab Issues
- Email: support@silverlabs.uk
Changelog
v1.1.0
- ✨ NEW: Included ready-made PWA assets (
pwa.jsandservice-worker.js) - ✨ NEW: Install prompt handling with JavaScript interop (
SilverShellPWA.install()) - ✨ NEW: Offline detection with automatic CSS classes (
pwa-online,pwa-offline) - ✨ NEW: Service worker update notifications
- ✨ NEW: Multiple caching strategies (cache-first, network-first, stale-while-revalidate)
- ✨ NEW: Background sync and push notification support
- 🔧 IMPROVED: Changed to Razor SDK for static web asset support
- 🔧 IMPROVED: No manual service worker creation required
- 📚 DOCS: Updated README with automatic asset inclusion instructions
v1.0.0
- Initial release
License
This project is licensed under the MIT License.
Made with ❤️ by SilverLABS
No packages depend on SilverLABS.SilverSHELL.PWA.
v1.1.1: Documentation improvements - Updated README with clear instructions for including PWA assets via _content path. Includes ready-made pwa.js and service-worker.js!
.NET 9.0
| Version | Downloads | Last updated |
|---|---|---|
| 1.2.2-ci.1020 | 2 | 10/26/2025 |
| 1.2.1 | 28 | 10/26/2025 |
| 1.2.1-ci.1016 | 1 | 10/26/2025 |
| 1.2.1-ci.1012 | 1 | 10/26/2025 |
| 1.2.1-ci.985 | 1 | 10/25/2025 |
| 1.2.1-ci.977 | 2 | 10/25/2025 |
| 1.2.1-ci.935 | 2 | 10/24/2025 |
| 1.2.1-ci.934 | 6 | 10/24/2025 |
| 1.2.1-ci.932 | 3 | 10/24/2025 |
| 1.2.1-ci.931 | 2 | 10/24/2025 |
| 1.2.1-ci.929 | 2 | 10/24/2025 |
| 1.2.1-ci.928 | 2 | 10/24/2025 |
| 1.2.1-ci.927 | 2 | 10/24/2025 |
| 1.2.1-ci.926 | 2 | 10/24/2025 |
| 1.2.1-ci.924 | 2 | 10/24/2025 |
| 1.2.1-ci.922 | 1 | 10/24/2025 |
| 1.2.1-ci.921 | 2 | 10/24/2025 |
| 1.2.1-ci.920 | 2 | 10/24/2025 |
| 1.2.1-ci.916 | 1 | 10/24/2025 |
| 1.2.1-ci.915 | 2 | 10/24/2025 |
| 1.2.1-ci.914 | 1 | 10/24/2025 |
| 1.2.1-ci.912 | 2 | 10/24/2025 |
| 1.2.1-ci.909 | 1 | 10/24/2025 |
| 1.2.1-ci.907 | 2 | 10/24/2025 |
| 1.2.1-ci.901 | 1 | 10/24/2025 |
| 1.2.1-ci.900 | 2 | 10/24/2025 |
| 1.2.1-ci.896 | 1 | 10/24/2025 |
| 1.2.1-ci.895 | 1 | 10/24/2025 |
| 1.2.1-ci.891 | 2 | 10/24/2025 |
| 1.2.1-ci.889 | 2 | 10/24/2025 |
| 1.2.1-ci.887 | 2 | 10/24/2025 |
| 1.2.1-ci.884 | 1 | 10/24/2025 |
| 1.2.1-ci.881 | 1 | 10/24/2025 |
| 1.2.1-ci.880 | 1 | 10/24/2025 |
| 1.2.1-ci.878 | 2 | 10/24/2025 |
| 1.2.1-ci.849 | 217 | 10/22/2025 |
| 1.2.1-ci.662 | 1 | 10/20/2025 |
| 1.2.1-ci.661 | 1 | 10/20/2025 |
| 1.2.1-ci.658 | 2 | 10/20/2025 |
| 1.2.1-ci.657 | 2 | 10/20/2025 |
| 1.2.1-ci.656 | 1 | 10/20/2025 |
| 1.2.1-ci.655 | 1 | 10/20/2025 |
| 1.2.1-ci.654 | 2 | 10/20/2025 |
| 1.2.1-ci.653 | 2 | 10/20/2025 |
| 1.2.1-ci.652 | 3 | 10/20/2025 |
| 1.2.1-ci.651 | 2 | 10/20/2025 |
| 1.2.1-ci.650 | 3 | 10/20/2025 |
| 1.2.1-ci.649 | 2 | 10/20/2025 |
| 1.2.1-ci.648 | 2 | 10/20/2025 |
| 1.2.1-ci.647 | 2 | 10/20/2025 |
| 1.2.1-ci.646 | 3 | 10/20/2025 |
| 1.2.1-ci.645 | 1 | 10/20/2025 |
| 1.2.1-ci.644 | 2 | 10/20/2025 |
| 1.2.1-ci.643 | 2 | 10/20/2025 |
| 1.2.1-ci.641 | 1 | 10/20/2025 |
| 1.2.0 | 16 | 10/19/2025 |
| 1.1.1 | 10 | 10/06/2025 |
| 1.1.0 | 115 | 09/25/2025 |
| 1.0.0 | 10 | 10/06/2025 |