Build a PWA using Workbox and Webpack

Build a PWA using Workbox and Webpack

This article will help you transform an app that doesn’t work offline into a PWA that works offline and shows an update available icon. You’ll learn how to precache assets with workbox, handle dynamic caching as well as handle updates to your PWA

This article will help you transform an app that doesn’t work offline into a PWA that works offline and shows an update available icon. You’ll learn how to precache assets with workbox, handle dynamic caching as well as handle updates to your PWA

A Progressive Web App (PWA) is a site that uses modern technology to deliver app-like experiences on the web. It’s an umbrella term for new technologies such as the ‘web app manifest’, ‘service worker’, and more. When joined together, these technologies allow you to deliver fast and engaging user experiences with your website.

This article is a step-by-step tutorial for adding a service worker to an existing one-page website. The service worker will allow you to make your website work offline while also notifying your users of updates to your site. Please note that this is based on a small project that is bundled with Webpack, so we’ll be using the Workbox Webpack plugin (Workbox v4).

Using a tool to generate your service worker is the recommended approach as it lets you manage your cache efficiently. We will be using Workbox — a set of libraries that make it easy to generate your service worker code — to generate our service worker in this tutorial.

Depending on your project, you can use *Workbox *in three different ways:

  1. A command-line interface is available which lets you integrate workbox into any application you have;
  2. A Node.js module is available which lets you integrate workbox into any Node build tool such as gulp or grunt;
  3. A webpack plugin is available which lets you easily integrate with a project that is built with Webpack.

Webpack is a module bundler. To simplify, you can think of it as a tool that manages your JavaScript dependencies. It allows you to import JavaScript code from libraries and bundles your JavaScript together into one or many files.

To get started, clone the following repository on your computer:

git clone [email protected]:jadjoubran/workbox-tutorial-v4.git
cd workbox-tutorial-v4
npm install
npm run dev

Next, navigate to <a href="http://localhost:8080/" target="_blank">http://localhost:8080/</a>. You should be able to see the currency app we’ll be using throughout this tutorial:

‘Currencies’ is a PWA that lists conversion fees of currencies against the Euro (€) currency. (Large preview)

Start With An App Shell

The application shell (or ‘app shell’) is a pattern inspired from Native Apps. It will help give your app a more native look. It simply provides the app with a layout and structure without any data — a transitional screen that is aimed to improve the loading experience of your web app.

Here are some examples of app shells from native apps:

Google Inbox App Shell: A few milliseconds before the emails load into the app shell. (Large preview)

Twitter’s native app on Android: App shell showing navbar, tabs, and loader. (Large preview)

And here are examples of app shells from PWAs:

The app shell of Twitter’s PWA (Large preview)

The app shell of Flipkart’s PWA (Large preview)

Users like the loading experience of app shells because they despise blank screens. A blank screen makes the user feel that the website is not loading. It makes them feel as if the website were stuck.

App shells attempt to paint the navigational structure of the app as soon as possible, such as the navbar, the tab bar as well as a loader signifying that the content you’ve requested is being loaded.

So How Do You Build An App Shell?

The app shell pattern prioritizes the loading of the HTML, CSS and JavaScript that will render first. This means that we need to give those resources full priority, hence you have to inline those assets. So to build an app shell, you simply have to inline the HTML, CSS and JavaScript that are responsible for the app shell. Of course, you should not inline everything but rather stay within a limit of around 30 to 40KB total.

You can see the inlined app shell in the index.html. You can inspect the source code by checking out the index.html file, and you can preview it in the browser by deleting the <main> element in dev tools:

The App Shell that we’re building in this article. (Large preview)

Does It Work Offline?

Let’s simulate going offline! Open DevTools, navigate to the network tab and tick the ‘Offline’ checkbox. When you reload the page, you will see that we will get the browser’s offline page.

The request to the homepage failed so we obviously see this as a result. (Large preview)

That’s because the initial request to / (which will load the index.html file) will fail because the Internet is offline. The only way for us to recover from that request failure is by having a service worker.

Let’s visualize the request without a service worker:

Network request goes from the browser to the Internet and back. (Icons from (Large preview)

A service worker is a programmable network proxy, which means it sits in between your web page and the Internet. This lets you control incoming and outgoing network requests.

Network request gets intercepted by the service worker. (Icons from (Large preview)

This is beneficial because we can now re-route this failed request to the cache (assuming we have the content in the cache).

Network request gets redirected to the cache when it already exists in the cache. (Icons from (Large preview)

A service worker is also a type of Web Worker, meaning that it runs separately from your main page and doesn’t have access to either the window or document object.

Precache The App Shell

In order to make our app work offline, we’re going to start by precaching the app shell.

So let’s start by installing the Webpack Workbox plugin:

npm install --save-dev workbox-webpack-plugin

Then we’re going to open our index.js file and register the service worker:

if ("serviceWorker" in navigator){
window.addEventListener("load", () => {

Next, open the webpack.config.js file and let’s configure the Workbox webpack plugin:

//add at the top
const WorkboxWebpackPlugin = require("workbox-webpack-plugin");

//add inside the plugins array:
plugins: [
, new WorkboxWebpackPlugin.InjectManifest({
  swSrc: "./src/src-sw.js",
  swDest: "sw.js"

This will instruct Workbox to use our ./src/src-sw.js file as a base. The generated file will be called sw.js and will be in the dist folder.

Then create a ./src/src-sw.js file at the root level and write the following inside of it:


Note: The self.__precacheManifest variable will be imported from a file that will be dynamically generated by workbox.

Now you’re ready to build your code with npm run build and Workbox will generate two files inside the dist folder:

  • precache-manifest.66cf63077c7e4a70ba741ee9e6a8da29.js
  • sw.js

The sw.js imports workbox from CDN as well as the precache-manifest.[chunkhash].js.

//precache-manifest.[chunkhash].js file
self.__precacheManifest = (self.__precacheManifest || []).concat([
    "revision": "ba8f7488757693a5a5b1e712ac29cc28",
    "url": "index.html"
    "url": "main.49467c51ac5e0cb2b58e.js"

The precache manifest lists the names of the files that were processed by webpack and that end up in your dist folder. We will use these files to precache them in the browser. This means that when your website loads the first time and registers the service worker, it will cache these assets so that they can be used the next time.

You can also notice that some entries have a ‘revision’ whereas others don’t. That’s because the revision can sometimes be inferred from the chunkhash from the file name. For example, let’s take a closer look at the file name main.49467c51ac5e0cb2b58e.js. It has a revision is in the filename, which is the chunkhash 49467c51ac5e0cb2b58e.

This allows Workbox to understand when your files change so that it only cleans up or updates the files that were changed, rather than dumping all the cache every time you publish a new version of your service worker.

The first time you load the page, the service worker will install. You can see that in DevTools. First, the sw.js file is requested which then requests all the other files. They are clearly marked with the gear icon.

Requests marked with the ⚙️ icon are requests initiated by the service worker. (Large preview)

So Workbox will initialize and it will precache all the files that are in the precache-manifest. It is important to double check that you don’t have any unnecessary files in the precache-manifest file such as .map files or files that are not part of the app shell.

In the network tab, we can see the requests coming from the service worker. And now if you try to go offline, the app shell is already precached so it works even if we’re offline!

API calls fail when we go offline. (Large preview)

Cache Dynamic Routes

Did you notice that when we went offline, the app shell works but not our data? That’s because these API calls are not part of the precached app shell. When there’s no Internet connection, these requests will fail and the user won’t be able to see the currency information.

However, these requests cannot be precached because their value comes from an API. Moreover, when you start having multiple pages, you don’t want to cache all API request in one go. Instead, you want to cache them when the user visits that page.

We call these ‘dynamic data’. They often include API calls as well as images and other assets that are requested when a user does a certain action on your website (e.g. when they browse to a new page).

You can cache these using Workbox’s routing module. Here’s how:

//add in src/src-sw.js
  new workbox.strategies.NetworkFirst({
    cacheName: "currencies",
    plugins: [
      new workbox.expiration.Plugin({
        maxAgeSeconds: 10 * 60 // 10 minutes

This will set up dynamic caching for any request URL that matches the URL <a href="" target="_blank"></a>.

The caching strategy that we used here is called NetworkFirst; there are two other ones that are often used:

  1. CacheFirst
  2. StaleWhileRevalidate

CacheFirst will look for it in the cache first. If it’s not found, then it will get it from the network. StaleWhileRevalidate will go to the network and the cache at the same time. Return the cache’s response to the page (while in the background) it will use the new network response to update the cache for the next time it’s used.

For our use case, we had to go with NetworkFirst because we’re dealing with currency rates that change very often. However, when the user goes offline, we can at least show them the rates as they were 10 minutes ago — that’s why we used the expiration plugin with the maxAgeSeconds set to 10 * 60 seconds.

Manage App Updates

Everytime a user loads your page, the browser will run the navigator.serviceWorker.register code even though the service worker is already installed and running. This allows the browser to detect if there’s a new version of the service worker. When the browser notices that the file has not changed, it just skips the registration call. Once that file changes, the browser understands that there’s a new version of the service worker, thus it installs the new service worker parallel to the currently running service worker.

However, it pauses at the installed/waiting phase because only one service worker can be activated at the same time.

A simplified life cycle of a service worker (Large preview)

Only when all the browser windows controlled by the previous service worker are installed, then it becomes safe for the new service worker to activate.

You can also manually control that by calling skipWaiting() (or self.skipWaiting() since self is the global execution context in the service worker). However, most of the time you should only do that after asking the user if they want to get the latest update.

Thankfully, workbox-window helps us achieve this. It’s a new window library introduced in Workbox v4 that aims at simplifying common tasks on the window’s side.

Let’s start by installing it with the following:

npm install workbox-window 

Next, import Workbox at the top of the file index.js:

import { Workbox } from "workbox-window"; 

Then we’ll replace our registration code with the below:

if ("serviceWorker" in navigator) {
  window.addEventListener("load", () => {
      const wb = new Workbox("/sw.js");


We’ll then find the update button which has the ID app-update and listen for the workbox-waiting event:

//add before the wb.register()
const updateButton = document.querySelector("#app-update");
// Fires when the registered service worker has installed but is waiting to activate.
wb.addEventListener("waiting", event => {
    updateButton.addEventListener("click", () => {
    // Set up a listener that will reload the page as soon as the previously waiting service worker has taken control.
    wb.addEventListener("controlling", event => {

    // Send a message telling the service worker to skip waiting.
    // This will trigger the `controlling` event handler above.
    wb.messageSW({ type: "SKIP_WAITING" });

This code will show the update button when there’s a new update (so when the service worker is in a waiting state) and will send a SKIP_WAITING message to the service worker.

We’ll need update the service worker file and handle the SKIP_WAITING event such that it calls the skipWaiting:

//add in src-sw.js
addEventListener("message", event => {
  if ( && === "SKIP_WAITING") {

Now run npm run dev then reload the page. Go into your code and update the navbar title to “Navbar v2”. Reload the page again, and you should be able to see the update icon.

Wrapping Up

Our website now works offline and is able to tell the user about new updates. Please keep in mind though, that the most important factor when building a PWA is the user experience. Always focus on building experiences that are easy to use by your users. We, as developers, tend to get too excited about technology and often end up forgetting about our users.

If you’d like to take this a step further, you can add a web app manifest which will allow your users to add the site to their home screen. And if you’d like to know more about Workbox, you can find the official documentation on the Workbox website.

Mobile App Development Company India | Ecommerce Web Development Company India

Mobile App Development Company India | Ecommerce Web Development Company India

Best Mobile App Development Company India, WebClues Global is one of the leading web and mobile app development company. Our team offers complete IT solutions including Cross-Platform App Development, CMS & E-Commerce, and UI/UX Design.

We are custom eCommerce Development Company working with all types of industry verticals and providing them end-to-end solutions for their eCommerce store development.

Know more about Top E-Commerce Web Development Company

Hire PHP Developer and Web Developer for your Online Business

Hire PHP Developer and Web Developer for your Online Business

PHP is widely used open-source scripting language it helps in making dynamically easy your websites and web application. Mobiweb Technology is your best technical partner and offering you solution for any kind of website and application...

PHP is widely used open-source scripting language it helps in making dynamically easy your websites and web application. Mobiweb Technology is your best technical partner and offering you solution for any kind of website and application development. To hire PHP developer and web developer at affordable prices contact Mobiweb Technology via [email protected]

Website Development - Top Reasons Why Your Business Need A Creative Website?

Website Development - Top Reasons Why Your Business Need A Creative Website?

Currently, most business owners want a website and expand their business to increase the selling on local to international markets. We give you the top reasons why you need a website.

Most of the entrepreneurs with innovative ideas about start-up businesses are unaware of all the opportunities the internet has for their business.

A major percentage of our population uses the internet to look for local businesses, and if the business does not have a website then most of their potential consumers won’t get to know about the website only. It gets difficult for beginners who have little knowledge about web development this is where the role of web development services comes into the picture. Having a website connects our business to all the parts of the world effortlessly and opens up various new platforms which were not available previously.

The power of a web page is simply incomparable to other expensive methods of advertising like print media. In the era of smartphones, tablets and PCs where everybody is constantly exposed to the internet at every point of life, the competition is brewing like coffee.

Your web page needs to stand out and connect with the consumers, all the web development services can help you to make your website look just as you want it to.

The purpose of your webpage is not only to serve your customer base, but also to attract new customers, so our website needs to be easily accessible and attractive and some of the ways in which a web development company would help you are by.

“The page should be navigable smoothly and effortlessly, and whatever information the customer needs he/she should be able to retrieve it easily through a search box, etc.”

Professional web developers are able to provide these services.

1. Search Engine Optimization
All the websites are competing to be on top of the list of search engine result pages, but only web developers know how to work on this with the help of proper keywords, image optimization, linking, etc.

2. Appropriate Visual Content
It is the need of the hour to provide the customers with relevant visuals to get a proper idea of your business. Hence, we need professional help to balance the text and visuals for your website so that the customer doesn’t get bored beforehand and leave the webpage

3. Online Transaction
Most of the consumers these days prefer cashless and online mode of payment. It becomes more convenient from the sales point of view too to keep a track of online sales records. Web development services ensure that your website has all required mediums for a transaction and also whether all of them are up to date or not.

4. Global Recognition
Once the brand name is out there, it is very important for the website to have a proper connection with the international client base as well as local customers, the format and design of the website helps is doing so.

5. Responsiveness
Anyone could set up an informative website, but to hold the customer’s attention the website also needs to responsive and interactive, Services are provided through which feedback of the customers can be collected and problems can be addressed as well.

6. Reducing Downtime
While the page is being formatted it is unavailable to the customers, this could result in a loss of attention span from many customers. Hence, webmasters make sure that they take as little time as possible to put up new blog posts or advertisements on the website and don’t make the customers wait.

7. Profit-Making Schemes
One of the ways in which our website might earn small profits is by allowing ads. However, it is a tedious job to also block inappropriate content. Web developers allow and block ads accordingly so that the ads don’t take up much space, but also harmlessly add up to the profits.

Read also: PHP Trends: 5 Best Framework For Web Development

The article gives an idea about how it is necessary for a business in the current world to have a webpage, but adding up all the features which would attract customers is not as easy as it looks and which is why web development services to help us.

Source by