amp-pwa-workbox
Google codelabs中amp-pwa-workbox的教程步驟精簡。
步驟
-
安裝
workbox-cli
npm install -g workbox-cli 複製程式碼
-
根目錄引入
workbox-sw.dev.v2.0.0.js
檔案 -
新建
src/sw.js
,配置service-worker的快取規則importScripts(`workbox-sw.dev.v2.0.0.js`); const workboxSW = new self.WorkboxSW(); workboxSW.precache([]); //TODO:add more runtime cache logic code 複製程式碼
-
新建
/workbox-cli-config.js
,配置precache的檔案路徑列表module.exports = { "globDirectory": "./", "globPatterns": [ "img/**.*" //TODO:add more file path patterns ], "swSrc": "src/sw.js", "swDest": "service-worker.js", "globIgnores": [ "./workbox-cli-config.js" ] }; 複製程式碼
-
命令列執行
workbox inject:manifest
生成/service-worker.js
-
在所有html檔案新增
<amp-install-serviceworker>
來註冊sw- 引入
<amp-install-serviceworker>
AMP元件
<script async custom-element="amp-install-serviceworker" src="https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js"></script> 複製程式碼
- html檔案中註冊sw
<amp-install-serviceworker src="/service-worker.js" layout="nodisplay" data-iframe-src="/install-service-worker.html"> </amp-install-serviceworker> 複製程式碼
- 新建
/install-service-worker.html
<!doctype html> <html> <head> <title>Installing service worker</title> <script type="text/javascript"> if (`serviceWorker` in navigator) { navigator.serviceWorker.register(`/service-worker.js`) .then(function(reg) { console.log(`SW scope: `, reg.scope); }) .catch(function(err) { console.log(`SW registration failed: `, err); }); }; </script> </head> <body> </body> </html> 複製程式碼
- 引入
-
修改
src/sw.js
以快取訪問過的頁面workboxSW.router.registerRoute(`/*`, args => { // if it is a resource request such as a image if (args.event.request.mode !== `navigate`) { return workboxSW.strategies.cacheFirst().handle(args); } //if it is a navigation request to a new page return workboxSW.strategies.networkFirst().handle(args); }); 複製程式碼
-
修改
src/sw.js
以快取AMP 執行時workboxSW.router.registerRoute(/(.*)cdn.ampproject.org(.*)/, workboxSW.strategies.staleWhileRevalidate() ); 複製程式碼
-
快取一個自定義的離線網頁
- 新建
/offline.html
<!doctype html> <html> <head> <meta charset="utf-8"> <title>The Photo Blog - Offline</title> <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"> </head> <body> <h1>You are Offline</h1> </body> </html> 複製程式碼
- 更新
workbox-cli-config.js
以快取offline.html
"globPatterns": [ "img/**.*", "offline.html" ] 複製程式碼
- 更新
src/sw.js
以處理離線/線上時的網路請求
workboxSW.router.registerRoute(`/*`, args => { if (args.event.request.mode !== `navigate`) { return workboxSW.strategies.cacheFirst().handle(args); } return workboxSW.strategies.networkFirst().handle(args).then(response => { if (!response) { return caches.match(`offline.html`); } return response; }); }); 複製程式碼
- 執行
workbox inject:manifest
來重新生成/service-worker.js
- 新建
-
到app-manifest生成
manifest.json
檔案 -
所有html檔案新增
mainifest
路徑引用<link rel="manifest" href="/manifest.json"> 複製程式碼
-
更新
workbox-cli-config.js
以快取index.html和icons"globPatterns": [ "img/**.*", "offline.html", "index.html", "icons/**.*" ] ... "templatedUrls": { "/": ["index.html"] } 複製程式碼
-
再次執行
workbox inject:manifest
可選1:建立一個app shell
-
新建shell.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="manifest" href="/manifest.json"> <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"> <title>AMP to PWA Demo</title> <style type="text/css"> /* omit */ </style> </head> <body> <header class="header"> <img src="/img/amp_logo_white.svg" width="36" height="36" /> <h1><a href="/">AMP PWA Codelab - PWA</a></h1> </header> <div id="amproot"> <!-- AMP Content should appear here! --> </div> <h2>This is the app shell!</h2> </body> </html> 複製程式碼
-
更新
workbox-cli-config.js
"globPatterns": [ ... "shell.html", "js/app.js" ], 複製程式碼
-
更新
src/sw.js
以讓網頁導航都匹配到/shell.html
workboxSW.router.registerRoute(`/*`, args => { if (args.event.request.mode !== `navigate`) { return workboxSW.strategies.cacheFirst().handle(args); } return caches.match(`/shell.html`, {ignoreSearch: true}); }); 複製程式碼
-
shell.html中引入AMP-Shadow-DOM runtime library和app.js
<!-- Asynchronously load the AMP-Shadow-DOM runtime library. --> <script async src="https://cdn.ampproject.org/shadow-v0.js"></script> ... <script src="/js/app.js" type="text/javascript" defer></script> 複製程式碼
-
app.js中書寫邏輯
class Router { replaceLinks(document) { // TODO replace links } } class AmpPage { constructor(rootElement) { this.rootElement = rootElement; } _fetchDocument(url) {...}; loadDocument(url) { // Add code to load a document and attach to Shadow Root return this._fetchDocument(url).then(document => { // Manipulating the content of the AMP filean // here remove header DOM element const header = document.querySelector(`.header`); header.remove(); window.AMP.attachShadowDoc(this.rootElement, document, url); }); } } const ampReadyPromise = new Promise(resolve => { (window.AMP = window.AMP || []).push(resolve); }); const router = new Router(); // get a reference to the container and URL, and load the AMP page // when ampReadyPromise resolves. const ampRoot = document.querySelector(`#amproot`); const url = document.location.href; const amppage = new AmpPage(ampRoot, router); ampReadyPromise.then(() => { amppage.loadDocument(url); }); 複製程式碼
-
執行
workbox inject:manifest
來更新/service-worker.js