🦕

Deno(Aleph.js) で Markdown で投稿できる SNS のようなものを作ってみた

2021/12/26に公開

Leaves

Deno(Aleph.js) の学習がてら、Markdown で投稿できる SNS のようなものを作り、Heroku 上に公開してみました。
Leaves と名づけました(Heroku 無料枠の利用のため、残念ながら初回アクセス時はインスタンスの起動が行われレスポンスが遅いことが多いと思います。。)

https://leaves.chiba.dev/

SNS にありそうな機能を含め、以下の機能を実装しています。

  • 投稿(Post) 📰
  • コメント(Comment)
  • フォロー(Follow) 👦
  • いいね(Like) 💛
  • 通知(Notification) 🔔
  • ソーシャルログイン(Google) 🔑
  • Markdown で投稿

Googleアカウントで認証するようにしており、ログイン時に以下のメッセージが表示されますが、メールアドレスの取得していません(これは何故メールアドレスと表示してるんでしょう。。)

続行するにあたり、Google はあなたの名前、メールアドレス、言語設定、プロフィール写真を md-sns.herokuapp.com と共有します。

検索機能も実装したかったのですが、無料枠で全文検索をできるようにするのは難しいですかね。。

以降は、どう実装し起動しているのか簡単にご紹介したいと思います。

ソースコード

ソースコードも公開しています。
仕事では、React, Next.js も未経験でありながら、いきなり Aleph.js へと進んでしまいました。
変な部分がありましたら、コメント頂けると嬉しいです。
https://github.com/chibat/md-sns

Deno

Web アプリのランタイムとして Deno を利用しています。
Deno は、JavaScript/TypeScript のランタイムです。
Node.js の作者である Ryan Dahl が開発を始めました。
主な特徴としては、Node.js と比べてデフォルトでセキュアである事と、標準で TypeScript に対応している点だと思います。
https://deno.land/

日本語の情報としましては、以下の Zenn Book がお薦めです。
https://zenn.dev/uki00a/books/effective-deno

Aleph.js

Web フレームワークとして Aleph.js を利用しています。
Aleph.js は、フルスタックな Web フレームワークです。
Next.js にインスパイアされたフレームワークだと思います。

https://alephjs.org/

SSR(Server Side Rendering) や ISR(Incremental Static Regeneration) にも対応されています。

useDeno 関数を使うことにより、SSR, ISR を実現できます。
最初、SSR をしたかったのですが、ISR のような挙動になり戸惑いました。
以下のようなコードだと ISR になるようです。

const post = useDeno(async () => {
  return await selectPost(postId);
});

SSR にするためには、以下のように revalidate オプションを指定する必要があるようです。

const post = useDeno(async () => {
  return await selectPost(postId);
}, { revalidate: true });

また、Aleph.js は、permission の設定を最小限にしようとすると結構面倒です。

Aleph.js 再設計?

以下の、GitHub Issue のコメントで、Aleph.js の再設計の話がされています。

https://github.com/alephjs/aleph.js/issues/429#issuecomment-967794820

Deno の compat モードの登場により Next.js を直接実行できるようになるだろうということや、Next.js が内部で swc を使いコンパイルパフォーマンスが上がっていることが影響しているようです。
Deno Deploy でも実行しやすいもになるのだと思います。

Heroku

Heroku に Deploy しています。
無料枠の利用のため、残念ながら初回アクセス時はインスタンスの起動が行われレスポンスが遅いことが多いと思います。

Heroku Buildpack for Deno

Heroku に Deploy するために、以下の Buildpack を使いました。
https://elements.heroku.com/buildpacks/chibat/heroku-buildpack-deno

この buildpack も私が作りました。この buildpack については、以下の記事を書いています。
https://qiita.com/chibato/items/839e13ab09428dc1481c

Heroku では、60秒以内に起動しないとタイムアウトになります。
Deno は、ビルドのフェーズと起動のフェーズが明確に分かれていないため、単純に起動するとこのタイムアウトの制約で起動できない事があります。
この buildpack では、その対策としてビルドフェーズで起動コマンドで指定されているスクリプトに対して deno cache を事前に実行するようにしています。
Aleph.js を使う場合、それでも事前のビルド処理が不足しています。
この buildpack では、レポジトリルートに heroku_build.ts というファイルを配置することにより、ビルド処理をカスタマイズできるようにしています。

PostgreSQL

データストアとして Heroku の PostgreSQL を利用しています。
以下の PostgreSQL ドライバを利用しています。
https://deno-postgres.com/

Heroku PostgreSQL のフリープランでは、証明書の利用ができないため、デフォルトですと接続エラーになります。
そのため、証明書エラーを無視する必要があります。
Deno では、v1.13 から --unsafely-ignore-certificate-errors オプションで証明書のエラーが無視できるようになっています。
ここは、残念ながらフリープランの制限なようです。

ドライバのコネクションプールについてですが、現在オプション設定が少ないように思えます。
また、自分の使い方もちょっと怪しいため、その影響でタイムアウトになるかもしれません。。

Task Runner について

Node.js の場合、npm に Task Runner の機能が含まれていると思います。
Deno 標準では同様のものがありません。
サードパーティーのもで velociraptor というツールがあります。
https://velociraptor.run/

今回、このツールを利用せず、単純に TypeScript でスクリプトを書いて shebang で実行するようにしています。
tasks.ts というファイルを作成しています。

以下のようにパラメータなしで実行すると指定可能なタスクの一覧が表示されます。

$ ./tasks.ts
test
dev
start
deploy
clean
logs

パラメータにタスク名を指定するとそのタスクを実行できます。
複数指定可能です。
キャッシュを消した後に dev モードで起動する場合は、以下のようなコマンドになります。

$ ./tasks.ts clean dev

ちなみにシバンで実行するため tasks.ts 最初の行を以下のようにしています。

#!/usr/bin/env -S deno run -A --unstable --no-check

-A オプションで全許可しているので、セキュリティーを考慮し、スクリプト内ではサードパーティーのモジュールに依存(import)しないようにしています(ちなみに velociraptor はサードパーティーモジュールに依存しています)。

おわりに

今回は、Heroku を利用しましたが、せっかっく Deno を使っているので将来的には Deno Deploy が利用できるようになると良いかと思っています。
Deno のエコシステムは、まだ少なかったり弱い部分があると思いますが、Deno アプリが増えてくると良いですね。

Discussion