Nuxt.js PWA のベースアプリを GitHub Pages へデプロイする

Nuxt.js を使うことで手軽に PWA なアプリを作ることができます。そして開発した PWA を世に出すためには、サーバー環境へデプロイする必要があります。Nuxt.js を SPA の JAMStack な作りにしている場合は、ウェブサイトをホスティングできる環境であれば、どこでも大丈夫です。今回は GitHub Pages でホスティングをします。

前回までの実装でNuxt.jsPWAwithTypeScriptができました。アプリとしての機能はまったくないですが、やはりデプロイして実際にスマートフォンからアクセスしてみたいところです。今回は簡単にデプロイできる GitHub Pages でホスティングします。また、一手間かかりますが CircleCI とも連携して、アプリのソース管理とホスティングを同じリポジトリで行い、ソースコードを変更したら自動的にビルド&デプロイする方法も紹介します。

シリーズの記事

環境
本記事の開発環境は以下となります。

GitHub Pages へデプロイ

GitHub Pagesは、ソースコード管理GitのホスティングサービスGitHubが提供する、ウェブサイト・ホスティングの機能です。
ユーザーや組織のウェブサイト、またはアプリなどのプロジェクト・ウェブサイトを公開できます。GitHub Pages はプログラムなどを実行できませんが、静的なサイトを手軽に公開できます。

まず GitHub にホスティング用のリポジトリを作成します。
[リポジトリ名] は、任意の名前です。 (今回はpwa-base-appとしました)
※ プロジェクトサイトを想定しています。ユーザーまたは組織サイト(リポジトリ名がusername.github.ioのパターン)の場合は設定が異なるので各項目で注釈を入れます。ご注意ください。

リポジトリをクローンしてローカルの開発ディレクトリに、アプリのソースをコピーしておきます。

GitHub リポジトリの [Settings] から GitHub Pages を有効にします。

  • [develop] はmaster branchを選択します

nuxt.config.tsに以下の設定を追加します。(必要箇所のみ抜粋)

  • build: publicPathは、CSS や JS などが置かれるディレクトリでデフォルトの_nuxt_始まりが GitHub Pages で使えないため変更します。(_で始まらなければ任意の文字列で大丈夫です)
  • router: baseは、GitHub Pages のプロジェクトサイトがサブパスのリポジトリ名に配置されるので[リポジトリ名]を設定します。
    ※ ユーザーまたは組織サイトの場合はドメイン直下に配置されるためrouter: baseの設定は不要です
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const config: NuxtConfiguration = {
    // ...(省略)

    build: {
    publicPath: '/static/',
    extend(config, ctx) {
    },
    },

    router: {
    base: '/pwa-base-app/'
    },
    }

GitHub Pages デプロイ用のモジュールを導入します。

1
$ yarn add -D gh-pages

※ npm の場合npm i -D gh-pages

デプロイの実行!
以下のコマンドでビルドとデプロイをします。

1
2
$ yarn build
$ yarn gh-pages -d dist -b master -m 'Update Site'

コンソールにPublishedが表示されたら GitHub Pages の設定で表示されていた URL にアクセスします。(ちょっとタイムラグがあるかもしれません。表示されなかったら少し待って再アクセスしてください。)

以上、簡単に GitHub Pages へデプロイでした。
毎回コマンドを打つ必要がありますが、GitHub Pages のリポジトリを用意するだけで簡単にホスティングできます。

CircleCI と連携した自動デプロイ

GitHub Pages へデプロイするのはコマンド1つで簡単ですが、開発中にちょくちょく実行するのは手間です。ソースがプッシュされたら自動でビルドしてデプロイしておいて欲しいです。これは CircleCI と GitHub を連携させることで実現できます。

ちょっと手間がかかりますが、設定を1回するだけで後はリポジトリにプッシュすると自動的にデプロイしておいてくれるので便利です。なにより「常にアクセス可能なプロトタイプ環境」が実現できるのでありがたいです。

CircleCI とは

CircleCIは Continuous Integration and Delivery と、サイトのタイトルにつけている通り CI(Continuous Integration)/CD(Continuous Delivery) の機能を提供するサービスです。
ソースコードの変更を受け、あらかじめ定義されたビルドやテスト、デプロイといったことを自動的に行ってくれます。無料で始められるので、CI/CD の入門や小規模なプロジェクトでも使いやすいですし、大規模なプロジェクトにもしかりと対応してくれます。

GitHub リポジトリにデプロイキーを追加

GitHub に CircleCI からデプロイできるようにデプロイキーを追加します。
まずssh-keygenで、パスフレーズなしの ECDSA キーペア(~/deploy_key~/deploy_key.pub)を作ります。
※ すべての作業が終わったらローカルのキーペアファイルは削除します

1
$ ssh-keygen -t ecdsa-sha2-nistp521 -C "" -f ~/deploy_key

※ ECDSA が使えない場合はssh-keygen -t rsa -b 4096 -C "" -f ~/deploy_key

そして~/deploy_key.pubの内容を、GitHub リポジトリの [Settings] - [Deploy keys] に貼り付けます。

  • [Title] は、あとでわかるようにします。(今回は CircleCI 用なのでCircleCIとしました)
  • [Key] は、~/deploy_key.pubの内容です。
  • [Allow write access]: チェックを付けます。これを忘れると CircleCI からプッシュできません。

追加されたキーのFingerprintをひかえておきます。

プロジェクトの npm スクリプトを設定

プロジェクト直下/package.jsondeployスクリプトを追加します。generateの行末にカンマを忘れないようにします。(scripts のみ抜粋)
これにより先ほどのデプロイコマンドをyarn deployだけで実行できるようになります。[ci skip]は CircleCI を動作させないためのコミットメッセージになります。masterブランチは GitHub Pages の公開用 HTML なので CI は使わないためです。

1
2
3
4
5
6
7
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"deploy": "gh-pages -d dist -b master -m 'Update Site [ci skip]'"
},

CircleCI の設定ファイルを作成

プロジェクト直下に.circleciディレクトリ、そのディレクトリにconfig.ymlファイルを追加します。
/.circleci/config.ymlに以下の部分を環境に合わせて変更したものを書きます。

  • 58行目 [fingerprints]: 上記 GitHub に追加したデプロイキーのFingerprint
  • 64行目 [user.name]: GitHub のmasterブランチへプッシュするユーザーの名前 (コミットログ用、私はCircleCIを使うことが多いです)
  • 65行目 [user.email]: GitHub のmasterブランチへプッシュするユーザーメールアドレス (コミットログ用、自分または開発チームのメーリングリストなど)
  • 21行目 [branches: only]: 後述の開発ブランチ名、今回はdevelopとしました
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    version: 2.1

    executors:
    default:
    working_directory: ~/workspace
    docker:
    - image: circleci/node:12
    environment:
    TZ: /usr/share/zoneinfo/Asia/Tokyo

    commands:
    system_info:
    steps:
    - run:
    name: System information
    command: |
    echo "Node $(node -v)"
    echo "Yarn v$(yarn -v)"
    setup:
    steps:
    - restore_cache:
    name: Restore Yarn Package Cache
    key: yarn-packages-{{ checksum "yarn.lock" }}
    - run:
    name: Setup
    command: yarn install
    - save_cache:
    name: Save Yarn Package Cache
    key: yarn-packages-{{ checksum "yarn.lock" }}
    paths:
    - ~/.cache/yarn

    jobs:
    build:
    executor:
    name: default
    steps:
    - system_info
    - checkout
    - setup
    - run:
    name: Build
    command: yarn build
    - store_artifacts:
    path: dist
    - persist_to_workspace:
    root: ~/workspace
    paths:
    - ./*
    deploy:
    executor:
    name: default
    steps:
    - attach_workspace:
    at: ~/workspace
    - add_ssh_keys:
    fingerprints:
    - "[GitHub に追加したキーの Fingerprint]"
    - run:
    name: Deploy
    command: |
    mkdir -p ~/.ssh
    ssh-keyscan github.com >> ~/.ssh/known_hosts
    git config --global user.name "[your name]"
    git config --global user.email "[email@example.com]"
    yarn deploy

    workflows:
    build-deploy-flow:
    jobs:
    - build:
    filters:
    branches:
    ignore:
    - master
    - deploy:
    requires:
    - build
    filters:
    branches:
    only:
    - [開発ブランチ名]

ちょっと長いですがざっくり以下です。(個々の詳細は、こちらCircleCI を設定する - CircleCIをご確認ください)

  • executorsで、実行環境を定義しています
  • commandsで、再利用可能な実行ステップsystem_infosetupを定義しています
  • jobsで、ワークフローから実行するジョブbuilddeployを定義しています
  • workflowsで、GitHub のブランチに応じて実行するジョブの定義をしています

[開発ブランチ名]にプッシュするとbuildジョブに次いでdeployジョブが実行されます。
buildジョブの中心は、yarn installyarn buildの実行です。
deployジョブの中心は、yarn deployです。

空ブランチへプッシュ

プロジェクトのディレクトリで以下のコマンドを実行します。今回は [ブランチ名] をdevelopとしました。ブランチ名は、先に作成した/.circleci/config.ymlと合わせる必要があります。

1
2
3
4
$ git checkout --orphan [ブランチ名]
$ git add .
$ git commit -m "initial commit"
$ git push -u origin [ブランチ名]

git checkout --orphanは、これまでのブランチとは関係のない空のブランチを作るオプションです。これによりmasterブランチとはつながっていないdevelopの空ブランチが作られます。
ここに開発用のソースをコミットして GitHub へプッシュします。
GitHub でブランチが追加されていることが確認できます。

また [Insights] - [Network] では、masterブランチと途切れてdevelopができていることが確認できます。(masterブランチは GitHub Pages 用で基本的にみることがないので [Settings] - [Branches] からデフォルトをdevelopにしておくと便利です)

CircleCI にプロジェクトを追加

CircleCIhttps://circleci.com/dashboardへ GitHub のアカウントでログインします。
左のメニューから [➕ ADD PROJECTS] を選択します。

リポジトリが列挙されるので、今回のリポジトリ名の横 [Set Up Project] をクリックします。
設定と手順が書かれていますが、設定済みなので [Start building] をクリックします。

ワークフロー画面が表示され、しばらく待つとビルド失敗が表示されます。(デプロイキーを CircleCI に登録していないため)

ワークフロー画面の左メニュー、プロジェクト名横の [⚙] 歯車アイコンをクリックします。
左メニューから [SSH Permissions] を選び、画面右の [Add SSH Key] ボタンをクリックします。
SSH Key 追加ダイアログが表示されるので情報を入力し、[Add SSH Key] ボタンをクリックします。

  • [Hostname]:github.com
  • [Private Key]:~/deploy_keyファイルの内容

再ビルドするので、先ほどのワークフローのビルド失敗画面から [Rerun] - [Rerun from beginning] をクリックします。
(左メニューアイコン2段目の WORKFLOWS です)

以上で自動ビルド&デプロイ、「CI/CD」の完成です!
developブランチへプッシュするたびに CircleCI が自動的にビルドし、GitHub Pages へデプロイしてくれます。

ローカルのキーペアファイルのクリーンアップ

ビルドが通り、GitHub Pages でアプリが見れるようになったらローカルのキーペアファイル~/deploy_key~/deploy_key.pubを削除します。
とくに秘密鍵側~/deploy_keyは、リポジトリに書き込みができてしまうので注意してください。

ソースコード

今回作成した部分までのソースを GitHub へアップしました。
(プロジェクトのソース管理の都合上、リポジトリ名samples-pwa-base-appsourceブランチになります。)
https://github.com/riotz-works/samples-pwa-base-app/tree/0.0.3

GitHub Pages にホスティングもしています。
(公開サイトは1つのため記事公開に合わせて変わり、本記事の内容とは異なります)
https://riotz.works/samples-pwa-base-app/


Nuxt.js アプリを、GitHub Pages へデプロイできるようになりました。
ホスティング先はいろいろ選べますが、小規模で手軽に扱いたい場合は GitHub Pages を使うと簡単です。

今回 CircleCI 連携をしました。今回のようなサンプルアプリでも CI/CD を使うことで簡単にホスティングできるようになるので便利ですし、本格的に使う場合はテストも CI で実行して早期にビルドエラーやテストの失敗を気づけるようにします。

私は CircleCI を好んで使っていますが、他にもさまざまなサービスがあるので環境にあったものを使うとよいでしょう。