Help us understand the problem. What is going on with this article?

AMPページをPWA化する。AMPでServiceWorkerを使う方法

More than 1 year has passed since last update.

AMP縛りでページ作ったけど、やっぱりPWA化もしたいと思いやってみたらあまりにも簡単にできたので手順を残しておきます。
出来上がったページをLighthouseで計測した結果、PWAの点数は100点満点でした。

TL;DR

AMP(Accelerated Mobile Pages)とは

  • モバイルページを高速化するためのもの
  • 速くするというより遅くしない
  • 詳しくはampproject.orgを見て下さい

PWA(Progressive Web Apps)とは

  • Webとネイティブアプリの良いところを合わせてUXを良くしようとする仕組み
  • オフライン、プッシュ通知、ホーム画面から起動などネイティブアプリっぽいことをWebで実現
  • 詳しくはGoogleのPWAページを見て下さい

AMPの実装

最初にAMPページを用意します。
既に手元にPWA化したいAMPページがある方はここは読み飛ばしてください。
AMPページが無い方は、初めての AMP ページを作成するで作ったAMPページをもとに進めます。
AMP HTML の実装は以下の通りです。
コピペして画像のパスを変更してもらえればAMPページはすぐできます。

index.html
<!doctype html>
<html amp lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello, AMPs</title>
    <link rel="canonical" href="http://example.ampproject.org/article-metadata.html">
    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
    <script type="application/ld+json">
      {
        "@context": "http://schema.org",
        "@type": "NewArticle",
        "headline": "Open-source framework for publishing content",
        "datePublished": "2015-10-07T12:02:41Z",
        "image": [
          "logo.png"
        ]
      }
    </script>
    <style amp-custom>
      /* any custom style goes here */
      body {
        background-color: white;
      }
      amp-img {
        background-color: gray;
        border: 1px solid black;
      }
    </style>
    <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
    <script async src="https://cdn.ampproject.org/v0.js"></script>
  </head>
  <body>
    <h1>Welcome to the mobile web</h1>
    <amp-img src="welcome.png" alt="Welcome" height="400" width="800"></amp-img>
  </body>
</html>

有効なAMPページかテストする

この時点でGitHub PagesやNetlifyにホスティングして、AMPテストページで有効なAMPか確認します。
有効な場合、以下のような画面が表示されます。

スクリーンショット 2018-03-19 00.18.19.png

PWA対応する

AMPページをPWA化していきます。
やることは以下のとおりです。

  • manifest.jsonを用意する
  • Service Workerを導入する

manifest.jsonを用意する

ただのJSONなので手で書いても時間はかかりませんが、はじめて書く方やもっと楽したい人のためにWeb App Manifest Generatorを使います。

https://app-manifest.firebaseapp.com/ にアクセスすると以下の画面に飛びます。

スクリーンショット 2018-03-19 00.35.25.png

各項目についてはGoogleが公開しているウェブアプリ マニフェストを見て下さい

青い「ICON」ボタンをクリックしてホーム画面に使うアイコン画像を選択します。
「GENERATE ZIP」ボタンをクリックしてapp-images.zipというzipファイルをダウンロードします。
このzipファイルにはmanifest.jsonと様々なサイズの画像が梱包されています。
zipを解凍してmanifest.jsonとアイコンの画像をプロジェクト内に置きます。
ダウンロードしたmanifest.jsonは以下のようになっていると思います。
内容を変更する場合は手動で書き直してください。

manifest.json
{
  "name": "AMP PWA Sample App",
  "short_name": "Sample",
  "theme_color": "#2196f3",
  "background_color": "#2196f3",
  "display": "standalone",
  "Scope": "/",
  "start_url": "https://example.com/amp-pwa/",
  "icons": [
    {
      "src": "images/icons/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-96x96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "images/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "splash_pages": null
}

HTMLからmanifest.jsonを読み込む

以下のようにheadタグにmanifest.jsonを読み込む記述を追加します

index.html
<link rel="manifest" href="./manifest.json">

metaタグtheme-colorを設定する

完全なPWAにするにはmanifest.jsonで指定したtheme-colorをHTML内にmetaタグで追加する必要があります。
contentの値はmanifest.jsonで定義したtheme-colorの値に合わせてください。

index.html
<meta name="theme-color" content="#2196f3">

これでmanifest.jsonの用意は完了です。

Service Workerを導入する

Service WorkerについてはService Workerの紹介Service Workerの基本とそれを使ってできることをお読み下さい。

AMPページではJavaScriptの実行に制限がありますが、amp-install-serviceworkerを使うことでService Workerを使うことができます。
また、sw-precacheworkboxでService Workerのコードを簡単に自動生成することができるのでService Workerのための学習は特に必要なく導入が可能です。

amp-install-serviceworkerを使ってService Workerを利用可能にする

AMPページでServiceWorkerを使う場合、amp-install-serviceworkerを使うことになります。
headの中に以下のscriptタグを追加してください。

index.html
<script async custom-element="amp-install-serviceworker"
  src="https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js"></script>

次にbodyの中に以下のamp-install-serviceworkerタグを追加してください。
srcはこの後紹介するService Workerのコードのファイルパスを設定します。
layoutは"nodisplay"を設定します。
data-iframe-srcはGoogle検索からアクセスする際にこの属性が無いとServiceWorkerは正常に動作しません。これについては後述します。
その他の設定値に関してはamp-install-serviceworkerのリファレンスにてご確認ください。

index.html
<amp-install-serviceworker
  src="./sw.js"
  layout="nodisplay"
  data-iframe-src="https://your_site_domain/sw.html">
</amp-install-serviceworker>

data-iframe-srcについて補足します。
Google検索からのアクセスした場合、AMPページはAMP CDNから返されます。このドメインはwww.google.co.jpです。AMPページのURLを見るとわかるのですが、 https://www.google.co.jp/amp/s/your_domain/ となっているはずです。
JavaScriptファイルの取得先のドメインはデプロイした先のドメインです。例えばGitHub Pagesにデプロイしていたらusername.github.ioとなります。
ServiceWorkerの仕様としてJavaScriptファイルが違うドメインの場合、ServiceWorkerへの登録は行なえません。
そのためJavaScriptの取得先と同じドメインにHTMLを用意して、そのHTML内でServiceWorkerへの登録を行います。
data-iframe-srcはそのServiceWorkerの登録を行うHTMLのURLを指定するための属性です。
以下がdata-iframe-srcに指定するHTMLのサンプルです。

sw.html
<!DOCTYPE html>
<html>
  <head>
    <title>installing Service Woker</title>
    <script type="text/javascript">
        if("serviceWorker" in navigator) {
          navigator.serviceWorker.register("/sw.js")
            .then(function(reg){
              console.log('SW scope: ', reg.scope);
            })
            .catch(function(err) {
              console.log('SW registration failed: ', err);
            });
        };
    </script>
  </head>
  <body>
  </body>
</html>

これでAMPページ内でService Workerを使う準備が整いました。

workboxを使ってService Workerのコードを生成する

workboxを使うとService Workerのコードを簡単に生成することができます。

workboxはCLI、node、webpackのいずれかで使うことができます。
今回は最も簡単そうなCLIで使います。CLIで使うにはworkbox-cliを使います。
npmで配布されているので、以下のようにインストールすることも可能ですが、

npm install -g workbox-cli

今回は一度しか使わないためnpxを使って実行します。
npxはグローバルにインストールせずにダウンロードと実行を一発で行ってくれます。

workbox-cliには4つのモードがあります。
* wizard
* generateSW
* injectManifest
* copyLibraries

今回はwizardを使います。4つのモードについて詳しくはworkbox-cliをご確認お願い致します。

npx workbox-cli wizard

実行するといくつか質問が表示されるので、答えていきます。
すべて答えるとworkbox-config.jsというファイルが自動生成されます。
スクリーンショット 2018-03-26 00.15.42.png

自動生成されたworkbox-config.jsはローカルのファイルをキャッシュする設定はwizardで選択するだけで設定できるのですが、今回はampproject.orgのCDNから取得したJSファイルもキャッシュしなければオフライン対応ができません。
そのためworkbox-config.jsを以下のように修正します。

workbox-config.js
module.exports = {
  "globDirectory": ".",
  "globPatterns": [
    "**/*.{png,html,json,js}"
  ],
  "swDest": "sw.js",
  // 以下を手動で追加
  "runtimeCaching": [{
    urlPattern: new RegExp('^https://cdn.ampproject.org'),
    handler: 'staleWhileRevalidate',
    options: {
      cacheableResponse: {
        statuses: [0, 200]
      }
    }
  }]
};

修正したworkbox-config.jsを元にService Workerのコードを生成します。
以下のコマンドを実行してください。

npx workbox-cli generateSW workbox-config.js

コマンドを実行するとプロジェクト直下にsw.jsというファイルができているはずです。
このsw.jsがService Workerのコードです!

プロジェクト構成

ここまでで以下のようなプロジェクトになっているかと思います。

.
├── images
│   └── icons
│       ├── icon-128x128.png
│       ├── icon-144x144.png
│       ├── icon-152x152.png
│       ├── icon-192x192.png
│       ├── icon-384x384.png
│       ├── icon-512x512.png
│       ├── icon-72x72.png
│       └── icon-96x96.png
├── index.html           
├── manifest.json
├── sw.js
├── welcome.png
└── workbox-config.js

Lighthouseで確認する

最後にPWA化できているのか確認してみましょう。
GitHub PagesとかNetlifyなどにホスティングしてLighthouseで確認すると満点に近い点数になってるはずです。
自分はGitHub PagesにホスティングしてChrome DevToolsのAuditsで確認し100点でした。

スクリーンショット 2018-03-19 00.02.19.png

まとめ

参考

最後までお読み頂きありがとうございました。
不備や質問はコメント欄またはTwitterにてお願い致します。

2018/03/26 修正

この記事を最初に書いたときはsw-precacheを使った説明でしたが、開発が止まっているっぽく、後継にあたるworkboxを使った説明に修正しました。

shisama
Node.js Core Collaborator. 関西Node学園Organizer.
https://shisama.dev
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away