DEV Community

Cover image for A simple way to create a PWA with Blazor WebAssembly
Bradley Wells
Bradley Wells

Posted on • Originally published at wellsb.com on

A simple way to create a PWA with Blazor WebAssembly

This tutorial will demonstrate a simple way to create a Progressive Web App (PWA) from your Blazor WebAssembly app. A PWA is an installable web app that works offline and is treated as a first-class citizen on desktop and mobile.

A Working Demo

In this tutorial, I will walk you through the process I used to turn my Blazor FIRE Calculator project into an installable progressive web app.

The complete code for the project is available on GitHub.

A Helpful Nuget Package

Your best friend when trying to convert your Blazor App to a PWA will be Blazor.PWA.MSBuild by SQL-MisterMagoo. At the time of this writing, v1.0.0 was just released, but feel free to install the latest release version. To install the Nuget package, execute the following command in the Package Manager Console.

Install-Package BlazorPWA.MSBuild -Version 1.0.0

Be sure the package is enabled for your project. This will add some hooks to your build process that will generate a manifest.json and ServiceWorker.js files, which are necessary for your PWA to function properly.

That’s it! The project works out of the box with no customization required. Fortunately, if you want to make customizations to your PWA, there are ways.

Customizing PWA

Change PWA Name

The first thing you may want to change is the name of your PWA. There are two names that will be used by your application, a short name and a long name. The short name is the name used in the app launcher once your PWA is installed. The long name is used in the install dialog.

To configure the names for your project, you will set some properties in your projects .csproj file. In my example, I added the following lines to BlazorFireCalculators.csproj.

<PropertyGroup>
    <ManifestShortName>FIRE Calculator</ManifestShortName>
    <ManifestLongName>Blazor FIRE Calculator</ManifestLongName>
</PropertyGroup>

Change Icons

The next thing you may want to change is the icon that accompanies your app. This icon will appear on the install dialog, loading screen, and in the app launcher, so you definitely want it to reflect your brand.

The easiest way to change the icon is to save two new image files in your project's wwwroot folder. One should be named icon-192.png and the other icon-512.png. These files will automatically be discovered during the build process and will be populated in manifest.json.

Auto Update Cache

In my app, I wanted to force BlazorPWA.MSBuild to regenerate the contents of the service worker each time I build the project. This ensures that all required files are automatically added to the cache when I build, even if I add new files between builds.

I also included a versioning system so my app will know to update the cache on remote clients when I push an update upstream. Add these two lines of code to your .csproj file.

<PropertyGroup>
    <ServiceWorkerCacheVersion>1</ServiceWorkerCacheVersion>
    <ServiceWorkerForce>true</ServiceWorkerForce>

    <ManifestShortName>FIRE Calculator</ManifestShortName>
    <ManifestLongName>Blazor FIRE Calculator</ManifestLongName>
</PropertyGroup>

Customize Install Dialog

I also wanted my Blazor application to display an install notification when my PWA app is installable. BlazorPWA.MSBuild automatically includes a notice across the bottom allowing the user to install your application. This default behavior may work for you, but I decided to customize it.

To force your Blazor app to handle displaying a custom alert instead of generating one automatically, add the following line to your . csproj file.

<PropertyGroup>
    <ServiceWorkerCacheVersion>2</ServiceWorkerCacheVersion>
    <ServiceWorkerForce>true</ServiceWorkerForce>

    <ServiceWorkerRegisterInstallableType>installable-blazor</ServiceWorkerRegisterInstallableType>

    <ManifestShortName>FIRE Calculator</ManifestShortName>
    <ManifestLongName>Blazor FIRE Calculator</ManifestLongName>
</PropertyGroup>

Now, open Shared/ MainLayout.razor. By adding a banner to this file, you will ensure that your users will be given the option to install your PWA regardless of which routing endpoint they land on. Here, you will inject a JavaScript Runtime helper in order to tie in to the hooks that are part of the PWA install process.

@inject IJSRuntime JSRuntime

Next, add html code to display some type of banner. Mine is a simple banner with text and two buttons.

@if (Installable)
{
    <div class="row justify-content-center">
        <div class="install-prompt col-sm-8 col-sm-offset-2 col-lg-6 col-lg-offset-3">
            <span>Install app?</span>
            <button class="installButton btn btn-primary" @onclick="@(() => InstallClicked())">Yes</button>
            <button class="cancelButton btn btn-danger" @onclick="@(()=>Installable=false)">No</button>
        </div>
    </div>
}

Note, I am also using the following css styling:

.install-prompt {
    background-color: #54595f;
    color: #fff;
    position: fixed;
    bottom: 0.5rem;
    padding: 0.5rem;
    display: flex;
    font-size: 1.5rem;
    border-radius: .25rem;
    z-index: 99;
}
    .install-prompt .installButton {
        margin-left: auto;
        width: 4em;
    }

    .install-prompt .cancelButton {
        margin-left: 0.3rem;
        width: 4em;
    }

Back in MainLayout.razor , you need to handle the call.

@code
{
    static bool Installable = false;
    static Action OnInstallable;
    protected override void OnInitialized()
    {
        OnInstallable = () => InvokeAsync(StateHasChanged);
    }
    [JSInvokable]
    public static Task PWAInstallable()
    {
        Installable = true;
        OnInstallable.Invoke();
        return Task.CompletedTask;
    }
    ValueTask InstallClicked()
    {
        Installable = false;
        return JSRuntime.InvokeVoidAsync("BlazorPWA.installPWA");
    }
}

First, you define the Installable bool, which is used to either show or hide the notice. Then, define a delegate OnInstallable that will inform the application to refresh the UI.

By default, the BlazorPWA.MSBuild tool looks for an invokable method called PWAInstallable to trigger adding the install dialog to the UI, so I went ahead and used that method name.

Finally, I wrote a method to handle the Install button’s OnClick event. This method uses the JS Runtime you previously injected to execute a function that is automatically generated by BlazorPWA.MSBuild and defined in ServerWorkerRegister.js Complete code for MainLayout.razor is on GitHub.

The Bottom Line

Converting your Blazor WebAssembly app into a full-fledged Progressive Web App is simple! This tutorial helped you set up service worker caching and it demonstrated some useful customizations for handling PWA calls in your app. By following this tutorial and creating a PWA in Blazor, you have created an app that can be installed to your desktop or mobile system. It can be launched from the app launcher, it will work offline, and it can receive updates just like any other app on your client’s device. The source code for the entire project is on GitHub, and a demo is available for you to test.

Source

Top comments (6)

Collapse
 
mistermag00 profile image
ℳisterℳagoo #Blazor

Nice write-up, thanks Bradley.

In my own application, I use this to keep the browser cache version in sync with my application version.

<ServiceWorkerCacheVersion Condition="'$(Configuration)' == 'Release'">$(Version)</ServiceWorkerCacheVersion>

Collapse
 
fakhrulhilal profile image
Fakhrulhilal M

Does it mean, whenever you publish the new version to the web server, then all installed/cached version will be updated to the latest version again?

Collapse
 
bradwellsb profile image
Bradley Wells

Clever! Great tip 👍

Collapse
 
noahhornak profile image
noah-hornak

Thanks for the very cool article. I'm very excited about Blazor and being able to build a PWA with just .NET. But what is your opinion on using Blazor Server Side or the Blazor client side version that's expected to release at next MSBuild? Do you think that the client side version will be better suited for building PWAs or what would be your thought process for deciding whether to use server side or client side Blazor?

Collapse
 
bradwellsb profile image
Bradley Wells

Hey Noah, there was a graphic one of the presenters shared at .NET Conf 2019 that I thought was helpful when deciding between client-side and server-side Blazor. I'll leave it here:

Collapse
 
xarala221 profile image
Ousseynou Diop

Interesting article, thank you for sharing.