Next.jsで作ったブログをAMPとPWAに対応させる

TL;DR

Next.jsのPWA対応というとnext-offlineとかnext-pwaが有名かと思います。しかし、AMPページのキャッシュはこれらがデフォルトで対応していないので、自前でやる必要があります(参考issue)。自分はこの2つのパッケージを使って色々やってて永遠にPWA対応できなかったので、AMPと同時に対応しようとしている人は注意が必要です。

とはいえ、やることはほとんどexample/amp-firstをコピペするだけなのですが...。

publicフォルダの準備

manifest.json

まず、manifest.jsonを用意します。何で用意してもいいですが、必要なものとして以下が挙げられます(参考)。iconとか用意するのはめんどうなので、PWA manifest generatorを使いました。

  • start_url
  • name or shortname
  • icons (192 - 512 px)
  • display

また、このiconはmaskableである必要があるので、Maskable.app Editorで変換した後、"purpose": "any maskable"をiconのプロパティに足します。

とりあえずこのサイトのmanifest.jsonは以下のような感じです。

manifest.json

{
    "name": "illumination-k dev",
    "theme_color": "#f69435",
    "background_color": "#f69435",
    "display": "standalone",
    "start_url": "/",
    "icons": [
        {
            "src": "/icons/icon-192x192.png",
            "sizes": "192x192",
            "type": "image/png",
            "purpose": "any maskable"
        },
        {
            "src": "/icons/icon-256x256.png",
            "sizes": "256x256",
            "type": "image/png",
            "purpose": "any maskable"
        },
        {
            "src": "/icons/icon-384x384.png",
            "sizes": "384x384",
            "type": "image/png",
            "purpose": "any maskable"
        },
        {
            "src": "/icons/icon-512x512.png",
            "sizes": "512x512",
            "type": "image/png",
            "purpose": "any maskable"
        }
    ],
    "short_name": "ik.dev",
    "description": "Homepage of illumination-k"
}

apple touch icon

ここを見てもらったほうが早いですが、PWA対応したいページのヘッダーに

<link rel="apple-touch-icon" href="/icons/icon-192x192.png" />;

を加えておきます。アイコンのサイズは192x192か180x180である必要があります。

serviceworker.js

examples/amp-first/public/serviceworker.jsをコピペしてpublicに置きます。たぶん、だいたいamp-swです。

serviceworker.js

/* global importScripts, AMP_SW */
importScripts('https://cdn.ampproject.org/sw/amp-sw.js')

/*
  This configures the AMP service worker to enhance network resiliency and
  optimizes asset caching. This configuration will:
  - Cache AMP scripts with a stale-while-revalidate strategy for a longer duration
    than the default http response headers indicate.
  - Cache valid visited AMP documents, and serve only in case of flaky network conditions.
  - Cache and serve an offline page.
  - Serve static assets with a cache first strategy.
  Checkout https://github.com/ampproject/amp-sw/ to learn more about how to configure
  asset caching and link prefetching.
*/
AMP_SW.init({
  assetCachingOptions: [
    {
      regexp: /\.(png|jpg|woff2|woff|css|js)/,
      cachingStrategy: 'CACHE_FIRST', // options are NETWORK_FIRST | CACHE_FIRST | STALE_WHILE_REVALIDATE
    },
  ],
  offlinePageOptions: {
    url: '/offline',
    assets: [],
  },
})

serviceworkerのregister

examples/amp-first/public/install-serviceworker.htmlをコピペしてpublicに置きます。

install-serviceworker.html

<!DOCTYPE html>
<title>installing service worker</title>
<script type="text/javascript">
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/serviceworker.js')
  }
</script>

PWA対応したいページでserviceworkerをインストールする

ampではserviceworkerのインストールはamp-install-serviceworkerで行えます。

PWA対応したいコンポーネントのbodyに以下を入れます。

<amp-install-serviceworker
  src="/serviceworker.js"
  data-iframe-src="/install-serviceworker.html"
  layout="nodisplay"
/>;

offlineページの作成

これよくわかってないので後で調べるかもしれませんが、amp-firstの例ではofflineページが準備されています。コピペして置いておきましょう。serviceworkerのofflinePageOptionなんでしょう。

offline.js

import Layout from '../components/Layout'

export const config = { amp: true }

const Home = () => (
  <Layout>
    <h1>Offline</h1>
    <p>Please try again later.</p>
  </Layout>
)

export default Home

結果

以上でPWA対応は完了です。当サイトtopの2020/09/30現在のlighthouse performanceです。

lighthouse-next-blog

ちなみにWordpress時代はこんなんなので、非常に成長していると言えるでしょう。all 100は難しいですね...。

lighthouse-wordpress-top

この記事に関するIssueをGithubで作成する

Read Next