🦕

Deno Deployに自己紹介ページを作るサービスを作った

2021/08/17に公開

本記事はtoranoana.deno #0にて発表したものです。
https://yumenosora.connpass.com/event/220025/


Zenn、Twitter、GitHubなど、アカウントを持っているページが増えてくると、各サービスに他サービスのリンクを表示するのが大変になってきます。
こういう場合は、どこかに「リンク一覧」のプロフィールページを作り、そこへのリンクを貼るようにすれば管理が楽です。

既存のサービスとして、Linktreeというものがあります。
https://linktr.ee/

ただ、個人的にはリンクだけを管理したいわけではありません。
普通にプロフィール項目も箇条書きのように表示できたら良いじゃないかな、と思いました。

ということでDeno Deployの勉強も兼ねて自作しました。
サービスとして他の人も使える形で公開したので紹介します。

Denote

https://github.com/kawarimidoll/denote
Denote -A minimal profile page generator for Deno Deploy- です。

"Denote"というのはDeno x Note…というのも意識していますが、そもそもdenoteという動詞があるのです。

by weblio

こちらがデモページです。
https://denote.deno.dev/denote

こんな感じになります。


やっぱりDenoといったら夜の雨だよな〜〜!

全体のバランス(アイコンの下に項目のリストがある構成)はLinktreeを踏襲しましたが、ページ内で項目が分かれていたり、雨が降っていたりするところはオリジナルです。

kawarimidollのプロフィールページはこちら。

https://denote.deno.dev/kawarimidoll

OGP設定もしているので、Zenn等に埋め込んだときに良い感じに情報が表示されます。

API

登録・更新

エンドポイント

POST https://denote.deno.dev/

登録と更新をPOST/PUTで分けず、同一のものとしました。
これは(後述しますが)GitHub Actions等で自動化する際にそちらのほうが都合が良いと考えたためです。

パラメータ

  • name ページ名
  • token トークン(更新・削除の際に参照される 変更不可)
  • config リスト項目やメイン画像などの設定のJSON

新規登録の際は任意のトークンを使用できますが、更新の際は名前・トークンが一致していないとエラーになります。

削除

エンドポイント

DELETE https://denote.deno.dev/

パラメータ

  • name ページ名
  • token トークン(登録時に設定したもの)

表示

エンドポイント

GET https://denote.deno.dev/[name]

CLI

上記のAPIにcurlなどでリクエストを投げれば登録等をできるのですが、設定項目が増えるとconfigに長大なJSONが載ることになり、運用が難しくなります。

curl -X POST -d '{"name":"my-name","token":"my-token","config":{"list":{"id-1":{"icon":"fontawesome/font-awesome","items":[{"icon":"jam/info","text":"this is a text with an icon"},{"text":"this is a just text"},{"icon":"octicons/octoface","text":"this is a link to GitHub","link":"https://github.com"},{"text":"this is a link to Twitter","link":"https://twitter.com"},{"link":"https://gitlab.com"}]},"id-2":{"icon":"feather/anchor","items":[{"icon":"clarity/block","text":"this is the second block"},{"icon":"simple/deno"}]}}}}' https://denote.deno.dev

設定項目はテキストベースで管理して、それをDenoteに反映させたいと思いました。

そこで、ローカルのJSON/YAMLファイルをパースして、https://denote.deno.devへのリクエストを行うスクリプトを作りました。
deno installによってCLIツールとしてインストールすることができます。

つかいかた

https://deno.land/x/denote

インストール

下記のコードでdenoteという名前でインストールできます。
名前を変えたい場合は--name hogehogeでリネーム可能です。

❯ deno install --allow-read --allow-write --allow-net --no-check --force https://deno.land/x/denote/cli/denote.ts

初期設定の生成

denote initで最小限の設定ファイルを生成します。
ファイルはJSONまたはYAMLですが、YAMLのほうには解説コメントが載ります。

❯ denote init ./config.yml

登録・更新

denote registerで設定ファイルをDenoteへ反映します。
--nameおよび--tokenオプションは必須です。
なお、「設定ファイルをローカルで管理する」と書いていましたが、Denoの仕様上、Web上に公開されているファイルでも指定可能です。
つまり設定をGistに置いて、ローカルからdenote registerを実行して公開するということもできます[1]

❯ denote register ./config.yml --name my-name --token my-token

削除

denote unregisterで公開されているページを削除します。
--nameおよび--tokenオプションは必須です。

❯ denote unregister --name my-name --token my-token

ローカルサーバーでの確認

denote serveでローカルサーバーを立てられます。
公開前に表示を確認したい場合にどうぞ。

❯ denote serve ./config.yml

自動実行

CLIを作ったと書きましたが、deno runで公開URLを直接叩けばインストール不要で実行可能です。
つまりGitHub Actionsでdenote registerを動かせば、自動でDenoteを更新できます。

.github/workflows/denote_profile.yml
name: Denote profile
on:
  push:
    branches: [master]

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v2
      - uses: denoland/setup-deno@v1
      - run: >
          deno run --allow-read --allow-net --no-check
          https://deno.land/x/denote/cli/denote.ts register ./denote.yml
          --name kawarimidoll --token '${{ secrets.DENOTE_TOKEN }}'

これをやる際に、新規登録と更新で分岐するのが難しいため、Denoteの登録・更新APIを一緒にしてしまったのでした。

kawarimidollのプロフィールリポジトリで動いています。
https://github.com/kawarimidoll/kawarimidoll/blob/master/.github/workflows/denote_profile.yml

設定ファイル

設定ファイルはJSONまたはYAMLで記述します[2]

リポジトリにexample.ymlを置いています(実はdenote initはこれをダウンロードしているだけです)。
https://github.com/kawarimidoll/denote/blob/main/example.yml

必須項目

トップレベルにlistというキーが必須です。
その配下がちょっと複雑なので、example.ymlで説明します。

example.yml
list:
  id-1:
    icon: fontawesome/font-awesome
    items:
      - icon: jam/info
        text: this is a text with an icon
      - text: this is a just text
      - icon: octicons/octoface
        text: this is a link to GitHub
        link: https://github.com
      - text: this is a link to Twitter
        link: https://twitter.com
      - link: https://gitlab.com
  id-2:
    icon: feather/anchor
    items:
      - icon: clarity/block
        text: this is the second block
      - icon: simple/deno
  • listは配下に任意の名前のキーを持ちます。
    • このlistの子(上記のid-1id-2)がグループとして扱われます。
      • このキーがページ内リンクのIDとして扱われます。
  • グループはiconitemsというキーを持ちます。
    • icon[iconset-name]/[icon-name]という名前の文字列です。
      • 後述するicongramというサービスに載っているアイコンのみ使用できます。
    • itemsはリスト項目の配列です。
  • リスト項目はicontextlinkというキーを持つことができます。
    • これらは3つとも任意です。
    • iconはグループのものと同じく、icongramで表示できるアイコンです。
    • textはリストに表示されるテキストです。
    • linkはリンク先のURLです。textがあればそれが、なければlinkの文字列が表示されたリンクとなります。

任意項目

以下のキーは任意です。

name

ページのトップに表示される名前です。
省略した場合は、登録の際にnameオプションに設定したもの(つまり、表示の際のhttps://denote.deno.dev[name]に入るもの)が使用されます。
また、HTMLファイルのページ名として、name | Denoteの形で使用されます。

image

メイン画像のURLです。
省略した場合は画像なしになります。
OGP設定のog:imageにも反映されるため、埋め込みリンクで表示されます。

favicon

favicon画像のURLです。
省略した場合はDenoteのロゴが使われます。

description

上記nameの下に表示される説明というかコメントです。
省略した場合はコメントなしになります。
OGP設定のog:descriptionにも反映されるため、埋め込みリンクで表示されます。

twitter

OGP設定のtwitter:siteで使用されるtwitterユーザー名です[3]
省略した場合は単にスキップされます。

技術情報

データの保存

DynamoDBに受け取ったデータを保存しています。
これは公式のチュートリアルをかなり参考にしました。

https://deno.com/deploy/docs/tutorial-dynamodb

ルーティングにsiftを使っているのもチュートリアルそのままです。

ただし、受け取ったデータは全てをそのまま保存するのではなく、tokenはHash化、configはgzip圧縮しています。

https://deno.land/std/hash
https://deno.land/x/compress

自作ライブラリでタグを生成

siftでJSX/TSXを書けるのですが、HTMLタグペアを書きたくない…という思いが強いので、自作のライブラリを使用しています。

https://deno.land/x/markup_tag

以下の記事で公開したものです。
https://zenn.dev/kawarimidoll/articles/6022552f509b84

github-contributions-apiで使うために作ったものですが、結構気に入っています。
https://zenn.dev/kawarimidoll/articles/b573f617a51c0b

icongramからアイコンを表示

アイコンの表示にはicongramというサービスを使っています。

https://icongr.am/

  • 👍 メリット
    • 共通の表記(https://icongr.am/[icon-set]/[icon-name].svg)で複数のサービスのアイコンを呼び出せる
    • 各種サービスの巨大なCSSを読み込むことなく必要なアイコンだけを表示できる
  • 👎 デメリット
    • 最新のアイコンが反映されていない
    • Herokuにホスティングされており表示にラグが出る場合あり

おわりに

じつは最初のアイデアから2点の方針転換がありました。

ひとつはサーバーの扱いです。
最初はkt3k/deploy_dirを使い、設定項目も全て含めた単一のサーバーファイルを生成していました。
これだと表示は高速なのですが、生成されるserver.jsを都度コミットしなければならない構成でした。
自分専用ならそれでも良いのですが、https://denote.deno.dev/xxxのパスで色んな人がアクセスできるようにしたほうが面白いかな?と考えて方針転換しました。
結果的にDynamoDBの勉強もすることができてよかったです。

また、見た目も最初は白背景のシンプルな感じでした。
せっかくDenoなので夜にして雨を降らせたいな〜と思っていろいろ調べて調整しました。
結果的に良い感じの見た目に仕上げることができたと思うので満足です。
https://twitter.com/KawarimiDoll/status/1422858096234274816

ちょっとまだイケてない部分があるかもしれませんが、是非(使用|Star|フォロー|フィードバック)してもらえると非常に嬉しいです。

今後もDenoでいろいろ作っていきますのでよろしくおねがいします🥳

脚注
  1. あまりメリットが思い浮かびませんが ↩︎

  2. YAMLパーサで共通で処理できるためです ↩︎

  3. いまいちこれを設定する意味がわかっていない… ↩︎

Discussion