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

workbox + webpackでServiceWorkerを使いPWA化してみた

More than 1 year has passed since last update.

PWAとは

Googleの記事によると、

プログレッシブ ウェブアプリはウェブとアプリの両方の利点を兼ね備えたアプリです。ブラウザのタブで表示してすぐに利用することができ、インストールの必要はありません。使い続けてユーザーとの関係性が構築されていくにつれ、より強力なアプリとなります。不安定なネットワークでも迅速に起動し、関連性の高いプッシュ通知を送信することができます。また、ホーム画面にアイコンを表示することができ、トップレベルの全画面表示で読み込むことができます。

つまり、ネイティブアプリのような機能(プッシュ通知やホーム画面にアイコンを表示など)を提供しながらも、通常のWebページ同様ブラウザでアクセスできるアプリケーション

特徴

Googleが提示するPWAの特徴

特徴 必要なもの
オフラインでの動作 ServiceWorker
プッシュ通知 ServiceWorker
ホーム画面追加 Web App Manifest

対応状況(2018/09/20)

Can I Use

ServiceWorker

スクリーンショット 2018-09-20 11.29.06.png

Web App Manifest

スクリーンショット 2018-09-20 11.29.33.png

実現したこと

  • ServiceWorkerを有効に
  • manifest.jsonを設置
  • HTTPS対応

ServiceWorkerを有効に

workbox-sw + webpackで実現

workbox

workbox.png

  • Google製ServiceWorkerのコードを生成を支援してくれるライブラリ
インストール
npm install --save-dev workbox-sw

# webpackでworkboxを使うためにプラグインもインストール
npm install --save-dev workbox-webpack-plugin
webpack
webpack.config.js
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
const dist = __dirname + '/dist'

// webpack config
{
  plugins: [
    // Other webpack plugins...
    new WorkboxWebpackPlugin.GenerateSW({
      globDirectory: dist,
      globPatterns: ['*.{html,js,css}', 'images/**/*.{jpg,jpeg,png,gif,webp,svg}'],
      swDest: dist + '/sw.js',
      clientsClaim: true,
      skipWaiting: true,
    }),
  ]
}
インストールしたworkbox-webpack-pluginをimportし、以下のオプションを設定
  • globDirectory: precache対象とするディレクトリ
  • globPatterns: precache対象とするファイルのパターン
  • swDest: workboxが生成するServiceWorkerのファイルのパス
  • clientsClaim: 最新のサービスワーカーに、アクティブになるとすぐにすべてのクライアントを制御するよう指示
  • skipWaiting: 待機フェーズに入ると最新のServiceWorkerにアクティベーションを指示

ここまではprecacheの設定で、静的なコンテンツを事前にキャッシュさせることができる

runtimeCachingの設定を追加

動的コンテンツはruntimeCachingを行う

GoogleAPIのURLにマッチするurlPatternのときにapiというnameで3日間100件までのデータをキャッシュする例(ステータスコード200の場合のみ)

webpack.config.js
    new WorkboxWebpackPlugin.GenerateSW({
      globDirectory: dist,
      globPatterns: ['*.{html,js,css}', 'images/**/*.{jpg,jpeg,png,gif,webp,svg}'],
      swDest: dist + '/sw.js',
      clientsClaim: true,
      skipWaiting: true,
      runtimeCaching: [
        {
          urlPattern: new RegExp('/'),
          handler: 'staleWhileRevalidate',
        },
        {
          urlPattern: new RegExp('https://www.googleapis.com/'),
          handler: 'cacheFirst',
          options: {
            cacheName: 'api',
            expiration: {
              maxEntries: 100,
              maxAgeSeconds: 72 * 60 * 60
            },
            cacheableResponse: { statuses: [0, 200] },
          }
        },
      ],
    }),
ServiceWorkerを登録
src/index.js
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('./sw.js')
  })
}

manifest.jsonを設置

  • ホーム画面などにWebアプリやサイトを表示する方法を制御し、ユーザが起動できる対象や起動時の見た目(スプラッシュ画面など)を指定できる

manifest.jsonを作成

  • manifest.jsonジェネレータ
    • 512×512の画像をUploadするだけで必要な大きさの画像ファイルをまとめてzipにしてくれるのが便利
  • 192×192のpngアイコンが登録されていないと、Chrome for Androidでホーム画面に追加バナーが表示されない
manifest.json
{
  "name": "test app",
  "short_name": "test app",
  "theme_color": "#3f51b5",
  "background_color": "#ffea00",
  "display": "standalone",
  "Scope": "/",
  "start_url": "/?utm_source=homescreen",
  "icons": [
    {
      "src": "./assets/img/icons/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "./assets/img/icons/icon-96x96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "./assets/img/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    },
    {
      "src": "./assets/img/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "./assets/img/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    },
    {
      "src": "./assets/img/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "./assets/img/icons/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "./assets/img/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "splash_pages": null
}
  • name, short_nameは必須
  • "display": "standalone"でChromeからアドレスバーがなくなりネイティブっぽくなる
  • "start_url"でホーム画面から飛んだときのパラメーターなど設定できる

htmlで読み込み

<head></head>の中で読み込む

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

HTTPS対応

ServiceWorkerを有効にする条件としてHTTPSに対応していなければならない

Netlifyでdeployする

Netlify
スクリーンショット 2018-09-26 14.03.57.png

  • 無料でhttpsでのdeployに対応している
  • Github, GitLab, Bitbucketなどからのdeployが可能

参考:高機能ホスティングサービスNetlifyについて調べて使ってみた

おわりに

  • workboxを使うことでServiceWorker対応を、Netlifyを使うことでhttps化を手軽に行うことができた
  • workboxはwebpushには未対応のためpush通知を利用したければ自分でロジックを書きworkboxで生成されたコードとマージしなければならない

参考
PWA(Progressive Web Apps)と戯れてみる
ServiceWorkerを簡単に書けるworkbox-swの使い方

aaaaayako
フロントエンドエンジニア👩🏻‍💻
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした