Skip to content
This repository was archived by the owner on Jan 19, 2025. It is now read-only.

Commit eca7bdd

Browse files
committed
New post ready 🚀
1 parent 03504e0 commit eca7bdd

File tree

2 files changed

+97
-5
lines changed

2 files changed

+97
-5
lines changed

_drafts/2019-03-15-github-pages-progressive-web-app.md

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ layout: post
33
title: "Transform your Github Pages blog into a Progressive Web App"
44
description: "In this post I will talk about how I transformed my blog on Github Pages and Jekyll into a PWA."
55
date: 2019-03-15
6-
image: /assets/images/posts/XXXXXXXX
6+
image: /assets/images/posts/pwa-logo.jpg
77
tags: [pwa, web development, javascript],
88
comments: true
99
seo:
@@ -32,7 +32,7 @@ What does basically means? PWAs are web application that combine the best of the
3232

3333
Soooo I started to think: "Whoah, I can modify my blog/website to become a PWA, so that I can explore this new technology and I can also have something that 'feels like an app' for my blog!!!".
3434
So how is it possible to transform a site build with Jekyll and published on Github Pages in a basic PWA? In this post I will show you how I did it (and this article is part of the PWA described here).
35-
To create a basic PWA we need 3 things:
35+
To create a basic PWA I need 3 things:
3636

3737
* publish the site on HTTPS
3838
* a [web app manifest](https://developers.google.com/web/fundamentals/web-app-manifest/ "web app manifest")
@@ -46,7 +46,7 @@ To have https on my github pages site I had to do...nothing!!!:tada::tada::tada:
4646

4747
#### Web App Manifest
4848

49-
The [web app manifest](https://developers.google.com/web/fundamentals/web-app-manifest/ "web app manifest") is a JSON file that must be deployed in the root of you we application. This JSON is used by user browser about to get some information about your web application and how it should behave when 'installed' on the user's mobile device or desktop. This manifest is required by Chrome to show the Add to Home Screen prompt.
49+
The [web app manifest](https://developers.google.com/web/fundamentals/web-app-manifest/ "web app manifest") is a JSON file that must be deployed in the root of you web application. This JSON is used by user browser about to get some information about your web application and how it should behave when 'installed' on the user's mobile device or desktop. This manifest is required by Chrome to show the Add to Home Screen prompt.
5050

5151
A typical manifest file includes the following informations:
5252

@@ -134,10 +134,102 @@ A service worker is the heart of a Progressive Web App. Let's see the definition
134134

135135
>A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction. Today, they already include features like push notifications and background sync. In the future, service workers might support other things like periodic sync or geofencing. ... is the ability to intercept and handle network requests, including programmatically managing a cache of responses.
136136
137-
Whoooaaa!!! :open_mouth: Basically service worker let you web app inherit some features that are tipically found only in a native mobile app:
137+
Whoooaaa!!! :open_mouth: Basically service workers let your web app inherit some features that are tipically found only in a native mobile app:
138138

139139
* push notification
140140
* offline support
141141
* background sync
142142

143-
.... (https://developers.google.com/web/fundamentals/primers/service-workers/)
143+
Anyway, there are some particular features of a service worker you must be aware of in order to fully understand how they works:
144+
145+
* you can't access the DOM directly. In order to be able to manipulate the page content, you need to use the worker [postMessage](https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage "worker post message") api and then manipulate the page change the content if needed (using javascript).
146+
* service workers are a programmable network proxy, allowing you to control how network requests from your page are handled.
147+
* service worker don't have a global state, so on each invocation a service worker will not be aware of anything of the previous one (to share data between sessions, you need to use the [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API))
148+
149+
So how do I created the service worker for my blog? I started by adding a `sw.js` file to the root of project. This is the standard position for a service worker source code. Then I added the registration script before the end of the body of my pages. Below you can find the registration script.
150+
151+
```javascript
152+
<script>
153+
if('serviceWorker' in navigator) {
154+
navigator.serviceWorker
155+
.register('/sw.js')
156+
.then(function() { console.log("Service Worker Registered"); });
157+
} else {
158+
console.log('error register service worker')
159+
}
160+
</script>
161+
```
162+
163+
Then I started to write my service worker. To do that, first I studied the lifecycle of a service worker, composed by the following main events:
164+
165+
* `install`, launched when the service worker will be installed
166+
* `activate`, launched just after the installation process has been completed correctly.
167+
* `fetch`, launched on each fetch request executed inside the page
168+
169+
So in the install event I followed the standard approach:
170+
171+
* I opened the cache for my blog pwa with name `chicioCodingCache{% include version.txt %}`, where version.txt is a file that is automatically filled with the latest tag number on each `npm version` execution.
172+
* I added to the cache the files needed to make my pwa works (css and js of the site, and in the future also a HTML scaffolding structure :stuck_out_tongue_winking_eye:).
173+
174+
In the activate event I added a strategy to manage the old caches: I just delete them and I kept only the new one created during the install phase.
175+
Then in the fetch event I decided the cache strategy for all the network request made inside my pages. What I chose is basically to return immediately the element if it is present in the cache while at the same time try to update it in the cache. So the next time the user will see the content updated.
176+
To manage the fact that not all the browsers implement the entire [Service Worker Cache API](https://w3c.github.io/ServiceWorker/#cache-objects "service worker cache api"), I added a polyfill to manage this inconsistency and imported it with the [WebWorker importScripts() api](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/importScripts "webworker import scripts api").
177+
One last note: I had to put the frontmatter header inside the service worker source code file to let jekyll understand that the file that contains the service worker must be processed. Jekyll in this way will add:
178+
179+
* the cache version number as explained above (`version.txt` include file)
180+
* the list of js and css urls to be cached in the install events (I generate this urls lists with a script that extracts them from other Jekyll template files and put them inside `service-worker-home-urls.js`, `service-worker-blog-urls.js` and `service-worker-css-urls.js`)
181+
182+
Below you can find the complete implementation of the service worker.
183+
184+
```javascript
185+
---
186+
---
187+
importScripts('/cache-polyfill.js');
188+
189+
const siteCacheName = 'chicioCodingCache{% include version.txt %}';
190+
const dependenciesUrls = [
191+
"/favicon.ico",
192+
{% include service-worker-home-urls.js %}
193+
{% include service-worker-blog-urls.js %}
194+
{% include service-worker-css-urls.js %}
195+
]
196+
197+
self.addEventListener('install', (event) => {
198+
event.waitUntil(
199+
caches.open(siteCacheName).then((cache) => {
200+
return cache.addAll(dependenciesUrls);
201+
})
202+
);
203+
});
204+
205+
self.addEventListener('activate', (event) => {
206+
event.waitUntil(
207+
caches.keys().then((cacheNames) => {
208+
return Promise.all(
209+
cacheNames.filter((cacheName) => {
210+
return cacheName !== siteCacheName
211+
}).map((cacheName) => {
212+
return caches.delete(cacheName);
213+
})
214+
);
215+
})
216+
);
217+
});
218+
219+
self.addEventListener('fetch', (event) => {
220+
event.respondWith(
221+
caches.open(siteCacheName).then(async (cache) => {
222+
return cache.match(event.request).then((response) => {
223+
return response || fetch(event.request).then((response) => {
224+
cache.put(event.request, response.clone());
225+
return response;
226+
});
227+
});
228+
})
229+
);
230+
});
231+
```
232+
233+
#### Conclusion
234+
By adding all the above implementation my blog is now a Progrssive Web App (that's right, the article you're reading part of a PWA :smirk:). If you want to see the entire source code of my website/blog discussed here you can have a look at [this repository](https://github.com/chicio/chicio.github.io "chicio coding repository").
235+
So now it's time to start to develop you first PWA or transform you website/ web application in PWA. If you want, you could share your experience with me in the comments below :two_hearts:.

_images/posts/pwa-logo.jpg

35.5 KB
Loading

0 commit comments

Comments
 (0)