Google codelabs中amp-pwa-workbox的教程步驟精簡。javascript
安裝workbox-cli
css
npm install -g workbox-cli
複製代碼
根目錄引入workbox-sw.dev.v2.0.0.js
文件html
新建src/sw.js
,配置service-worker的緩存規則java
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的文件路徑列表git
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
github
在全部html文件添加<amp-install-serviceworker>
來註冊swshell
<amp-install-serviceworker>
AMP組件<script async custom-element="amp-install-serviceworker" src="https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js"></script>
複製代碼
<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
以緩存訪問過的頁面npm
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 運行時json
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
新建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