株式会社クイックのWebサービス開発blog

HAPPYなサービスプランナー・エンジニア・デザイナーのブログです。

【Lighthouse/Docker】Chromeは入っていないけどDockerは動かせるサーバでLighthouseを動かす方法

こんにちは!Czです!

最近驚いたことがあるんですよ。
休日にね、子供たちとリビングでゲーム実況見ていたんです。
そしたらね、その動画のチャンネルのおすすめ動画に親戚が「どーん」と映ってたんですよ。
えっ?ちょっとまって?って感じで。 まさか親戚が登録者数40万のYoutuberだとは思いませんでしたよ。

おじさん、正月とかに会ったときにちょっと緊張しちゃうぞ!( ^ω^ )

ところでみなさん、Lighthouseは知っていますか?(話の切り替え下手)

ざっくり言うと あなたのサイトをGoogleの観点で評価してくれるツール です。
「Performance」「Accessibility」「Best Practices」「SEO」「Progressive Web App」の5つのカテゴリと、様々な指標で評価しスコア化してくれます。
SEO対策を考えている方は必ずチェックしておきたいやつです。

詳しく知りたい方は以下をチェック!
developers.google.com

手持ちのGoogle Chromeで動かしてみる

いまいちピンと来てない方、手持ちのGoogle Chromeで動かしてみましょうか!

右上のメニュー > その他ツール > デベロッパーツールを開き、Lighthouse タブを選択します。

そうすると以下のような画面が出てくるので f:id:aimstogeek:20210422231552p:plain

[Generate report]ボタンを押しましょう。(今開いているページをなにやらせわしなく評価してくれます)

終わったら以下のような結果が出てきます。 f:id:aimstogeek:20210422231639p:plain

このように100点満点中何点かというスコアを表示してくれます。
これを基にどこを改善すべきかを考えることが出来そうですね!

またNode CLIとしても用意されているのでjsさえ書ければ上の手順を踏まなくても実行できます! github.com

...ここでタイトルに結びつけるために唐突な脳内会議

A「Lighthouseを毎日決まった時間に動かしたいな〜」
B「でも自分のPCでは動かしたくない!絶対に!」
C「ちょうどJenkinsサーバあるじゃん」
D「Nodeは入ってないけどDocker入ってるからNodeは実行出来そうだな」
E「え〜っと、Chromeは...?」

A,B,C,D,E「入ってない!!!」

Chromeは入っていないけどDockerは動かせるサーバでLighthouse動かしたい

ここからはコードを書いて説明しますね。

まずはDockerの前にホストマシンでLighthouseを動かしてみましょう!

ファイル構成はとりあえずこんな感じ

.
├ ─ ─  package.json
├ ─ ─  src/
|    └ ─ ─  index.js
└ ─ ─  dist/ ← 計測結果出力先

まずはpackage.json

{
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "node src/index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "chrome-launcher": "^0.13.4",
    "lighthouse": "^7.3.0",
    "prettier": "^2.2.1"
  }
}

今回必要なのは「chrome-launcher」と「lighthouse」この2つ。
お好みでprettier(フォーマッター)も入れときましょうか。

そして src/index.js 以下のように記述してください。

const fs = require('fs'); // 結果の保存用
const chromeLauncher = require('chrome-launcher'); // Chrome起動用
const lighthouse = require('lighthouse'); // Lighthouse実行用

// 計測対象のURL
const targetUrl = process.env.URL;

// デバイス: 'mobile' or 'desktop'
const device = process.env.DEVICE || 'mobile';

// 保存先
const distDir = `${process.cwd()}/dist`;
const fileName = process.env.FILE_NAME || 'report';

if (!targetUrl) {
  console.error('URLが指定されていません')
  return;
}

// Lighthouse用オプション
const opts = {
  output: 'html', // 出力の形式。jsonは別の方法で取得できるのでhtmlとしている
};

// Lighthouse用設定
// @see[https://github.com/GoogleChrome/lighthouse/blob/master/docs/configuration.md]
const config = {
  extends: 'lighthouse:default',
  settings: {
    emulatedFormFactor: device,
  },
};

// Chrome用オプション
const chromeOpts = {
  autoSelectChrome: true, // False to manually select which Chrome install.
  chromeFlags: [
    '--no-sandbox', // このフラグがないとオレオレ認証のローカル環境ではこけてしまう
    '--headless', // ヘッドレスモードで起動
  ],
};

(async () => {
  // Chromeを起動
  const chrome = await chromeLauncher.launch(chromeOpts).catch(reason => console.error(reason));

  // 起動したChromeのportをlighthouseが参照するportに指定する
  opts.port = chrome.port;

  // lighthouseを実行
  const res = await lighthouse(targetUrl, opts, config).catch(reason => console.log(reason));

  // html形式で保存
  fs.writeFileSync(`${distDir}/${fileName}.html`, res.report, 'utf8');

  // json形式で保存
  fs.writeFileSync(`${distDir}/${fileName}.json`, JSON.stringify(res.lhr), 'utf8');

  // Chromeの終了
  await chrome.kill();
})();

何をやっているかと言うと

  1. Chrome起動して
  2. Lighthouse起動して
  3. htmlとjsonで結果を保存

という非常にシンプルな感じとなっています。

実行するときはこんな感じ

env URL=<対象のURL> DEVICE=mobile FILE_NAME=report npm start 

環境変数で必要なオプションを渡しています。

URL
Lighthouseを実行対象となるページのURL
DEVICE
携帯かPCか('mobile' or 'desktop')
出力するファイル名
'report'とすると report.html と report.json がdistディレクトリ配下に作られる


結果はdistディレクトリ配下に作られます。 確認してみましょうか。

こんな感じでjsonとhtml形式で出力されています!

/dist/report.json f:id:aimstogeek:20210423110701p:plain

/dist/report.html f:id:aimstogeek:20210422234618p:plain

ちゃんと出力されましたね!

Chromeが起動できるDockerコンテナを作成する

ではやっと本題。先ほど作ったコードをDocker上で動かせるようにします。

ディレクトリ構成

├ ─ ─  docker
│    └ ─ ─  chrome
│        └ ─ ─  Dockerfile
├ ─ ─  docker-compose.yml
├ ─ ─  package.json
├ ─ ─  src
│    └ ─ ─  index.js
└ ─ ─  dist/ 

Docker関連のファイルが追加していきます。

まずは/docker/chrome/Dockerfile

FROM ubuntu:20.04

#SHELL ["/bin/bash", "-c"]

ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo

# google-chrome-stableをインストールするための準備
RUN apt update && apt-get update
RUN apt install -y wget gnupg gnupg1 gnupg2
RUN sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \
      wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN apt update && apt-get update
RUN apt install -y tzdata

# google-chrome-stableのインストール
RUN apt install -y google-chrome-stable

# nodeのインストール(n package使用)
RUN apt install -y nodejs npm && npm install n -g && n stable && apt purge -y nodejs npm

コード内のコメントにある通りなのですが以下の処理を行っています。

  1. google-chrome-stableをインストールするための準備
  2. google-chrome-stableをインストール
  3. n packageを使ってnodeをインストール

次にdocker-compose.yml

version: "3"
services:
  chrome:
    build:
      context: ./
      dockerfile: ./docker/chrome/Dockerfile
    volumes:
      - .:/work
    working_dir: /work
    shm_size: 2gb # メモリが足りないとスコアが下がるため多めに割り当てる

これで準備完了!

Docker上でLighthouseを実行

次のコマンドを実行してみてましょう

docker-compose run --rm -e URL=<対象のURL> -e DEVICE=mobile -e FILE_NAME=report chrome npm start

f:id:aimstogeek:20210423005426p:plain

ちゃんと動いてくれました!

あとはこれをJenkinsなりcronなりで定期実行することで、改善を定量的に評価できたり改善のモチベーションにもなりそうですね!

今日はここまで!

収集したデータをBIツールとか使って解析するのも今後紹介できたらいいな!


\\『真のユーザーファーストでマーケットを創造する』仲間を募集中です!! //

919.jp