メモログ

塵が積もって山とならないメモのログ

PWAのチェックリストを満たす

たいして更新もしない個人のブログで Service Worker とか入れる必要まったくないと思いながらも、Lighthouse の結果を見るたびに「PWAのチェックリストだけ100点に至らない」というなんとも言えないモヤモヤ感があった。別にそんなに大変でもないんだから入れてしまえ、ということでPWAのチェックリストを満たすべく、Service Worker と App manifest に対応しました。

Service Worker をサイトに追加するのはとても簡単で、Service Worker 用のスクリプトファイルを用意して、navigator.servceWoeker.register で読み込むだけ。HTTPSでないといけないとか、スクリプトファイルの置き場所がscopeと異なる場合は Service-Worker-Allowed のヘッダーが必要とか、いろいろ考慮すべきところはあるけれど、Github pagesはHTTPSだし、ファイルもどこにでも置けるので特に気にしなくても大丈夫。

1
2
3
4
5
<script async>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js');
}
</script>

service-worker.js では、今のところ最新10件分のHTMLとfeatured imageに使っているsvgファイルをプリキャッシュするようにした。

最新10件のポストデータを得るのに、まず script ディレクトリに service-worker.js を入れて、generatorを登録。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
hexo.extend.generator.register('service-worker', (locals) => {
const posts = locals.posts.sort('-date').filter(post => post.draft !== true).limit(10).toArray();

const lastUpdated = posts.sort((a, b) => a.updated < b.updated ? 1 : -1 )[0].updated.valueOf();

const precacheList = posts.map(post => post.path);
precacheList.unshift('/');

posts.forEach(post => {
const featuredImage = post.featured && post.featured.image;
if (featuredImage) {
precacheList.push(`/assets/images/${featuredImage}/${featuredImage}.svg`);
}
});

return {
path: 'service-worker.js',
data: {
precacheList: precacheList,
lastUpdated: lastUpdated
},
layout: 'service-worker'
}
});

そのあと theme の layout に service-worker.ejs を追加して、Service Worker のスクリプトファイルを生成。

1
2
3
4
const precacheList = [
<% page.precacheList.forEach(function(item){ %>
'<%- url_for(item) %>',<% }); %>
];

詳細は service-worker.jsservice-worker.ejs を参照。

App Manifest については静的なファイルを用意して、manifestへのリンクを追加しただけ。 theme-color はLight House がそう言ってくるので追加している。

1
2
<link rel="manifest" href="/manifest.json" >
<meta name="theme-color" content="white">

詳細は manifest.json。ただ値を入れるだけではあるけど、スプラッシュスクリーンを有効にするためにいくつか要件があり、それを満たすようにアイコン画像を用意している。

そして Lighthouse の結果。100点になりました👍