PWA Night CONFERENCE 2020 に行って、ampproject/amp-sw: A drop in service worker library to help your AMP pages gain network resiliency in 1 line の存在を知りました。
興味を持ったので、サンプルページを実装してみました。
実装時に気づいたことを記載します。
作成したページ
作成したページは以下になります。
ファイル構成
以下のファイルをサンプルとして作成しました。
amp-soundcloud で soundcloud で公開されている曲をページに埋め込んでいます。
ファイル名 | 内容 |
---|---|
index.html | INDEX AMPページ |
index2.html | INDEX AMPページからリンクしているAMPページ |
offline.html | オフライン時に表示するページ |
serviceworker.html | ServiceWorkerを読み込むIframeページ |
sw.js | ServiceWorker |
AMP ページで ServiceWorker を使用するための実装内容
AMP ページで ServiceWorker を使用するための実装内容を説明します。
index.html
index.html内の実装について説明します。
-
metaタグ内に、以下のスクリプトを記載する。
<script async custom-element="amp-install-serviceworker" src="https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js"></script>
-
amp-install-serviceworker タグで、ServiceWorker の JavaScript と、Iframeを指定する
<amp-install-serviceworker src="/amppwa/sw.js" data-iframe-src="https://examples.monotalk.xyz/amppwa/serviceworker.html" layout="nodisplay"> </amp-install-serviceworker>
serviceworker.html
serviceworker.html の実装は以下の通りです。
<!doctype html>
<html>
<head>
<title>installing service worker</title>
<script type="text/javascript">
var swsource = "https://examples.monotalk.xyz/amppwa/sw.js";
if("serviceWorker" in navigator) {
navigator.serviceWorker.register(swsource).then(function(reg){
console.log('ServiceWorker scope: ', reg.scope);
}).catch(function(err) {
console.log('ServiceWorker registration failed: ', err);
});
};
</script>
</head>
<body>
</body>
</html>
var swsource = "https://examples.monotalk.xyz/amppwa/sw.js";
では自サイトのServiceWorkerのパスを指定する必要があります。
sw.js
sw.js
は以下の実装を行いました。
importScripts('https://cdn.ampproject.org/sw/amp-sw.js');
AMP_SW.init({
linkPrefetchOptions: {
maxAgeSecondsInCache: 1000
},
offlinePageOptions: {
url: '/amppwa/offline.html',
assets: [],
}
});
最小限の実装1line
の場合は以下のようになります。
importScripts('https://cdn.ampproject.org/sw/amp-sw.js');
AMP_SW.init();
amp-sw の挙動について
amp-sw
のソースと、README.md
、実際の動作から どのような挙動をするのか確認してみました。
以下、気づいたことを記載します。
ユースケースについて
以下は、README.md
に記載されていました。
-
httpレスポンスヘッダの設定よりも長い期間、
stale-while-revalidate
でAMPスクリプトをキャッシュする。 -
有効な表示済みのAMPドキュメントをキャッシュし、不安定なネットワーク状態の場合にのみ表示する。
-
指定したCache戦略でページにとって重要なアセットをキャッシュする。
-
ユーザーアクセスしたことのないページに移動したときのために、オフラインページをキャッシュする。
-
AMPページからの発信リンクをprefetchする。
5つのモジュールに分かれている
以下、5つのモジュールに分かれています。
-
AMP caching module
AMP の JavaScript 等のリソースをcacheするモジュールです。 -
Document caching module
AMP の HTML をcacheするモジュールです。 -
Asset caching module
画像/フォントなどの静的アセットをcacheするモジュールです。 -
Offline page module
表示したことのないページをオフライン時に表示した際、offline用のHTMLを表示するモジュールです。 -
Link prefetch module
link rel=prefetch
をサポートしないブラウザにプリフェッチ機能を提供するモジュールです。
AMPのページは、Cacheされると、link rel=prefetch
の記述は削除されてしまいます。
CacheされたHTMLでもprefetchの機能を実現するために提供されていると考えられます。
AMP_SW.init() の実装
AMP_SW.init() のソースは以下になります。
function init(config: ServiceWorkerConfiguration = {}) {
ampCachingModule.init();
let fallbackOfflinePageUrl;
if (config.offlinePageOptions) {
fallbackOfflinePageUrl = config.offlinePageOptions.url;
}
const navRoute = documentCachingModule.init(
config.documentCachingOptions,
fallbackOfflinePageUrl,
);
if (config.assetCachingOptions) {
import(/* webpackChunkName: "optional-modules" */ '../asset-caching/index').then(
async ({ AssetCachingAmpModule }) => {
const assetCachingModule = new AssetCachingAmpModule();
await assetCachingModule.init(
config.assetCachingOptions as AssetCachingOptions,
);
},
);
}
if (config.linkPrefetchOptions) {
import(/* webpackChunkName: "optional-modules" */ '../link-prefetch/index').then(
async ({ LinkPrefetchAmpModule }) => {
const linkPrefetchModule = new LinkPrefetchAmpModule();
await linkPrefetchModule.init(
config.linkPrefetchOptions as LinkPrefetchOptions,
navRoute,
);
},
);
}
if (config.offlinePageOptions) {
import(/* webpackChunkName: "optional-modules" */ '../offline-page/index').then(
async ({ OfflinePageAmpSwModule }) => {
const offlinePageModule = new OfflinePageAmpSwModule();
const offlinePageConfig: OfflinePageOptions = config.offlinePageOptions as OfflinePageOptions;
await offlinePageModule.init(
offlinePageConfig.url,
offlinePageConfig.assets,
);
},
);
}
// Taking over the document
self.addEventListener('install', function(e: ExtendableEvent) {
const { skipWaiting } = self as ServiceWorkerGlobalScope;
e.waitUntil(skipWaiting());
});
self.addEventListener('activate', async (e: ExtendableEvent) => {
const { clients } = self as ServiceWorkerGlobalScope;
e.waitUntil(
clients.claim().then(async () => {
// Cache current document if its AMP.
const windowClients = await clients.matchAll({ type: 'window' });
return Promise.all(
documentCachingModule.cacheAMPDocument(windowClients),
);
}),
);
});
}
ソースを見る限り、以下のモジュールはデフォルトで動作します。
- AMP caching module
- Document caching module
以下はオプション指定により動作します。
- Asset caching module
- Offline page module
- Link prefetch module
サンプルを動かして気づいたこと
-
AMP というプレフィックスがついたCacheが作られる
それぞれのモジュールに対応するAMPというプレフィックスがついた名前でCacheが作られます。
-
Link prefetch module は動作しない?
data-rel='prefetch'
をつけたリンクをCache してくれるようなのですが、特に動作している雰囲気はありませんでした。
Google に Cacheされたページの場合動作するのかもしれません。
参考
以下、参考にした記事になります。
offline用のページを用意する発想はなかったのですが、アクセシビリティ観点でも有用に思いました。
自サイトのPWAに別途組み込んで見ようかと思います。
以上です。
コメント