PWA for Vue applications: A practical guide
Tags: vue, pwa, cli, cache
Published: 2021-02-23 14:28:08



## Table Of Contents
   * [What is PWA?](#chapter-1)
   * [Fast decoration of your app using PWA Vue CLI plugin](#chapter-2)
   * [Get deeper on caching](#chapter-3)
	   * [How does caching affect "reach offline exprience" of my page?](#chapter-4)
	   * [Customize Vue CLI PWA plugin to support API caching](#chapter-5)

## What is PWA?<a name="#chapter-1"></a>

Consider the PWA as ice toppings that you can add to your Web App. Each topping is different but by blending them together they turn your Web App into one that tastes exactly like a native app. These flavors have always been available, but Google's chefs put them all together in one tray and called them Progressive Web Apps or PWA!
They even introduced the Lighthouse taster that lets us know how well our web app tastes like a PWA (or better yet, how well it tastes like a native App).
Many apps since then have added these toppings or parts of them to their websites. Some of the most famous ones are Spotify, Housing, and Starbox.

**Do you need PWA tray?** 
In order to reply to this question, you need to know more about the toppings available in the PWA tray along with your customers preferences. If your customers don’t like strawberries in their ice cream, why would you pay for one?

-   🍓 Reach  offline  experience: This means your app is available and fast even if the internet connection fails. If your web app is on the intranet, no one will care about this topping. However, people who live in developing countries and users who access your website on their mobile phones may very well value this topping.
    
-   🍯 Installable: Installable apps are'nt just accessible via a URL in the browser, but also  can be  installed on android and  ios  devices.In this case users will click on an icon to open your app instead of writing the URL in the browser. That's it! You don't have to re-write your app in native or electron.
    
-   🍒 Background sync: A Background sync feature lets you defer the actions if the user doesn't have a reliable connection. Imagine that your user fills out a form and presses 'Send'. But there is no connection currently. You don't want his efforts go to waste, so you gather the actions and send it to server as soon as the connection is back.
    
-   🍇 push notification: What do you think about mobile app notifications, especially when they're closed? For instance: when you're watching TV and you're receiving a notification from the twitter app, saying: "Hey, somebody gave you a 👍. If you think it's a good idea to notify your users, then the Push notification feature might suit you.
    

**How much time and effort should I spend on this tray?**
When using PWA plugins, you can dramatically improve your PWA factor within 30 minutes. After that, it gets exponentially harder to make it better.


## Fast decoration of your App using PWA Vue CLI plugin 🍓🍯<a name="#chapter-2"></a>

I hope you already know about  Vue  CLI plugins. But  don't  worry if you don't. They're pretty easy to understand.

> Vue CLI is a npm package you install globally on your computer.
> It lets you set up Vue projects quickly and without headaches.

> Vue CLI Plugins are npm packages you add as dependency to your Vue CLI project,
> They add some features and functionalities to your Vue project quickly and without headaches. 

Here we use @vue/cli-plugin-pwa to add "🍓Reach offine  experience" and "🍯Installable" support to our web app. That’s important to know: you don’t necessarily need a plugin to add  PWA  support, but using a plugin will make this process faster.

**Preparation**
I use a simple Vue CLI project for this article. You can find it [here](https://github.com/pegahsafaie/vue-cli-PWA-plugin) but you can use any other Vue CLI project of your choice. If you don't know how to create a Vue CLI project look at this [link](https://cli.vuejs.org/guide/creating-a-project.html#vue-create).

**Measure the PWA of your webpage before any changes**
Before we make any changes let's see what does Google's taster says about us. I recommend you use Incognito, but Chrome or  Firefox works too.
Before running Lighthouse tests on our web app, you have to deploy your app first:
 - Build your web app in production mode using:
	```console 
	 npm run build
	```
	This command will generate a build directory named (by default) *dist*.
 - To run dist folder locally on a HTTP-server, Install the HTTP-server on your machine:
	```console 
	 npm install -g serve
	```
	Now run the server with placing the build directly(dist) on the server:
	```console 
	 serve -s dist
	```

> During development you'll be able to use service worker through `localhost`, but to deploy it on a site you'll need to have HTTPS setup on your server.

- Open the website in your localhost and go to devTools>Lighthouse. Select the "Progressive Web App" category and press 'Generate new report'. That's what you probably see after some minutes.
![PWA report before applying PWA plugin on my webpage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/glcgsre9aturjp1cmb45.jpg)
	
**Apply PWA Plugin**
If you are using Git, clean your local changes (commit, stash or discard them). This way you are able to see the changes that were added by the plugin.
    
To install and invoke PWA Vue CLI plugin execute this command:
 ```console
 vue add pwa
 ```
 
**Measure Again**
 Build your app again in production mode and deploy it locally. Now we can ask Mr. Taster about the PWA factor.
 ![PWA report before applying PWA plugin on your webpage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oc90scztfk0zi2ozvddz.jpg)
Congrats! It means that your app works offline and you can register it on "App store" or "Google play store". Take a Look at this [article](https://css-tricks.com/how-to-get-a-progressive-web-app-into-the-google-play-store/) on how to get progressive web app into the google play store.


## Get deeper<a name="chapter-3"></a>

When I first applied PWA plugin to my app, I didn't have a good feeling about it. Even after receiving a Lighthouse taster award, My app was performing well without me knowing how. I wasn't even asked to config it during the installation process.

That's because the plugin does not aim to confuse you with PWA concepts but instead applies proven best practices that most web applications should follow. It assumes that if you know a lot about PWA configuration, you'll return to do your customizations.

With this section we go one level deeper to see how these best practices can be customized to meet your needs.

#### How does default caching affect my app? <a name="chapter-4"></a>

As said before, "Reach Offline Experience" on a website means that it is fast and accessible even with an unreliable connection. 
Service Workers are the heart and soul of this feature. A service worker is a script that runs independently from your webpage and acts as an interconnect between your website and network, implementing caching strategies to reduce traffic between the webpage and server.

This diagram below illustrates you how the service worker caches your essential static resources. The essential static resources are the resources that your webpage requires in order to be  initiated. For example html, js,  css  and image files used in your home page are essential resources for your webpage.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/63h0qnc6amnb1d7hpyeg.png)

This process is also logged to your console. Don't be confused with the word workbox. It is a webpack plugin used by your serviceworker to complete the precaching process. Let's learn more about it later on.
![Consolelog shows us how precaching works](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iy95nizybqq1kopmioqw.jpg)

Looking at the application tab of your browser, you see all the precached resources. 
![PWA webpages cache the essential resources. We can see the list in application tab](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8jjqxvjy1rtzkf4j7bp6.jpg)
Caching worked fine. But let's see how does caching affect the speed of your webpage?
When we refresh the page here is what happens:
![How does caching avoid unnecessary network communication](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vaf4mzhigy9rzbh51kup.png)
I refreshed both the PWA and non PWA webpages in 3 different network modes. You can see the differences in network tab in the next pictures:
- Refreshing without throttleing. The PWA webpage reads from the cache while the non PWA webpage downloads all the resources again. Still you don't see a big time difference in load time as the webpage is small and internet connection is pretty good.
![Refresh without throttling](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ruyiopothf9yvicpf2g0.jpg)


- By refreshing with slow 3G the load time difference is 2 times bigger.
![Refresh with slow 3G](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oslklkphjsday9rfwl1v.jpg)

- Rereshing while offline does not load anything for non PWA webpage. The PW webpage on the other hand is loaded smoothly and fast.
![Refresh without connection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/518es4xey52pb2oclrl1.jpg)

As you can see, with a PWA, there isn’t much difference between the three modes. That indicates this website is quite reliable even when the network is not stable.

#### Customize Vue CLI PWA plugin to support API caching<a name="chapter-5"></a>
It's important to know what the PWA plugin does before we customize our application. Once you activate the plugin, it registers serviceworker.js in your main file. Registering serviceworker from the main file means we want serviceworker to get registered as soon as the page loads. Apart from that, PWA plugin does'nt do much more than organizing! Whenever the project is built, the PWA plugin tells Workbox to generate a serviceworker to cache the static resources. Workbox is the heart of caching strategies. Two modules in Workbox webpack plugins are responsible for implementing caching strategy: 'generateSW' and 'InjectManifest'.
We can use 'generateSW' when we don't have any configuration and we just want to precache essential static resources. Otherwise it's necessary to use InjectManifest. You can find more details on workbox webpack plugin [here](https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin).
 
 
![How does PWA plugin add precaching to your project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uqcukqlhw6dj3y0g5dm0.png)

 **Improve Reach offline exprience of your users**

*If you prefer to skip the details and go directly to the code, visit my repository [here](https://github.com/pegahsafaie/vue-cli-PWA-plugin) on github.*

We have seen how does Vue CLI PWA plugin applies precaching to our webpage. Now Let's  improve the project by adding an API request to load some data. It gets an ip address and returns a country name.
![By pressing "show country", an API request will be send to show you country name](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ctcan450s0zpsc8gvy6j.jpg)

- How can I cache the response from my API? Can I rely on the default configuration of the PWA Vue CLI plugin?
Unfortunately no! This time we have to add the caching strategy ourselves.

- How should we start?
First we need to determine our caching strategy. Google offers a list of caching strategies for a quick start called an [offline cookbook](https://web.dev/offline-cookbook/). 
I also made a simple matrix out of these strategies, so it's easier for me to choose what I want.

	|   Updates Frequency / Fallback Support|High    | Low |
	|---|---|---|---|---|
	|   **True**|Network First/Stale While Revalidate   | Cache First |
	|   **False**| Network Only  | Cache Only |

	
	Does my API response update often? No! We always get the same country for the 		same ip.
Does my API need a fallback? Sure. I don't want to enter a risk and not show anything when my cache is empty for the first time.

	So i take [Cache First strategy](https://web.dev/offline-cookbook/#cache-falling-back-to-network) which says:
	> We look in the cache first. If the resource is there we use it. If not, we get it from the network and also update the cache using the response of the network.

- I know my strategy. Where should I put it? 

	> Vue CLI PWA plugin configuration is handled via the `pwa` property of either the `vue.config.js` file, or the `"vue"` field in `package.json`. You can find more details [here](https://cli.vuejs.org/core-plugins/pwa.html#example-configuration) 

	In the previous section, we learned that the Workbox webpack plugin includes two caching modules: 'generateSW' and 'InjectManifest'. To customize our caching strategy, we call 'InjectManifest'. The InjectManifest Module requires a js file which contains our extra scripts or logic. 
```javascript
// Inside vue.config.js
module.exports = {
  // ...other vue-cli plugin options...
  pwa: {
    workboxPluginMode: 'InjectManifest',
    workboxOptions: {
      // swSrc is required in InjectManifest mode.
      swSrc: 'src/service-worker.js',
    }
  }
}
```

- Let's put our new strategy in the src/service-worker.js file. 

```javascript
// inside src/service-worker.js 

// define a prefix for your cache names. It is recommended to use your project name
workbox.core.setCacheNameDetails({prefix:  "simple-vue-project"});

// Start of Precaching##########################
// __precacheManifest is the list of resources you want to precache. This list will be generated and imported automatically by workbox during build time
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
// End of Precaching############################

// Start of CachFirst Strategy##################
// all the api request which matchs the following pattern will use CacheFirst strategy for caching
workbox.routing.registerRoute(
/https:\/\/get\.geojs\.io\/v1\/ip\/country\.json/,
new  workbox.strategies.CacheFirst()
);
// End of CachFirst Strategy####################
```

As you might have noticed, once you switch from 'GenerateSW' mode to 'InvokeManifest' mode, there is no default precaching and everything has to be added by hand to the script.

You might be wondering where the workbox came from. There was no import! Workbox injects the whole library from the official CDN during the build process. Not ideal but quick and easy for our tutorial. More information [here](https://developers.google.com/web/tools/workbox/modules/workbox-sw).

**Test our imporvements**
Let's check the application and network tabs to make sure our code works. As we mentioned earlier: the app must be built and deployed to your localhost.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8f5tfjlj5lgiw9l7hqn9.jpg)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ib9w4pyaxxeo99ste5zj.jpg)
Once you make an API call, The response data will be cached and you can see it in your cache list. Now if you switch to offline mode and call the API again, you will receive the response data from the cache.

Congratulations! Your caching strategy has been customized! Please leave me a comment if you have further questions regarding the customization of your caching strategies😊.