初心者でもタグ1つで秒速PWA対応。GUIエディタ(また)作りました。


概要

  1. 前回記事のLGTMとストックありがとうございます!
  2. PWAって便利ですよね。
  3. PWAってなかなか複雑ですよね。
  4. Service Workerとその登録スクリプト、1つにまとまっちゃいました。
  5. manifest.jsonも動的(?)に読み込めますね。
  6. 1行だけソース書けば対応できるようになりそう
  7. できちゃったのでまたエディタつくっちゃいました(こちら)

はじめに

こんにちは。いーちゃんです。
突然ですが、あなたのサイトPWA、対応してますか?
すでに実装している人、これから実装する人、面倒でできていない人など、様々だと思います。
manifestとService Workerを書けば済むんですがそれすらも面倒だと時々思ったり...。
ということでPWA対応を秒でしていきましょう。
(例によって前置きが長いのでエディタを早く使いたい方はこちらへどうぞ)

そもそもPWA(Progressive Web Apps)って何?


(Nuxt.jsのサイトより)
スマートフォンなどでWebページを見ていて、このような「ホーム画面に追加」ボタンを見かけたことはありませんか?
押してみるとあたかも普通のアプリのようにホーム画面に追加されます。サイトによっては、ネットがつながらない環境でも読み込めたりもします。利用者にとっては、いい事づくしです。

この機能を自分のページでも使えるようにするためには、PWA(Progressive Web Apps)に対応させなければなりません。

逆に言えば、この仕様に準拠さえすればブラウザが勝手に追加してくれるので、とても楽です。
...その実装に少し手間がかかったりもするのですが。

PWAは主に、

- Web App Manifest (JSON)
- Service Worker (JavaScript)

の2つで構成されています。それぞれ、

  • Web App Manifest: サイトの名前やアイコンを定義する
  • Service Worker: キャッシュなどの処理を裏でする

という役割です。キャッシュが必要なければService Workerはファイルだけ用意してもいいのかもしれません(未検証)。
しかし、キャッシュの実装はページの2回目以降の読み込みには大きな影響を及ぼしますから、「できることなら実装しておきたい」。そう思いませんか?

Service Workerの実装

Service Workerのキャッシュの仕組み

Service Workerでは主に2回、キャッシュを取るタイミングがあります。それは、

  • はじめにページが開かれた時(=Service Workerをインストールするとき)
  • ファイルを実際に取得する時

です。Service Workerが取得したキャッシュは、ブラウザに保存されています。

Chromeだと、ここで見れたりします。

(Nuxt.jsのサイトより)

そのため、2回目以降はサーバーと通信する必要が(少)なくなるので、ページ読み込み速度が大きく改善するのです。

通信する必要がなくなるかはサイトの仕組み次第ですが。

Service Workerの登録

Service Workerの処理内容を sw.js に記述したとします。そのスクリプトをアプリに関連付けるために、またスクリプトを書きます。

普通なら 単に<script>タグにService Workerを書いたりsrc属性でsw.jsを指定するだけではうまくいかないものです。

HTMLのheadタグに以下を追記します。

<script>
if ("serviceWorker" in navigator) { // 対応ブラウザのみ処理
    navigator.serviceWorker.register("/sw.js");
}
</script>

あら簡単。
ちなみに、この登録用スクリプト自体は<script src="">での指定も可能です。

Web App Manifestには何を書く?

Web App Manifestは、アプリの名前、概要、アイコンなど、アプリ自体の挙動…というよりかは見た目を定義するようなファイルです。規格上 *.webmanifest ファイルへの定義が基本ですが、中身はJSONなので *.json への定義も許可されています。(そのため、以下manifest.jsonと呼ばせてください。)

Chrome等の拡張機能でも同名の manifest.json が用いられますが、定義すべき内容は異なります。

PWAが最低限動作するために必要な定義は、

  • アプリの名前
  • アイコン(1つ以上指定)

です。簡単。
ですが、例えば「PWAからのアクセスは別の処理を」や、「ホーム画面に置くにはアプリ名が長すぎる」など、アプリによっては情報を追記したほうが良いかもしれません。

ということで、基本的にこのようなファイルが作成できます。

{
  "name": "アプリのフルネーム",
  "short_name": "短い名前",
  "description": "アプリの概要",
  "start_url": "/起点URL",
  "theme_color": "#テーマ色",
  "icons": [
    {
      "src": "/アイコン画像のパス",
      "sizes": "192x192"
    }
  ]
}

パスのはじめに/をつけ、絶対パスを指定しています。 manifest.json はサブディレクトリから参照されることも多いので、(個人的には)絶対パスで指定しておくと便利だと思います。

アイコン画像は、最低限192x192を用意しておくことが望ましいでしょう(Googleの方針)。

さらに、テーマ色も定義しておくと、ブラウザによってはいろいろな部分の表示色を変えてくれたりもするので、統一感を出すためにも指定をおすすめします。

なお、これ以外にも様々な設定ができますが、説明は割愛させていただきます。こちらのサイトに詳しい説明がありますので、興味がありましたらこちらも参照してみてください。

manifest.jsonの登録

こちらはlinkタグ1つで登録できます。

<head>
  <link rel="manifest" href="/manifest.json">
</head>

唯一注意点があるとすれば、CSSではないのでrel="manifest"を書くことです。

個人的にはhrefなのかsrcなのかもよく迷いますが。

いざ実装。

こう見るとJavaScript書いてJSON書いて、と(文法似てるけど)なかなか大変ですね。お待たせいたしました。ここでやっと1行実装の登場です。

ということで、またエディタを作りました
(こちら)。

前回の記事をお読み頂いていると察されているかもしれませんが、ソースコードは前回から転用してます。
必須欄を最低限打ち込んでいただければService Workerとmanifest.jsonを勝手に作ります。zipにします。ダウンロードしていただき、<script>タグ1つで動きます。

Service Workerのスクリプトを見ると、「1行実装」できる理由が見つかるかもしれませんね。

エディタ実装について

サーバー構成や言語などは前回と同じなので割愛します。コピーですから。

なんで1行でいいの?

答えは簡単。

  • manifest.jsonの読み込み
  • Service Workerの登録
  • Service Workerの処理

をService Workerのスクリプトに全部まとめちゃったからです。

何ならmanifest.jsonも消せないかな…と思い試しにBLOBのURLを渡してみましたがプロトコルがだめみたいです。難しい。
(Data URLとかならいけたり…?(未検証))

Service WorkerはDOMにアクセスできないので、manifest.jsonの読み込み、Service Workerの登録を1ファイルで..なんて通常ではできません。そのため、

  1. 普通のスクリプトとして呼び出す
  2. manifest.jsonを追加する
  3. Service Workerとして呼び出す
  4. Service Workerとして処理する

という処理をするために、(window.)navigatorの存在で処理を分岐しています。

終わりに

思いつきでService Workerの登録スクリプトと処理スクリプトをまとめてみたら、意外とうまくいっちゃいました。
「思いついたらとりあえずやってみる。」大事なのかもしれませんね。

例によってもう一度URL貼ります。(https://pwa.app.e-chan.cf/)
これまた例によってGitHubも公開しています。スパゲッティーです。

この記事の感想、あるいはご指摘等ありましたらぜひコメントよろしくお願いします!
※特に機能テストが不十分な可能性もあるので...。

ちなみに、私も参加しているOrganization、SGGのLGTMが1000超えしたようです。
いつも閲覧ありがとうございます。
Organizationのページは こちらです。ぜひご覧ください。