🦕 Deno アプリを Heroku にデプロイする

この記事は[Deno Advent Calendar 2019](https://qiita.com/advent-calendar/2019/deno)、24日目の記事です。

[Deno](https://deno.land/) アプリを [Heroku](https://jp.heroku.com/) で起動する buildpack を作成しましたので紹介したいと思います（シェルスクリプトをちょっと書いただけですが）。
作成した buildpack は、[Heroku のサイト](https://elements.heroku.com/buildpacks/chibat/heroku-buildpack-deno)にも自動でインデックスされました。
[Deno Newsletter](https://deno.news/issues/deno-newsletter-34-v0-18-0-199776) でも共有して頂けました！

# 🦕 サンプルアプリのデプロイ

簡単なサンプルアプリのデプロイ方法について説明します。
関連ファイルは [github](https://github.com/chibat/heroku-deno-getting-started) から clone できます。

## 前提条件
* [Git がインストール済みであること](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [Heroku のアカウントが作成済みであること](https://signup.heroku.com/jp)
* [Heroku CLI がインストール済みであること](https://devcenter.heroku.com/articles/heroku-cli)
* [Deno がインストール済みであること（ローカル環境での動作確認のため）](https://deno.land/)

## Web アプリの作成

まずは簡単な Web アプリを作成します。
次の内容で main.ts という名前のファイルを作成します。

```javascript
import { serve } from "https://deno.land/std@v0.27.0/http/server.ts";
import * as flags from "https://deno.land/std@v0.27.0/flags/mod.ts";

const DEFAULT_PORT = 8080;
const argPort = flags.parse(Deno.args).port;
const port = argPort ? Number(argPort) : DEFAULT_PORT;

if (isNaN(port)) {
  console.error('Port is not a number.');
  Deno.exit(1);
}

const body = new TextEncoder().encode("Hello World\n");
const s = serve({port: port});
console.log("http://localhost:" + port);
for await (const req of s) {
  req.respond({ body });
}
```
このコードは、Deno サイトのトップページに記載されているコードとほぼ同じです。コマンド引数でポート番号を受け取れるようにしています。

## ローカル環境での動作確認

ローカル環境で動作確認をします。次のコマンドを実行し、Web アプリを起動します。

```
$ deno run --allow-net=:8080 main.ts
```

Web ブラウザや curl コマンドで http://localhost:8080 にアクセスし動作を確認します。 

```
$ curl http://localhost:8080
Hello World
```

## Heroku へのデプロイ

### Procfile

次のような起動コマンドを記述した Procfile という名前のファイルを作成します。

```
web: deno run --allow-net=:${PORT} --cached-only main.ts --port=${PORT}
```

環境変数 `PORT` は、アプリが listen すべきポート番号で Heroku により与えられます。

### runtime.txt

次のような内容で runtime.txt のファイルを作成すると、実行する Deno のバージョンを固定できます。
ファイルが存在しない場合は、最新版の Deno が利用されます。

```
v0.27.0
```

### Deploy

次のコマンドでデプロイを実行します。

```
$ git init
$ git add .
$ git commit -m "first commit"
$ heroku create --buildpack https://github.com/chibat/heroku-buildpack-deno.git
$ git push heroku master
```

この buildpack の挙動としましては、`git push` したときに内部で Deno のインストールと `deno cache` を実行し、依存するものをキャッシュします。アプリの起動時、再起動時にはキャッシュを利用します。

次のコマンドを実行すると、ブラウザが起動し Web アプリにアクセスします。

```
$ heroku open
```


# 🦕 おわりに

今回、Deno アプリを Heroku で起動する buildpack を紹介させて頂きました。
この buildpack は、 Cloud Foundry(Application Runtime) でも利用可能なことを確認しています。
Docker に明るい方は、この buildpack を使わずに Dockerfile を作成し、デプロイすることもできるかと思います。

私が Deno に興味をもったのは Node.js を開発した [Ryan](https://en.wikipedia.org/wiki/Ryan_Dahl) が作り始めたということもあるのですが、セキュリティーの機能に惹かれたからです。
Deno はデフォルトでネットワーク、ファイル、環境変数などへのアクセスが制限されます。
多くの人は、依存するライブラリに悪意あるコードが含まれている事に関心がないのかもしれませんが、Node における [event-stream 事件](https://qiita.com/mysticatea/items/aac027f9183ea9f0f9b1) や [Rubyライブラリ事件](https://japan.zdnet.com/article/35141553/)、[Python ライブラリ事件](https://japan.zdnet.com/article/35140047/) が発生しています。
Deno ならば最低限のアクセス権限しか与えなければ多くの問題を防ぐことができると思います。
Node がかなり普及してしまったので、新しい JavaScript ランタイムとして使ってもらうことはなかなか難しい挑戦だと思いますが、Deno が今後どのように進んでいくのか楽しみです。　

以上です。