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

CircleCIとslackを使ってLighthouseの計測結果を簡単に見たい

主な目的

管理しているサービスやWebサイトが増えていく中で、
新規機能開発や既存機能の改善などを行なった際に発生する副作用を、把握することが難しくなってきました。

バグの検知や表示崩れもですが、特にスピードに関して追いきれていない部分があり
一人でやる分にはdevtoolsを開いてAudits叩いてもいいんですが、
チームでやっていくにはやはり限界が出てきます。

そこで取っ掛かりとしてCircleCIの勉強も兼ねて、Lighthouseとの連携をやってみました。

実装する機能ついて

以下の順序で実装していきます。

  • LighthouseをlocalのCLI上で実行
  • CircleCI上でLighthouseを実行
  • slack WebhookURLの発行とCircleCI環境変数への登録
  • slack通知のCircleCIへの実装

LighthouseをCLI上で実行

Lighthouse によるウェブアプリの監査

Lighthouseを実行する方法は2つあります。
以下公式サイトから引用すると

Lighthouse を実行するには 2 つの方法があります。Chrome 拡張機能として実行する方法と、コマンドライン ツールとして実行する方法です。 Chrome 拡張機能では、よりユーザー フレンドリーなインターフェースでレポートを確認できます。 コマンドライン ツールとして実行した場合は、Lighthouse を統合システムの一部として使うことができます。

今回は最終的にCI上での実行を想定をしているので、まずはコマンドラインツールとしての実行をローカルで確認します。

# globalにlighthouseをインストール
npm install -g lighthouse

# Lighthouseのverを確認
lighthouse --version
# 5.1.0

# 目的のサイトを指定してコマンドを実行
lighthouse https://www.google.com/?hl=ja

# --viewを指定すると即時ブラウザが立ち上がって確認ができる
lighthouse https://www.google.com/?hl=ja --view

注意点
公式サイトではNode のバージョン 5 以降をインストールします。と書いてあるんですが
Lighthouse5系以上だとNodeのバージョン10以上じゃないと動かないようです。

試しにnode.8.11.2の環境で実行したところ以下のエラーが出てストップします。

class URLShim extends URL {
                      ^

ReferenceError: URL is not defined
    at Object.<anonymous> (/Users/xxxx/.nodebrew/node/v8.11.2/lib/node_modules/lighthouse/lighthouse-core/lib/url-shim.js:35:23)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/xxxx/.nodebrew/node/v8.11.2/lib/node_modules/lighthouse/lighthouse-core/lib/network-request.js:14:13)
    at Module._compile (module.js:652:30)

公式のissueにも上がっていました。
ReferenceError: URL is not defined
対応策としては以下が考えられます。

  1. Nodeのバージョンを10以上にする
  2. Lighthouseの4系をインストール

Nodeの公式サイトを見るに現在のLTSが10.16.0なので、そのバージョンで起動します。
なお今回は特定のディレクトリ内でだけ10.16.0にすることに(global環境は一旦切り分け)
Nodeの環境構築に関しては今回本筋ではないので割愛しますが、以下を参考にさせていただきました。

参考
anyenv と nodenv で node.js バージョン管理、設定後に gulp の設定を修正(Mac)

Nodeのバージョンが10以上であれば、以下のコマンドを叩くと終了後に自動的にブラウザが立ち上がって結果が確認できます。

lighthouse https://www.google.com/?hl=ja --view

テスト結果

CircleCI上でLighthouseを実行

localでは動作が確認できたので、これをCircleCIに載せていきます。
CircleCI公式サイト

今回はCircleCIの導入そのものには言及しません。
導入に関しては他の記事を参考にしていただいて、あくまで今回はLighthouseとslack連携に絞って書いていきます。

なおCircleCI上での実装に関しては、以下の記事を参考にさせていただきました。

LighthouseをCircle CI上で雑に実行してみる

今回連携するサイトは以前作成したblogです。
連携しているgithubのリポジトリにあるcofig.ymlを変更していきましょう。
細かい部分には言及していないので以下の公式ドキュメントも一緒に参考にしていただければと思います。

CircleCI公式ドキュメント

まずは一例として一番シンプルな形のconfig.ymlの例から

.circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/ruby:2.4.1
    steps:
      - checkout
      - run: echo "A first hello"

上記の設定で連携済みのgithubに変更をpushすると
buildが走ったタイミングでjobが起動してCircleCI上で表示が確認できます。

circleci.com_gh_tomopict_vue-press-blog_4.png

ここにlighthouseの実行jobを追加していきます。
まずは完成形です。

.circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/node:10.16-browsers # Ligthouse v5 以上の場合 Node > v10必須
    steps:
      - checkout # コード実行場所(working_directory)にcheckout
      - run:
          name: Install lighthouse
          command: |
            sudo npm install -g lighthouse
      - run:
          name: Check lighthouse
          command: |
            lighthouse --version
      - run:
          name: Run lighthouse
          command: |
            lighthouse https://tomopict.netlify.com/ --output html --output json --output-path ./tomopict.json

      - store_artifacts:
          path: '.'

workflows:
  version: 2
  build_and_test:
    jobs:
      - build

workspaceで使用するdockerイメージを指定

docker:
    - image: circleci/node:10.16-browsers

注意
Localで実行する際にLighthouseのバージョンが5以上の場合Nodeのバージョンが10以上必要との記載がありました。
ここで10以上を指定しようと思ってCircleCI公式のドキュメントを見ると9系までしか表示されていません。

しかしall available image tagsのリンクを見る限り12までNodeのイメージは存在しているようです。
ですのでlocalと同じ10.16.0で揃えます。

image: circleci/node:10.16-browsers

なおimage: circleci/node:10.16だと以下のエラーが出て失敗します。

Runtime error encountered: The environment variable CHROME_PATH must be set to executable of a build of Chromium version 54.0 or later.
Error
    at new LauncherError (/usr/local/lib/node_modules/lighthouse/node_modules/chrome-launcher/dist/utils.js:35:22)
    at new ChromePathNotSetError (/usr/local/lib/node_modules/lighthouse/node_modules/chrome-launcher/dist/utils.js:42:9)
    at Object.linux (/usr/local/lib/node_modules/lighthouse/node_modules/chrome-launcher/dist/chrome-finder.js:108:15)
    at Launcher.<anonymous> (/usr/local/lib/node_modules/lighthouse/node_modules/chrome-launcher/dist/chrome-launcher.js:143:80)
    at Generator.next (<anonymous>)
    at /usr/local/lib/node_modules/lighthouse/node_modules/chrome-launcher/dist/chrome-launcher.js:12:71
    at new Promise (<anonymous>)
    at __awaiter (/usr/local/lib/node_modules/lighthouse/node_modules/chrome-launcher/dist/chrome-launcher.js:8:12)
    at Launcher.launch (/usr/local/lib/node_modules/lighthouse/node_modules/chrome-launcher/dist/chrome-launcher.js:131:16)
    at Object.<anonymous> (/usr/local/lib/node_modules/lighthouse/node_modules/chrome-launcher/dist/chrome-launcher.js:52:24)
Exited with code 1

circleciのイメージに元々入っているchromedriverと、chromedriver-helperに齟齬があるようです。
※参考※CircleCIのChromeとchromedriver-helperのchromedriverのバージョンを揃える

今回はnode:10.16ではなく10.16-browsersとすることで回避しました。
ここに関しては名称的にはブラウザがバンドルされているdockerイメージかと思いますが、詳細は調べきれていません。

コードの実行場所にチェックアウト、Lighthouseのインストール

コードの実行場所にチェックアウトして、そこでLighthouseのインストールを行います。
この時にsudoをつけないとエラーになるのでご注意。

    steps:
      - checkout
      - run:
          name: Install lighthouse
          command: |
            sudo npm install -g lighthouse

Lighthouseのバージョンを表示

念のためLighthouseのverを出力しています。

      - run:
          name: Check lighthouse
          command: |
            lighthouse --version

URLを指定して実行

今回対象のサイトのURLを指定します。lighthouse <url>
なお出力するレポートのpathとnameも指定しています。

      - run:
          name: Run lighthouse
          command: |
            lighthouse https://tomopict.netlify.com/ --output html --output json --output-path ./tomopict.json

レポートのpathとname関しては指定せずに出すこともできますが、その場合HOSTとDATEがそのまま付与されてきます。

lighthouse https://tomopict.netlify.com/ --output json --output html
# saves `./<HOST>_<DATE>.report.json` and `./<HOST>_<DATE>.report.html`

そのままだとslack通知の時にレポートの場所を指定するのがいささかめんどくさくなるので、明示的に指定しています。
↓↓↓↓↓ 公式サイトからの表示例が以下 ↓↓↓↓↓

output/example
# NOTE: specifying an output path with multiple formats ignores your specified extension for *ALL* formats
lighthouse --output json --output html --output-path ./myfile.json
# saves `./myfile.report.json` and `./myfile.report.html`

↓↓↓↓↓ 今回の設定 ↓↓↓↓↓

lighthouse --output json --output html
—out-putpath ./tomopict.json
# saves `./tomopict.report.json` and `./tomopict.report.html`

ちなみに軽い違和感に付いて
pathの指定がhtml,json両方出すのに片方だけ—out-putpath ./tomopict.json指定していることが若干違和感。
ちなみにhtmlとjsonそれぞれoutputpathを指定するとエラーで止まる。

URLを指定して実行

レポートの出力先を指定します。

      - store_artifacts:
          path: '.'

ここまで準備ができたら該当のリポジトリをpushします。
CircleCI上で問題なくLighthouseが起動するか確認しましょう。
正しく動作した場合jobがsuccess表示になって、「Artifacts」タブの中に今回のレポートが出力されます。

スクリーンショット 2019-07-15 12.04.46.png

slack WebhookURLの発行と環境変数への登録

さてこれでCircleCI上での実行を確認できたので、slackへの通知を実装します。

slackのWebHook URL取得

まずは以下にアクセスをして必要なチャンネルのwebhookURLを取得してきます。

Incoming Webhook
通知をするチャンネルを選択して、「Incoming Webhookインテグレーションの追加」をクリックすると
次のページに「Webhook URL」が表示されるのでメモしておきます。

webhook01.png
webhook02.png

WebhookURLを環境変数に登録する

config.yml内で環境変数として呼び出したいのでCircleCI内で環境変数として登録をします。
ログインしたら左カラムメニューの[SETTINGS]→[Projects]から今回連携したいプロジェクトの歯車をクリックします。

webhook3.png

次のページで[BUILD SETTINGS]内にある[Environment Variables]を選択して、[Add Variable]をクリックします。
webhook4.png

モーダルで環境変数の登録画面が開くので、それぞれに以下を入力します。

Name:SLACK_WEB_HOOK
Value:{先ほどslackでメモしたWebhookURL}

webhook5.png

これでconfigの中から${SLACK_WEB_HOOK}で環境変数として呼び出すことができます。

slack通知のconfig.ymlへの実装

最後にconfig.ymlへslackへの通知機能部分を追記します。
該当の箇所のコードは以下です。

/.circleci/config.yml
      - run:
          name: vuepress deploy
          command: |
            curl -X POST --data-urlencode 'payload={"username": "circleCI", "text": "デプロイしました:<'https://${CIRCLE_BUILD_NUM}-xxxxxxxxx-gh.circle-artifacts.com/0/home/circleci/project/tomopict.report.html' | open report :earth_asia:>", "icon_emoji": ":ghost:"}' ${SLACK_WEB_HOOK}
          #xxxxxxxxxは固有のIDが入る

最後のcurlコマンドのところですが、意外とここでかなりハマりました。
slack公式のincoming Hookの所では以下のような記載になっていたんですが、
一番外側のダブルクオーテーションがそのままだとうまく動作せず、結局シングルクオーテーションに書き換えました。

slack公式例
curl -X POST --data-urlencode "payload={\"channel\": \"#general\", \"username\": \"webhookbot\", \"text\": \"これは webhookbot という名のボットから #general に投稿されています。\", \"icon_emoji\": \":ghost:\"}" https://hooks.slack.com/services/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

また、リンクを貼るにあたり環境変数を持ってくる際にそこはシングルクオーテーションにしたりと、よく考えれば分かる部分だったんですが、地味にハマりました。
ちなみに環境変数に関しては以下を参考にさせていただきました。

[メモ] CircleCI_環境変数一覧(1.0&2.0)

なおサンプルによっては環境変数も1で使えるが2系で使用ができないものが書いてあって地味にそこもハマります。
具体的にはCIRCLE_ARTIFACTS

変更点としては以下

変更点
\"" #エスケープを排除
一番外側の"'に変更

slackの通知まで全て反映した状態のconfig.ymlが以下になります。

.circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/node:10.16-browsers # Ligthouse v5 以上の場合 node > v10必須
    steps:
      - checkout # コード実行場所(working_directory)にcheckout
      - run:
          name: Install lighthouse
          command: |
            sudo npm install -g lighthouse
      - run:
          name: Check lighthouse
          command: |
            lighthouse --version
      - run:
          name: Run lighthouse
          command: |
            lighthouse https://tomopict.netlify.com/ --output html --output json --output-path ./tomopict.json
      - store_artifacts:
          path: '.'

      - run:
          name: vuepress deploy
          command: |
            curl -X POST --data-urlencode 'payload={"username": "circleCI", "text": "デプロイしました:<'https://${CIRCLE_BUILD_NUM}-xxxxxxxxx-gh.circle-artifacts.com/0/home/circleci/project/tomopict.report.html' | open report :earth_asia:>", "icon_emoji": ":ghost:"}' ${SLACK_WEB_HOOK}
          #xxxxxxxxxは固有のIDが入る

workflows:
  version: 2
  build_and_test:
    jobs:
      - build

この状態で該当のリポジトリにpushすれば以下のように通知がきます!
意外と長かった・・・。

スクリーンショット 2019-07-15 19.56.04.png

リンクをクリックすると、Lighthouseのレポートが見れます。
151-161642287-gh.circle-artifacts.com_0_home_circleci_project_tomopict.report.html.png

お疲れ様でした!

まとめ

最後まで読んでいただきありがとうございます。
CircleCIの導入自体は初めてだったんですが、やはり使いやすいですね。

今の所デプロイのタイミングでテストを実行してその場で確認するだけにしてますが、
テスト結果自体も残しておいて推移の計測にも使って行こうかと思います。

ちなみに保存されているものの期間は以下のとおり明言されていないので、
レポートに関してはs3なりGoogle spreadsheetなりに残しておいたほうがいい気がします。

アーティファクトの用途 (および制限)

あとは今後複数サイトで運用するにあたってどの辺りまでコストをかけようか悩む所です。
無料プランだと同時実行数が1なので複数ビルドが重なった時に処理時間が遅くなったりはしそうです。

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
ユーザーは見つかりませんでした