Google App Engineにmercury-parserをデプロイしてみる

# 発端
- 「[Mercury Web Parser API](https://mercury.postlight.com/web-parser/) を **2019/4/15** でシャットダウンするよ」とメールが来た。
- Chrome拡張で便利に使っていたので、なくなると困る。
- なのでとりあえずGoogle App Engineにデプロイする事にした。

# 作業環境
- Windows 10 Pro x64
- [Git for Windows](https://gitforwindows.org/) がインストール済み
- [Node.js 8.15.1](https://nodejs.org/dist/latest-v8.x/) がインストール済み
- [App Engine スタンダード環境で Node.js を使用するためのクイックスタート](https://cloud.google.com/appengine/docs/standard/nodejs/quickstart) などを参考にGoogle App Engineにプロジェクトを作成する
- [Google Cloud SDK](https://cloud.google.com/sdk/docs/downloads-interactive) がインストール済み

# [mercury-parser](https://github.com/postlight/mercury-parser) リポジトリの取得
- 適当なフォルダでGitHubのリポジトリからクローンする。

```
git clone https://github.com/postlight/mercury-parser.git
```

# app.yaml app.js .gcloudignore package.json を用意する
- クローンしたフォルダに app.yaml と app.js と .gcloudignore を追加する。

```yaml:app.yaml
runtime: nodejs8
```

```js:app.js
const express = require('express');
const Mercury = require('./dist/mercury');

const app = express();

app.get('/', (req, res) => {
  const url = req.query.url;
  if (!url || url === undefined) {
    res.status(200).end('');
    return;
  }
  let timeoutID;
  Mercury.parse(url)
    .then(function(result) {
      res.status(200).send(result).end();
      clearTimeout(timeoutID);
    })
    .catch(
      (timeoutID = setTimeout(function() {
        res.status(200).end('');
      }, 20000))
    );
});

const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
  console.log('Press Ctrl+C to quit.');
});
```

```:.gcloudignore
.agignore
.babelrc
.circleci/
.eslintignore
.eslintrc
.gcloudignore
.git
.gitattributes
.github/
.gitignore
.nvmrc
.prettierignore
.prettierrc
.remarkrc
assets/
CHANGELOG.md
cli.js
CODE_OF_CONDUCT.md
CONTRIBUTING.md
dist/generate-custom-parser.js
dist/generate-custom-parser.js.map
dist/mercury.js.map
dist/mercury.web.js
fixtures/
karma.conf.js
LICENSE-APACHE
LICENSE-MIT
node_modules/
preview
README.md
RELEASE.md
rollup.config.js
rollup.config.web.js
score-move
scripts/
src/
yarn.lock
```

- package.jsonは元からあるファイルを改変する。
  - scriptsにstartを追加。
  - enginesの書式をGoogle App Engine方式に変更。
  - dependenciesにexpressを追加。

```json:package.json
  "scripts": {
    "start": "node app.js", ← 追加
  ～ 中略 ～
  },
  ～ 中略 ～
  "engines": {
    "node": "8.x.x" ← 変更
  },
  ～ 中略 ～
  "dependencies": {
    "express": "^4.16.4", ← 追加
  ～ 中略 ～
  },
```

ここまで実施済みなのが [このリポジトリの「feat-gae-deploy」ブランチ](https://github.com/kik0220/mercury-parser/tree/feat-gae-deploy) 。

# ローカルで実行してみる
ローカルで軽く試してみる場合は、mercury-parserをクローンしたフォルダをコマンドプロンプトで開き、↓を実行すると8080番ポートでサーバーが起動する。

```
npm install
npm start
```

- `npm install`は最初の1回目か package.json で dependencies などを変更した時のみ実行する。
- `http://localhost:8080/?url=<パースしたいURL>` で動作を確認出来る。

# Google App Engineにデプロイしてみる
### 手順
1. mercury-parserをクローンしたフォルダをコマンドプロンプトで開き、`gcloud app create` を実行する。
2. `gcloud app create` は最初の1回のみ実行する。

 ※ `<プロジェクトID>`は作成したGoogle App Engineの **プロジェクトのID**。
 　 **プロジェクトの名前** とは別なので注意。

```
gcloud app create --project=<プロジェクトID>
```
↑で、デプロイするリージョンを聞かれるので、好きな場所を指定する。


```
gcloud app deploy --project=<プロジェクトID>
```

続けるか聞かれるので、続けるならEnterキーを押す。
ファイルのアップロードとサービスの起動が実行される。
・
・
・
デプロイ完了！

# 動作を確認してみる
アップロードした app.js は
`https://<プロジェクトID>.appspot.com/?url=<パースしたいURL>`
でパースした結果をJSONで返してくるので、適当なURLで試してみる。

# せっかくなので [Custom Parser(extractor)](https://github.com/postlight/mercury-parser/blob/master/src/extractors/custom/README.md) を作ってみる
うまくパースされないページなどがあると自分で Custom Parser(extractor) を作ってみたくなるもの。

- mercury-parserをクローンしたフォルダで `yarn generate-parser` を実行し、URLを入力すると、 Custom Parser(extractor) のひな形を作成する事が出来る。
- [yarn](https://yarnpkg.com/lang/ja/) は `npm install -g yarn` でインストール出来る。
- `yarn watch:test <入力したURLのドメイン名>` でテストが通るようになったら、 `yarn test_build` で `dist/mercury.js` をビルドしてみる。
- `yarn test_build && npm start` でローカル実行して試すも良し、 `yarn test_build && gcloud app deploy --project=<プロジェクトID>` でデプロイするも良し。

# ついでに
- package.json の scripts によく使うコマンドを追加すると yarn で呼び出せて便利。
  - `"deploy": "gcloud app deploy --project=<プロジェクトID>",` で `yarn deploy` とか。
  - `"log": "gcloud app logs tail -s default --project=<プロジェクトID>",` で `yarn log` とか。

- デプロイしたプロジェクトが呼び出されまくって無料枠を超えてしまうなど怖い事もありますので、
  必要に応じて使用量の制限はしておきましょう。
  ![使用量.png](https://qiita-image-store.s3.amazonaws.com/0/21033/c5303ebf-1e78-f8b6-238d-64b55a8467cb.png)