lighthouseをdocker化して、nowを使って結果をjsonで取得する

lighthouseを定期的に計測するためにtravisなどを使う方法はあったのですが、
CIを使わずに[now](https://zeit.co/now)を使って、計測結果をjsonで取得したいと思い色々やってみました

nowのURLにアクセスすれば、lighthouseの計測結果のjsonが取得できるようなものを作りました

## ファイル構成とか

`app`以下は`express-generator`を使用して作成
`services`は追加で作成
作成できたら`now`コマンドでnowにデプロイすれば、使えるはず

```
.
├── Dockerfile
└── app
    ├── app.js
    ├── bin
    ├── node_modules
    ├── package.json
    ├── public
    ├── routes
    ├── services
    ├── views
    └── yarn.lock
```

## Dockerfile

dockerfile は、nodeをベースに、chromeが動くようにと、日本語が一応表示できるようしたかったので、以下の記事を参考にしました
[Dockerを使ってHeadless Chromeを動かしてみる](https://qiita.com/dd511805/items/dfe03c5486bf1421875a)

```Dockerfile
FROM  node:8-slim

RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - &&\
  sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' &&\
  apt-get update &&\
  apt-get install -y google-chrome-unstable unzip

RUN mkdir /noto

ADD https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip /noto

WORKDIR /noto

RUN unzip NotoSansCJKjp-hinted.zip && \
  mkdir -p /usr/share/fonts/noto && \
  cp *.otf /usr/share/fonts/noto && \
  chmod 644 -R /usr/share/fonts/noto/ && \
  fc-cache -fv

WORKDIR /
RUN rm -rf /noto

# Install app dependencies
RUN npm i -g yarn
RUN mkdir /app
COPY ./app/package.json /app
RUN cd /app;yarn install

# Bundle app source
COPY . .

EXPOSE  3000
WORKDIR /app
CMD ["yarn", "start"]
```

## package.json

express-generator でできた package.json に、`lighthouse`,`chrome-launcher`を追加

```package.json
{
  "name": "kanmi-lighthouse",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.18.2",
    "chrome-launcher": "^0.10.2",
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "express": "~4.15.5",
    "jade": "~1.11.0",
    "lighthouse": "^2.9.1",
    "morgan": "~1.9.0",
    "serve-favicon": "~2.4.5"
  }
}
```

## lighthouseの実行

servicesの配下に`lighthouse.js`を作成
ここで、lighthouseの結果から今回必要なものだけを取得
`chromeFlags`はどれか不要かも知れませんが、動いたのがこれなのでひとまずペンディング

```javascript:lighthouse.js
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');

const perfConfig = require('lighthouse/lighthouse-core/config/perf.json');

function launchChromeAndRunLighthouse(url, opts, config = null) {
  return chromeLauncher
    .launch({ chromeFlags: opts.chromeFlags })
    .then(chrome => {
      opts.port = chrome.port;
      return lighthouse(url, opts, config).then(results => {
        delete results.artifacts;
        return chrome.kill().then(() =>
          results.reportCategories.map(data => ({
            name: data.name,
            score: data.score
          }))
        );
      });
    });
}

const opts = {
  port: 0,
  autoSelectChrome: true, // False to manually select which Chrome install.
  chromeFlags: [
    '--show-paint-rects',
    '--headless',
    '--disable-device-emulation',
    '--disable-gpu',
    '--enable-logging',
    '--no-sandbox'
  ]
};

module.exports = url => {
  return launchChromeAndRunLighthouse('https://' + url, opts);
};
```

上記の関数をこんな感じで呼び出し(`routes`フォルダに配置)

```javascript
var express = require('express');
const lighthouse = require('../services/lighthouse');
var router = express.Router();

router.get('/', async function(req, res, next) {
  const results = await lighthouse('qiita.com/');
  res.json(results);
});
```

## 結果

URLにアクセスした際のjson はこんな感じに出力されます

```json
Array[5][
  ({
    "name": "Performance",
    "score": 39.05882352941177
  },
  {
    "name": "Progressive Web App",
    "score": 45.45454545454545
  },
  {
    "name": "Accessibility",
    "score": 51.041666666666664
  },
  {
    "name": "Best Practices",
    "score": 62.5
  },
  {
    "name": "SEO",
    "score": 85
  })
]
```

## 感想

lighthouse自体をローカルで動かすのは簡単だったけれど、Docker化してnowで動かすのに色々手間取りました
あと、nowだとアクセスしていないと`FROZEN`状態になるので、定期的に動かさないと結果取得に時間がかかるのが難点だと思いました