ちょっと話題の記事

Vue.jsで作ったゲームをインストール可能(PWA)にしてGitHub Pagesで公開してみた

2020.01.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

おはようございます、加藤です。年末年始は実家の北海道に帰省するつもりだったのですが、見事にインフルエンザB型にかかってしまって、急遽キャンセルしました...
予定が全て吹っ飛んで暇になったので、年末年始は下記の教材を使ってVue.jsを勉強していました。
超Vue JS 2 入門 完全パック - もう他の教材は買わなくてOK! (Vue Router, Vuex含む)
まだ7割しか終わっていないですが、せっかくなので簡単なゲームをインストール可能な状態で作って公開してみました。

新規プロジェクトの場合

Vue CLIで新規プロジェクトを作成する際に、指定する事でPWAとしてプロジェクトをセットアップできます。

npx -p @vue/cli vue create new-project

# Manually select features を選択する
Vue CLI v4.1.2
? Please pick a preset:
  default (babel, eslint)
❯ Manually select features

# Progressive Web App (PWA) Support にチェックを入れる(矢印キーで選択してSpaceキーを押す) 
# Enterを押して進む
? Check the features needed for your project:
 ◉ Babel
 ◯ TypeScript
❯◉ Progressive Web App (PWA) Support
 ◯ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

# [自由] ESLint with error prevention only を選択する
❯ ESLint with error prevention only
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier

# [自由] Lint on save のみにチェックを入れた状態でEnterを押して進む
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◉ Lint on save
 ◯ Lint and fix on commit

# [自由] In package.json を選択する
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
   In dedicated config files
❯  In package.json

# [自由] 今回のプロジェクト設定を保存しないので、N入力して進む
? Save this as a preset for future projects? (y/N) N

cd new-project

既存プロジェクトの場合

既存プロジェクトの場合は、下記のコマンドに従い2つのライブラリをインストールし、1つのファイルを作成します。

cd ${PROJECT_DIR}
npm install register-service-worker
npm install --only=dev @vue/cli-plugin-pwa
touch src/registerServiceWorker.js

src/registerServiceWorker.js

/* eslint-disable no-console */

import { register } from 'register-service-worker'

if (process.env.NODE_ENV === 'production') {
  register(`${process.env.BASE_URL}service-worker.js`, {
    ready () {
      console.log(
        'App is being served from cache by a service worker.\n' +
        'For more details, visit https://goo.gl/AFskqB'
      )
    },
    registered () {
      console.log('Service worker has been registered.')
    },
    cached () {
      console.log('Content has been cached for offline use.')
    },
    updatefound () {
      console.log('New content is downloading.')
    },
    updated () {
      console.log('New content is available; please refresh.')
    },
    offline () {
      console.log('No internet connection found. App is running in offline mode.')
    },
    error (error) {
      console.error('Error during service worker registration:', error)
    }
  })
}

GitHub Pagesで公開する為にVueの出力ディレクトリを変更する

GitHub Pagesはパブリックリポジトリを静的Webサイトホスティングしてくれる機能です。今回は、masterブランチの/docsディレクトリを公開対象に使用するので、Vueの出力ディレクトリをデフォルトの/distから/docsに変更します。 ルートディレクトリに下記のファイルを作成してください。

vue.config.js

module.exports = {
  publicPath: "./",
  assetsDir: "",
  outputDir: "docs",
  devServer: {
    host: "localhost"
  }
};

インストール可能にする為に、Web App Manifestを作成する

インストール可能な状態で公開するには、Web App Manifestを作成する必要があります。JSON形式でファイルを作成します。ブラウザはWeb App Manifestからアイコンやメタデータを取得します。
合わせてアイコンも用意する必要があります。下記の様なアイコン生成も含めてWeb App Manifestを生成してくれるサイトがあるので利用すると簡単にマニフェストとアイコンを作成できます。

App Manifest Generator

Web App Manifestはmanifest.jsonmanifest.webmanifestといった名前で作成します。調べて限りでは最近は前者のmanifest.jsonとしている情報が多かったです。

src/manifest.json

{
  "name": "vue-game-tic-tac-toe",
  "short_name": "tic-tac-toe",
  "icons": [
    {
      "src": "./img/icons/android-chrome-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "./img/icons/android-chrome-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    },
    {
      "src": "./img/icons/apple-touch-icon-60x60.png",
      "sizes": "60x60",
      "type": "image/png"
    },
    {
      "src": "./img/icons/apple-touch-icon-76x76.png",
      "sizes": "76x76",
      "type": "image/png"
    },
    {
      "src": "./img/icons/apple-touch-icon-120x120.png",
      "sizes": "120x120",
      "type": "image/png"
    },
    {
      "src": "./img/icons/apple-touch-icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    },
    {
      "src": "./img/icons/apple-touch-icon-180x180.png",
      "sizes": "180x180",
      "type": "image/png"
    }
  ],
  "start_url": "./index.html",
  "display": "standalone",
  "background_color": "#FFFFFF",
  "theme_color": "#4e342e"
}

用意したアイコンはsrc/img/icons配下に置きます。

ここで注意点です。Web App Manifestに全てのブラウザが対応している訳ではありません、特にiOS Safariが対応していないのがネックです。
この問題に対処する為にPWACompatを使用します。
<head>タグ内に6〜9行目の記述を追加してください。

public/index.html

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <link rel="manifest" href="manifest.webmanifest"/>
  <script async src="https://cdn.jsdelivr.net/npm/pwacompat@2.0.9/pwacompat.min.js"
          integrity="sha384-VcI6S+HIsE80FVM1jgbd6WDFhzKYA0PecD/LcIyMQpT4fMJdijBh0I7Iblaacawc"
          crossorigin="anonymous"></script>
  <title>vue-game-tic-tac-toe</title>
</head>

コンテンツを用意する

今回はこちらのサイトを参考にさせて頂き○☓ゲームを作ってみました。 作成したアプリはこちらに公開しています。

インストール可能か確認するだけならデフォルトのコンテンツのままでOKです。コンテンツを用意したい方はVueを編集してください。

動作確認する

PWAの動作確認はvue-cli-service buildでは行えず、Webサーバーを用意し生成物をデプロイする必要があります。 面倒なので、Web Server for ChromeというChromeのアプリを使用します。 このアプリを使うと指定されたディレクトリをルートしてWebサーバーとして動作してくれます。npm run buildした後に、/docsを対象として選択し表示されるURLへアクセスしてください。

Google ChromeでURLにアクセスし、アドレスバーに+というインストールする為のアイコンが表示されればOKです。実際にインストールも行えます。

Chromeで開発者ツールを開きApplicationタブを開くと、読み込まれたWeb App Manifestの情報が確認できます。

リリースする

まず、リリース用のscriptをpackage.jsonに追加します。 8行目のreleaseの行を追加してください。

package.json

{
  "name": "vue-game-tic-tac-toe",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve --https",
    "build": "vue-cli-service build",
    "release": "npm run build && git add -u docs/* && git commit -m \"release\" && git push"
  },
  "dependencies": {
    "core-js": "^3.4.4",
    "node-sass": "^4.13.0",
    "register-service-worker": "^1.6.2",
    "sass-loader": "^8.0.0",
    "vue": "^2.6.10",
    "vue-toasted": "^1.1.27"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^4.1.0",
    "@vue/cli-plugin-pwa": "^4.1.2",
    "@vue/cli-service": "^4.1.0",
    "vue-template-compiler": "^2.6.10"
  }
}

その後、GitHubにリポジトリを作成しCommit&Pushします。 scriptを作成したのでnpm run releaseでリリースが行えます。リリースしてください。

最後のGitHub Pagesを有効化します。 GitHubリポジトリにアクセスし、SettingsOptionsと選択します。 GitHub Pagesの項目でSourcemaster branch /docs folderに変更します。するとGitHub Pages用のURLが上部に表示されアクセスが可能になります。

URLにアクセスし、インストール可能なWebサイトとして動作すれば完成です!! iOS Safariの場合は下記のように操作する事でインストールが行えます。

Android & Chromeならアクセスすればバナーでインストールするか確認が行われます。

あとがき

作っているのはWebサイトなのにインストール後はネイティブアプリチックになるPWAは凄いですね!今回はデザインなど工夫していないのでネイティブアプリ感はあまり無いですが...
自分が作るようなミニゲームであれば、この構成で十分に要件を満たせそうです!!