Create a Simple Progressive Web App (PWA)
Prerequisites
- Node.js
- Nodemon
- Express
- Axios
- Async/Await
- https://jsonplaceholder.typicode.com/ (Fake Rest API)
- Chrome Browser
GitHub Link: https://github.com/mp5maker/progresssive-web-app
What should you expect ?
- We will be going through an example using http://localhost:4000/
Why should we use Progressive web app at all ?
- To give an native app experience for tablets and mobile
- Add offline support for the app
- Support for push notification (not covered)
- Many more
Progressive Web App Checklist
- The website needs to be served over https (use ngrok.io if you want to mimic https for development)
- The website can also be served using localhost
- Service worker will not work in http
- App needs to have a manifest file
- App needs to have a working service worker
Content
- Service Worker Communication
- Manifest File
- Service Worker Events
Service Worker Communication
- Service worker [sw.js] has a life cycle that is different than web page
- Therefore, service worker [sw.js] has no access to global “window” object
- Create a separate service worker file [sw.js]
- On the other hand, [main.js] will have the access to “window” object
- We will be registering service worker [sw.js] from [main.js]
- Install few packages
npm init -y
npm install express
npm install --save-dev nodemon
2. Create a folder structure like Fig: 1
3. Simple Node Server (index.js)
- We would be able to see a page in localhost:4000
npm run dev
4. Route “/” => index.html
5. Create main.js inside static folder
- Detect, if the browser supports service worker or not
- Looks for the sw.js
- Generates a list of post
6. Add the simple css
You would able to see something like this
Manifest File
- You can see the properties which are self explanatory
- Check your console and check the
Installability
[Fig: 7], it will ask for the missing pieces - You can always generate manifest.json using manifest generator from other websites or app
- Before generating, make sure you have a logo which is 1:1 ratio and (at least) 512 X 512 pixels in size.
- “start_url” is a string which represents the location when a user taps a icon in mobile or tablets to where should it first go (home screen usually)
- “scope” is a string which restricts navigation to a sub directory of the site
- Therefore, the files needs to available in the following address bar url locations
start url: http://localhost:4000/
manifest url: http://localhost:4000/manifest.jsonSince our scope is "/" all the files needs to be in
http://localhost:4000/other files urls (example): http://localhost:4000/main.js
Console -> Application -> Manifest
Lighthouse
- Go to console then to Lighthouse
- Check mark only the Progressive Web App
- Generate a report
- If there are any issues, fix it accordingly
Service Worker Events
- Since sw.js do not have the access to window object and it runs in a different thread than the main.js, we need to register the sw.js from the main.js
- Inside sw.js, the service worker go through install event
- In install event, we can decide what files we want to cache
- In activate event, usually it is best to remove the previous caches or deprecated ones
- In fetch event, especially for offline app, we can decide how we want to save the response and return the response of the api urls
Now you can see something like these in your chrome browser
Now the native experience for the tablets or mobile is ready but to give offline experience we need to go little deeper.
Common
- Cache list consists of static files
- Static cache version is the key where all the CACHE_LIST will be saved
Install Event
- Inside sw.js, caches which is a global var (readily available)
- If you console.log the caches you will find it has few__proto__ which includes delete, has, keys, match, open
- If you console.log the cache [these is from caches.open] you will find it has few __proto__ which includes add, addAll, delete, keys, match, matchAll, put
- Storing the resources in CACHE_LIST
Activate Event
- Mostly we remove the outdated caches
Fetch Event
- This is where we define how the files are supposed to serve from the cache
const CACHE_LIST = [
"/",
"/index.html",
"/main.js",
"/main.css",
"https://cdnjs.cloudflare.com/ajax/libs/twitter- bootstrap/4.5.3/css/bootstrap.min.css",
"https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.0/axios.js"
];
Cache Only
- We can only serve the CACHE_LIST files
- Show error if the request do not match any files from CACHE_LIST
eg: '/index.html'
Cache then network
- If the request matches the CACHE_LIST respond
- If it is not available in CACHE_LIST, fetch it from the api
- Save the response from the fetch to the CACHE_LIST
- Then return the response
eg: 'https://unpkg.com/axios/dist/axios.min.js'
Network then Cache
- No matter what the request is, first fetch
- If there is a success fetch response, return the response and update the cache
- If there is fetch error, return the response from the cache if the request matches the one of the items in CACHE_LIST
I would use the network then cache over here
Now the app will work offline
Over here as you can see the “/posts/” as well other images files has been cached because of how we setup the fetch event.
Some Caveats
- Debugging process for the service worker is sometimes tedious
- When you refresh the page the new updated sw.js will be installed but it wont be activated. Therefore, you wont be able to see the changes for the new sw.js instantly.
- For this reason you need to close all the current working tabs and open a new tab.
- Alternatively you check mark the updated on reload in service worker console in google chrome
- Also feel free to click Unregister and skipWaiting and see how it works out for you.
- It is also better, to turn off the service worker during development using .env file or process.env.NODE_ENV because it might hamper your other work