This is example app for enriching with PWA technology creating for the PWA Workship during Amsterdam JSNation Conference 2018
- Node with npm installed
- Your favorite editor/IDE capable of working with JS code
- Chrome browser
- A smartphone (IPhone users have to add to homescreen manually)
Please follow these steps to get the example app running on your machine.
git clone https://github.com/xebia/pwa-workshop.git
cd pwa-workshop
npm install
npm start
Open up chrome at http://localhost:8080
Then in new console run
npm run expose
This starts a tunnel with https
to make it easy to open the app on your mobile phone. Open your phones browser at
https://{some-hash}.ngrok.io
If you see the static (non-progressive) website on your phone, you are ready to start the workshop! :D
Running npm start
serves the current directory. There is no build step.
Running npm run start:random
starts the same server, but serves random news. This is useful for demonstrating news is
updated in the background in Bonus Step 4
.
The solutions/
directory contains the answers for the exercises. Use this if you did not finish the exercise in
time.
index.html
is a bootstrap.css based responsive webpage
server.js
serves the current directory and proxies all other calls to an
unofficial hacker news API. The browser caching of this API is disabled to
make it useful to cache with a service worker.
main.js
makes a call to /news
and puts this on the page using a simple .innerHTML
call.
The instructor-scripts/
directory contains scripts making it easier to update all steps. This is only needed for
instructors developing this workshop.
- Open Developer Tools and go to the
Audit
tab. - Press
Perform an audit...
and press Run audit. For this workshop you only need to run the PWA tests.
We want to add icons and a splashscreen to our app. A generator can automatically create the required resources and provide the required code.
- Go to the online favicon generator and generate an icon bundle. Use the
provided icon
icon.png
. - Extract the generated files in the project folder.
- Add the generated html snippet to the head of
index.html
. - Set the
name
,short_name
andstart_url
(= "/"
) properties insite.webmanifest
. - Verify the fields in the manifest section of the
application
tab in the chrome devtools. Note theadd to homescreen
link doesn't work yet. - Run a lighthouse check and verify there are no manifest related errors.
- Check out the user experience of adding the app on the homescreen of your phone, by choosing "Add to Home screen"
from the browser's menu. There will not be an
app install banner
yet, but you can add the app manually to your homescreen. - Remove the app from your homescreen again.
We're going to use the workbox-cli to generate a service worker which will precache all requied static resources on installation. workbox-cli will automatically put hashes of the files in the service worker file.
- Add this code to the end of the
<main>
section ofindex.html
.<script> // Check that service workers are registered if ('serviceWorker' in navigator) { // Use the window load event to keep the page load performant window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js'); }); } </script>
- Create a file called sw-src.js with these contents:
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.2.0/workbox-sw.js'); workbox.precaching.precacheAndRoute([]);
- Run
npm i -D workbox-cli
to add workbox command line tools to yourdevDependencies
. - Run
./node_modules/.bin/workbox wizard --injectManifest
. And manually choose.
as the root of your web app. Let the wizard cache all files, by pressingreturn
(space
allows you to unselect and select file types), and let it usesw-src.js
as a source of your service worker to generatesw.js
. - Add a npm script called
generate-sw
to yourpackage.json
which runsworkbox injectManifest
. - Run
npm run generate-sw
. - Check out the chrome devtools console to see the workbox debug output. Also see the service worker installed in the
service worker
section of theapplication
tab in the devtools. - Run lighthouse on your ngrok https url and verify you score 91 points for progressive web app! (At the time of writing it falsely says no redirect is done to https, see GoogleChrome/lighthouse#2383)
- Make a change to
index.html
. See how it is not being picked up by refreshing. Runnpm run generate-sw
again and refresh the page. The change is still not picked up, but the new service worker is shown aswaiting to activate
in theapplication
->service worker
devtools section. Close all tabs of the app and re-open them to start using the new service worker. This is how users update to the new version of the service worker. - Make a change to
index.html
again and rungenerate-sw
again. Now update the service worker by using theskip waiting
link in the service worker devtools section or by clicking theUpdate on reload
checkbox. Refresh the page to see the change. This is how to update the service worker while developing.
Important note: Run npm run generate-sw
every time you make a change to a cached resource. Otherwise changes are not
being picked up anymore, not even after a hard refresh. It's also a good idea to manually unregister the service worker
after you have finished this workshop. Making changes with service workers take some time getting used to.
Although the app is installable and will load while offline it won't show news while offline. Instead it will show
Network error while loading news
. Browser caching would work for this use case, but we want control over the cache on
the client. For example we want to be able to use a stale while revalidate
caching strategy in the next exercise.
Therefore we are going to leverage runtime caching in our workbox serviceworker.
- Add this code to
sw-src.js
workbox.routing.registerRoute( '/news', workbox.strategies.networkFirst() );
- Regenerate the service worker with
generate-sw
- Check the chrome devtools console to verify that workbox is responding to
/news
. - Check the chrome devtools network tab to verify
/news
is fetched by the service worker. - Open the cache section of the
application
tab of the chrome devtools. Find theprecache
and theruntime
cache. Find the news data in the runtime cache. - Try loading the web app while offline, by ticking the
Offline
box underApplication
->Service Workers
. It should show the previously fetched news!
If you completed the previous exercises your app works great while offline and online. However, when your network is slow the screen will remain empty while the news is loading. This can be solved by displaying the cached version before the network call is completed. The service worker will still do the network call in the background. When a server response is returned it will be cached and workbox will broadcast a message notifying the app that the news was updated. The app can now refresh the news page by retrieving it from the cache.
- Kill (
ctrl+c
) the server and start a different server usingnpm run start:random
. This ensures that workbox always has a cache update to broadcast. Otherwise not all of your code will run. - Use the
staleWhileRevalidate
caching strategy together with thebroadcastUpdate
plugin. Read this guide which explains how to do this. You need to updatemain.js
to update the view when the cache was updated. - Note that the user experience suffers when the entire list of news is suddenly replaced. Make it possible for the user to chose whether to update or not by adding a "update news" button. The button should only be displayed when the cache was updated.
We only have a couple lines of code in our application, however we're not getting a 100 points on the performance audit of lighthouse. Extract the critical CSS from bootstrap.css and inline it in the html to improve the performance. See if you can get 100 points.