🦕

Deno Deploy専用のSSGを作った

2021/09/22に公開

本記事はtoranoana.deno #1の発表資料です。
https://yumenosora.connpass.com/event/223214/


Deno Deployで動くSSGを作りました。

その名もDiplodocusです。

https://github.com/kawarimidoll/deno-diplodocus

名前のDiplodocusDeploy docsからの連想です。

https://ja.wikipedia.org/wiki/ディプロドクス

なぜつくったか

Denoモジュールや関連プロダクトは増えていますが、解説ドキュメントをGitHub PagesやVercel、Netlifyなどのプラットフォームで運用しているものが多い印象です。
個人的には、Deno用リポジトリにドキュメント用のpackage.jsonが入ったり、ビルドされたHTMLが入ったりすることに違和感がありました。Deno過激派なのでせっかくのDenoプロジェクトなら、ドキュメントのホスティングもDenoに一本化したほうが良いんじゃないかという感覚ですね。

そんな中、Deno DeployがBeta 2にアップデートされ、File system APIが追加されました。
これに関しては以下の記事で紹介しているのでご覧ください。

https://zenn.dev/kawarimidoll/articles/38d5c3d82e6882

今回のDiplodocusは、このAPIをドキュメントサイトの作成に利用できないかと考えて作ったものです。
これでプロジェクトの本体も説明もすべてDenoで完結できます。気持ち良いですね。

機能紹介

こちらのページでデモが稼働中です。

https://diplodocus.deno.dev/

クイックスタート

ここではdocsディレクトリ内のファイルが公開対象、server.tsがエントリーポイントとします。
こちらがディレクトリ構成です。

├── docs/
│  ├── about.md
│  ├── index.md
│  └── pages/
│     ├── 01.md
│     ├── 02.md
│     └── 03.md
└── server.ts

index.mdには以下のようにリンクを入れておくとわかりやすいです。

# index
- [about](/about)
- [page 01](/page/01)
- [page 02](/page/02)
- [page 03](/page/03)

エントリーポイントとなるserver.tsの中身はこんな感じになります。Deno Deploy Beta 2のサンプルとほぼ同様です。

// server.ts
import { Diplodocus } from "https://deno.land/x/diplodocus/mod.ts";

const diplodocus = await Diplodocus.load();

const port = 8080;
const listener = Deno.listen({ port });
console.log(`HTTP server listening on http://localhost:${port}`);

async function handleConn(conn: Deno.Conn) {
  const httpConn = Deno.serveHttp(conn);
  for await (const e of httpConn) {
    e.respondWith(diplodocus.handler(e.request));
  }
}

for await (const conn of listener) {
  handleConn(conn);
}

あとはローカルサーバーを立ち上げればOKです。deno runまたはdeployctlが使えます。

$ deno run --allow-net --allow-read --no-check ./server.ts
$ # deplyctl run --no-check ./server.ts

この例では、以下のページにアクセスできるようになります。

  • http:localhost:8080
  • http:localhost:8080/about
  • http:localhost:8080/page/01
  • http:localhost:8080/page/02
  • http:localhost:8080/page/03

どうやっているか

前述の通り、Deno Deploy用のFile system APIを使い、アクセスされたURLとリポジトリ内のパスを関連付け、対象のファイルを返しています。

https://deno.com/deploy/docs/runtime-fs

このとき、URLに拡張子が明示されていなければ(http:localhost:8080/page/01など)、同名のMarkdownファイルを探し、HTMLにパースします。
URLに拡張子が含まれていれば、Mimeタイプを適切に判定しつつ、ファイルをそのまま返します。

ということで、各ページに関してはSSGというよりSSRシステムなのですが、Markdown以外はServing Static AssetsしているのでSSGと言っても良いかな…と思っています。

また、表示のたびにMarkdownパースが走るので速度面に不安がありましたが、トップページでLighthouseの診断を行ったところ、スコアはなかなか良好でした。

DenoのSSGとして有名なPagicのトップページと比較してみましたが、大きな劣後は見られなかったため問題ないという結論に至りました。

特殊なチューニングをしたわけではないので、単にDeno Deployが速いということですね。すごい。

オプション

クイックスタートで書いたように、最小構成であればserver.tsだけで動作します。
さらに、server.tsと同一階層に設定ファイルを置くことで、様々な挙動を調整可能です。
設定ファイルはdiplodocus.(yaml|yml|json)で、存在すれば自動で読み込みます[1]

例えば、公開するディレクトリをdocs以外にしたり、サイト名やfaviconを設定したり、navbarに項目を追加したりすることが可能です。

設定可能な項目をここに載せると長くなりすぎるので、興味のある方はドキュメントをチェックしてください。
https://diplodocus.deno.dev/docs/02_site_config

推しポイント

単にMarkdownをレンダリングしているだけでないポイントがあるので紹介します。

自動リンク

Markdown文中のURL文字列は、リンク記法[link](https://www.example.com)でなくてもリンクになります。
さらに、外部リンクの場合は自動でtarget="_blank" rel="noopener noreferrer"およびアイコンが付きます。

画像表示

画像記法![image](xxx.png)を使うと、自動で画像がセンタリングされます。

シンタックスハイライト

Prism.jsを使ってシンタックスハイライトをかけています。

任意タグ追加

bottomHeadbottomBodyというオプションがあり、それぞれ<head></head>および<body></body>の末尾に任意の文字列を追加できます。
これにより、ユーザーが自由にスタイルやスクリプトを追加できます。

おわりに

Deno Deploy Beta 2のAPIのおかげで、ほぼ何も設定しなくても動作するものになりました。
上記のbottomHeadbottomBodyオプションを使えば、独自スタイルの追加やAnalyticsタグの設定も可能なので、細かくカスタマイズしたい方のテンプレートとしてもおすすめです。

ご意見・ご要望は大歓迎です。スターもお待ちしております。
https://github.com/kawarimidoll/deno-diplodocus

ちなみに、現時点での悩みは良さげなロゴ(アイコン)デザインが思いつかないことです。
アイコンは円形に収めたいのですが、ディプロドクスをそのまま絵にしようとすると長すぎて枠に入らない…しかし正面から見ると意味不明になる…。
良いアイデアをお持ちの方はご一報ください。

脚注
  1. 複数存在する場合はyamlが最優先、次にyml、最後にjson ↩︎

Discussion