iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 23
1
Modern Web

你應該要知道的新一代Web技術---漸進式網頁(PWA)系列 第 29

[Day29] 自動化管理Service Worker(Part2)

繼續昨天「針對不同的URL來路由(Routing)到對應的cache策略」,這裡我要將兩種不同的URL分別存入獨立的sub-cache中。第一個為material design CDN,另一個是從firebase storage取回的圖片URL。

workboxSW.router.registerRoute('https://cdnjs.cloudflare.com/ajax/libs/material-design-lite/1.3.0/material.indigo-pink.min.css', workboxSW.strategies.staleWhileRevalidate({
    cacheName: 'material-css'
}));
workboxSW.router.registerRoute(/.*(?:firebasestorage\.googleapis)\.com.*$/, workboxSW.strategies.staleWhileRevalidate({
    cacheName: 'post-images'
}));

workboxSW.router.registerRoute()的第一個參數除了能輸入正規表示法外,也可以指定輸入「一般的URL字串」,所以這裡將material design CDNURL中有出現firebasestorage.googleapis.com分別加入到material-csspost-images兩個sub-cache中。

記得現在每次更新完程式碼後要執行npm run generate-sw指令將新的Manifest注入到service worker中

除了staleWhileRevalidate的cache策略,另外還有像是cacheFirstcacheOnlynetworkFirst以及networkOnly策略可以使用。

在每個策略中,我們可以針對這個cache去設定一些選項,之前已經示範過設定cacheName了,這裡來看看還可以設定甚麼其他選項:

workboxSW.router.registerRoute(/.*(?:googleapis|gstatic)\.com.*$/, workboxSW.strategies.staleWhileRevalidate({
    cacheName: 'google-fonts',
    cacheExpiration: {
        maxEntries: 3,
        maxAgeSeconds: 60 * 60 * 24 * 30
    }
}));

開始設定googlefonts這個sub-cache的「有效筆數和期限」。這裡我最多只暫存3筆資料,以及有效期限為1個月(以秒數計算)。

來看一下執行結果吧:/images/emoticon/emoticon16.gif

我們可以發現當設定完有效期限後,workbox會自動在indexedDB中新增一個workbox-cache-expiration的table(key為google fonts url,value則是timestamp object)。

我們還有一個URL還沒有進行Routing處理,那就是Firebase RealTime Database API。在原始的sw.js file中,我將從這個API fetch回來的貼文資料暫存到indexedDB中。這裡我就直接依照原本的路由邏輯在新的service worker中添加程式碼:

workboxSW.router.registerRoute('https://trip-diary-f56de.firebaseio.com/posts.json', function(args) {
    return fetch(args.event.request).then(function(res) {
        var clonedRes = res.clone();
        clearAllData('posts').then(function() {
            return clonedRes.json();
        }).then(function(data) {
            for(var key in data) {
                writeData('posts', data[key]);
            }
        });
        return res;
    });
});

workboxSW.router.registerRoute的第2個參數除了使用workbox提供的cache策略外,也可以自己寫一個callback function。這裡workbox會幫我們監聽fetch event並將事件傳入args這個參數中,之後的程式邏輯就跟原本寫在sw.js中相同。


最後,我們來在新的service worker中實作當靜態資源(像是project中的help.html)沒有被暫存時,應該要出現的fallback頁面

非常可惜的是workbox並沒有提供我們簡單的方式來實作fallback頁面,所以這裡必須要自己來撰寫:

workboxSW.router.registerRoute(function(routeData) {
    return (routeData.event.request.headers.get('accept').includes('text/html'));
}, function(args) {
    return caches.match(args.event.request).then(function(response) {
        if(response) {
            return response;
        } else {
            return fetch(args.event.request).then(function(res) {
                return caches.open('dynamic').then(function(cache) {
                    cache.put(args.event.request.url, res.clone());
                    return res;
                })
            }).catch(function(err) {
                return caches.match('/offline.html').then(function(res) {
                    return res;
                });
            });
        }
    })
});

workboxSW.router.registerRoute()的第1個參數也可以輸入一個函式,這個函式主要是去定義我們要Routing的request類型,這裡我設定成只要去路由「headers中的accept欄位是html」的request。

接著第2個參數的函式可以直接依照之前sw.js中fetch event listener的else區塊中程式碼來修改。

cache邏輯基本上都是相同的,首先到cache中尋找有無暫存,有的話則回傳;沒有的話就透過網路去fetch回來,並把結果暫存到dynamic sub-cache中。

如果在cache中沒有暫存且也沒有網路連線的話,就回傳我們預先pre-cache好的offline.html頁面。

來看一下offline畫面的結果吧:

Day29 結束!! /images/emoticon/emoticon02.gif


上一篇
[Day28] 自動化管理Service Worker(Part1)
系列文
你應該要知道的新一代Web技術---漸進式網頁(PWA)29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言