Nuxt.js+Firebase HostingのサイトをPWA化してLighthouseで(ほぼ)100点満点を目指す

1年くらい前に仕事でNuxt.jsをいじる機会があったんだけどそれ以来使ってなかった。

ただ、GW中にNuxt tech bookを読んだところ久々にいじりたくなってしまい。

そこでちょうどFirebase HostingとPWA化に関して調べてたとこだったので、Nuxt.jsのサイトをPWA化してFirebase Hostingで動かす手慣らしでもしておこうかと思いやってみた。

ただ、普通にやっても面白くないので一応Lighthouseのスコアを満点にすることを目指してみることにした。

コンテンツはNuxtのスターターキットの初期生成されるページ。このページを対象に行う。

以下、Firebase Hostingの設定・Nuxtのプロジェクト作成・PWA設定・Lighthouseのスコア上げの流れで説明してます。

一応ソースはこちらで。

FIrebase Hostingのプロジェクトを作成する

Firebase Hostingを利用するためにまずはプロジェクトを作成する。

上記のリンクにアクセスして「プロジェクトを追加」から適当な名前のプロジェクトを作成しておく。

以下、「firebase-sample」というプロジェクト名を付けたとして話を進める。

firebase-toolsをインストール

firebaseの操作をcli上からするツールを入れる必要があるのでインストールする。

npm install -g firebase-tools

Nuxt.jsのプロジェクトを作成する

今回はvue-initコマンドを利用して、Nuxt.jsのスターターキットを利用する。色々聞かれるが全部エンターでok。

vue init nuxt-community/starter-template firebase-sample

そんでpackageのインストールを行う。

cd firebase-sample
npm install # Or yarn

とりあえずこれでサーバーが立ち上がるのでhttp://localhost:3000にアクセスしてみる。

npm run dev

この画面が出れば成功。

f:id:razokulover:20180502154145p:plain

デプロイする

Firebase Hostingにデプロイするために下記のjsonをfirebase.jsonとしてpackage.jsonと同じ階層に設置する。

{
  "hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  }
}

ソースのビルドを行う。この時dist/配下にファイルが生成される。

npm run generate

firebaseのプロジェクトを登録する。

firebase use --add firebase-sample

これでデプロイできる。

firebase deploy

うまくいくと、こんな感じのURLでアクセスできるようになる。

Lighthouse

Lighthouseはウェブアプリのパフォーマンスを簡単に計測するためのツール。

とりあえず、入れていない人は下記のリンクからChromeのエクステンションを入れる。

まずは先ほどデプロイしたページのデフォルト状態でのスコアを見てみる。

f:id:razokulover:20180502160504p:plain

パフォーマンスは静的ファイルなので97点で良いとして、PWAが低すぎる。

なのでまずはPWA対応をする。

PWA対応

Nuxt.jsでPWA対応するのはくそ簡単。

なぜならNuxt.js公式でPWA用のモジュールを出してるから。

なので、やることはパッケージをインストールして、

yarn add @nuxtjs/pwa

nuxt.config.jsにモジュールの利用を追記して、

{
    modules: [
        '@nuxtjs/pwa',
    ]
}

static/icon.png(512x512以上)のアイコンを追加して、

.gitignoreに下記を追記すればok。

sw.*

これでまたビルドしてデプロイしてみる。

npm run generate
firebase deploy

結果は、

f:id:razokulover:20180502161736p:plain

PerformanceとBest Practice以外は満点。あと少し。

Best Practicesの満点を狙う

f:id:razokulover:20180502161904p:plain

この2つのエラーをどうにかする必要がある。

  • Does not open external anchors using rel="noopener"
  • Manifest's short_name will be truncated when displayed on homescreen
Does not open external anchors using rel="noopener"

このエラーは「target="_blank"がついているリンクはrel="noopener"を付けた方がよりセキュアになるよ」というエラーなので当該リンクにrel="noopener"をつければok。

ソースコード的にはpages/index.vueのaタグに対してrel="noopener"を付与すればおわり。

Manifest's short_name will be truncated when displayed on homescreen

これはスマホでホームスクリーンに追加した際にタイトルが12文字を超えていると省略されちゃうから短い名前にしろっていうエラー。

なのでnuxt.config.jsに適当なshort_nameを設定すれば解決。

{
  manifest: {
      "short_name": "testapp"
  }
}

これでビルドしてデプロイしてスコアをみてみると、

f:id:razokulover:20180502162846p:plain

Performance以外はすべて100点になった。

Performance

Performanceの項目は97点なんだけど、これ以上コンテンツを変えずに改善しようとしても無理っぽかったので諦めた。

阿部寛のホームページでもPerformanceが94点なのでまぁ許容してくれ。

[追記] CircleCIでGitHubへのpushをフックに自動デプロイをさせる

firebaseにデプロイするためのトークンを取得する

firebase login:ci

.circleci/config.ymlを作成し、下記のような感じのファイルを作る。

version: 2
jobs:
  build:
    working_directory: ~/repo
    docker:
      - image: circleci/node:8.9.4
    steps:
      - checkout
      - run:
          name: Install firebase-tools
          command: |
            curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
            sudo apt-get install -y nodejs
            echo prefix=${HOME}/.local >> ~/.npmrc
            npm install -g firebase-tools
      - restore_cache:
          keys:
          - v1-dependencies-{{ checksum "package.json" }}
          - v1-dependencies-
      - run: npm install
      - save_cache:
          paths:
            - node_modules
          key: v1-dependencies-{{ checksum "package.json" }}
      - run:
          name: Build
          command: npm run generate
      - run:
          name: Deploy
          command: ~/.local/bin/firebase deploy --token $FIREBASE_TOKEN --project firebase-sample

あとは、CircleCIのプロジェクトへ行き、さっき取得したfirebaseのトークンをFIREBASE_TOKENの環境変数として設定する。

これでGitHubへpushするたびに勝手にデプロイされるようになる。

最後に

  • Nuxt.jsのサイトをFirebase Hostingで動かした
  • Nuxt.jsのサイトをnuxt/pwaモジュールを使ってPWA化した
  • Lighthouseのスコアを向上させた
  • Performanceの項目だけ100点満点にできなかった

ISUCONみたいにフロントエンドのISUCONとしてLighthouseのスコアアップ勝負みたいなのが開催されたりしたら面白そうとかおもったり。

あと以下は余談。

昔Nuxt.jsを触ってた時はv0.9〜v0.10くらいだったんだけど、もうv1.4まで進化しており、PWAやら外部ホスティングとの連携やらが充実し、かなり開発に集中できるフレームワークになっていた。

Next.jsもそうかもしれないけど、Nuxt.jsはもうフロントエンドのRailsと言っても過言ではないのではないかと感じる。

webpackすら全く意識せずにSSRやらVuexでの状態管理やらがが簡単にできる。

Firebase Hostingに簡単にdeployできるのもよい。

これはRails+Herokuでウェブアプリ開発が一気に加速した時のエコシステムの充実度に似てるなと思う。

ReactかVueかの違いはあるにせよ、フロントエンドは一時期の激しいエコシステムの移り変わりから安定期になっていくんだろうな(専門じゃないので知らんけど)。

国内の採用事例とかもっと増えると爆発しそう。

以上です。

基礎から学ぶ Vue.js

基礎から学ぶ Vue.js