Creating a simple progressive web app from scratch

The earlier post Creating a simple Progressive Web App (PWA) with .Net Core explains the benefits of PWAs and how to use .Net Core and the NuGet package WebEssentials.AspNetCore.PWA to simplify creating a PWA. However, it is easy enough to create a PWA without recourse to any package. This post shows how to create from the ground up the same PWA that was created in the earlier post.

Building your static files

I used the light-weight development environment Visual Studio Code. For this basic app, you will need an index.html file, an images folder, a Json manifest file, and a service worker javascript file. The PWA converts Fahrenheit to Celsius and vice versa.

To start, create an images folder to hold the small image that will appear on the home screen. Images of sizes 192×192 and 512×512 are both needed. These will be referenced in the manifest file, named “manifest-converter.json” . The index.html file contains the Html and javascript logic for converting temperatures. Both the index and manifest files are found at the bottom of this post. The last file you need is your service worker, named “service-worker.js”. This service worker allows the PWA to be installed and to work equally well off-line. You can copy directly the code file found at: to create service-worker.js.

After assembling these files, I used the Visual Studio Code extension Live Server to launch index.html and run the PWA. You now have a complete, working PWA that you can install on any device supporting PWAs.

Running this PWA on a .Net Core site

If you are running a .Net Core site, you can still run this code by placing it in the wwwroot folder. The code will run as static files. Be sure to change the “start_url” in the manifest file and to change the scope of the service worker registration in the index.html file. In my case, the manifest start_url was changed to “/converternonet/index.html” since I put the files in a folder under wwwroot with folder name “converternonet”. The scope became “/converternonet/”.

Index and Manifest sample files


  "name": "Convert Temperatures: Fahrenheit to Celsius",
  "short_name": "temperature converter",
  "description": "Progressive web app for to convert temperatures",
  "icons": [
      "src": "images/fc-192x192.png",
      "sizes": "192x192"
      "src": "images/fc-512x512.png",
      "sizes": "512x512"
  "display": "standalone",
  "start_url": "/converternonet/index.html"



<!DOCTYPE html>

<html lang="en">
    <meta name="viewport" content="width=device-width" />
    <meta name="description" content="Web App to convert Fahrenheit to Censius and Celsius to Fahrenheit" />
    <title>Converts Fahrenheit to Celsius and Celsius to Fahrenheit</title>
    <link rel="manifest" href="manifest-converter.json">
    <link href="service-worker.js">
    <!-- icon in the highest resolution we need it for -->
    <link rel="icon" sizes="192x192" href="images/fc-192x192.png">

    <!-- reuse same icon for Safari -->
    <link rel="apple-touch-icon" href="images/fc-192x192.png">

        /* When the input field receives input, convert the value from fahrenheit to celsius */
        function temperatureConverter(valNum) {
            valNum = parseFloat(valNum);
            result = ((valNum - 32) / 1.8).toFixed(1);
            document.getElementById("inputCelsius").value = result;

        function temperatureConverter2(valNum) {
            valNum = parseFloat(valNum);
            result = ((valNum * 1.8) + 32).toFixed(1);
            document.getElementById("inputFahrenheit").value = result;
        if ('serviceWorker' in navigator) {
            // Register a service worker hosted at the root of the
            // site using a more restrictive scope.
            navigator.serviceWorker.register('service-worker.js', { scope: '/' }).then(function (registration) {
                 console.log('Service worker registration succeeded:', registration);
            }, /*catch*/ function (error) {
                console.log('Service worker registration failed:', error);
        } else {
            console.log('Service workers are not supported.');
        h1 {
            color: #1038cd;
            font-family: Cambria;

        #converter {
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: flex-start;
            margin-left: 20px;
            margin-right: 20px;

            #converter input {
                height: 40px;
                width: 150px;
                font-size: x-large;
                padding-left: 20px;
                padding-right: 20px;

        img {
            padding: 10px;
            margin: 0px;
    <h1>Temperature Converter </h1>
    <div id="converter">

        <label id="lblFahrenheit">F<sup>o</sup></label>
        <input id="inputFahrenheit" type="number" placeholder="Fahrenheit"

        <img src="images/arrows_vertical.gif" alt="arrows to separate Celsius from Fahrenheit" />

        <label id="lblCelsius">C<sup>o</sup></label>
        <input id="inputCelsius" type="number" placeholder="Celsius"



Leave a Reply

Your email address will not be published. Required fields are marked *