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