😺

Deno deployを遊ぶなら今がチャンス!

2021/12/11に公開

はじめに

本記事の正確性等は一切保証できませんが、理解の誤りや、誤植・手順漏れ等、コメント・ご指摘に関しては何でも頂ければ幸いです。マサカリは優しく投げてください。

この記事で書くこと・書かないこと

書くこと

  • TypeScript/Denoは良いよねって話
  • Deno Deployの良いところ・辛いところ
  • こんな感じのものが作れるよ

あまり書かないこと

  • 他類似サービスとの比較(Cloudflare Workers, Heroku等)
  • トラブルシューティング詳細
  • 作ったサンプルの詳細

Deno、好きかも…

これまで散々書かれたDenoのいいところの話です。
ここまでも、ここからも、全部一個人の感想。

TypeScriptは良い

TypeScript、良いですよね。
現チームではClient/Server SideのいずれもTypeScriptで書いているので、彼のこと好きになっちゃいました。最近はもっぱらServer SideもすべてTypeScript/Node.jsで書いています。

僕がTypeScriptを好きな理由は、こんな感じです。

  • 型を定義したあとに実装を書ける。型に導かれながら実装できている実感を得られて安心感がつよい。
  • 程よく関数型っぽくも書ける。そのうち構造的パターンマッチも欲しくなる。
  • 程よくオブジェクト指向っぽくも書ける。構造的部分型なので適度にゆるい。

特に1個めの、型定義から実装の順番で書けるのは個人的にすごくありがたい。
あまり頭が良い方ではないので、「かくあれかし」で書いた通りに動くことはめったになく、だからこそコンパイラがちゃんと教えてくれる安心感はつよい。

でも、TypeScript(とJavaScript/Node.js)はつらいですよね。
未だにtsconfig.jsonpackage.jsonnode_modules等で何か問題が出たときには解決までに時間を要することが多々ありますし、prettierlinterを入れるのも一苦労、新しいフレームワークを試すときにはサンプルプロジェクトを動かしただけで何だか一仕事終えた気持ちになったりします。
僕はただhello worldに毛をはやしたようなCLIツールをピャッと作って、シングルバイナリでDeployしたいだけなのに…。(Go使え)

Denoも良い

TypeScriptを好きだから、TypeScriptに苦しめられているアンビバレントな皆さん。
Denoは一筋の光明になるかもしれません(なるといいですね)。

Denoはあなたを、tsconfig.jsonpackage.json, node_modulesから解放し、各種エコシステムをdenoコマンドに集約し、シングルバイナリのビルドまでやってくれる、ありがたいTypeScript/JavaScriptランタイムです。

他にもいろいろ、Node.jsをよりセキュアにするための権限制御の機能や、ブラウザ互換のWeb API実装などに利点があるようですが、そのあたり詳細は公式にて。

https://deno.land/

ともかく、ちょっとしたツールを作るならDenoはわりかし有効で、個人的には最近のイチオシです。

Deno Deploy、好きかも…

What is

手軽に、インターネットからリーチ可能なBackend Server欲しくなるときありませんか、僕はあります。

永続化する(収益の見込める)Serviceなら良いですが、仲間内で遊ぶためのServiceだったりすると、わざわざクレカを登録して~とかあんまりやりたくないですよね。心理的ハードルが上がりますし、誤ってクラウド破産するのも怖いです。

そんなわがままを叶えてくれるサービスとして、Deno Deployがあります。
Denoで書いたModuleをGithubのPub Repoに上げて、Deno Deployのコンソールからエントリーポイントを指定するだけで、Webサーバーが立つ時代が来ました。Herokuみたいですね。

Deno Deploy is a distributed system that runs JavaScript, TypeScript, and WebAssembly at the edge, worldwide.
引用: https://deno.com/deploy

この記事では、Deno Deployを使ってどれくらいかんたんにService公開までできるか、半日クッキングしていきたいと思います。

Deno Deploy、今ならタダ!

During the initial public beta for Deno Deploy the service is free to use. Once Deno Deploy reaches General Availablity, detailed pricing will be announced.
引用: https://deno.com/deploy/docs/pricing-and-limits

the service is free to use.
the service is free to use.
the service is free to use.
the service is free to use.

アツい、今がチャンス!!
Project数の制限もない(っぽい)のでGA前に遊び倒しましょう。利用規約は守りましょう。

https://deno.com/deploy/docs/fair-use-policy

お試し作成物

かんたんなサバクラ型のチャットツールを作ってみます。

開発記録

Versions

Backend

deno 1.15.3 (release, x86_64-unknown-linux-gnu)
v8 9.5.172.19
typescript 4.4.2

Frontend

npx 8.1.0
create-react-app 4.0.3
dependencies
{
    "@testing-library/jest-dom": "^5.16.1",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.2"
}

Code

backend/mod.ts
import { serve } from "https://deno.land/std@0.114.0/http/server.ts";

const sockets = new Set<WebSocket>();

const handleConnected = () => {
  console.log("Connected to client ...");
};

const broadCast = (sockets: Set<WebSocket>, data: string) =>{
  console.log(data)
  sockets.forEach((ws) => ws.send(data));}

const handleError = (e: Event | ErrorEvent) =>
  console.log(e instanceof ErrorEvent ? e.message : e.type);

serve(async (req: Request): Promise<Response> => {
  if (req.headers.get("upgrade") != "websocket") {
    return new Response(null, { status: 501 });
  }

  const { socket: ws, response } = Deno.upgradeWebSocket(req);
  ws.onopen = () => handleConnected();
  ws.onmessage = (message) => broadCast(sockets, message.data); // 
  ws.onclose = () => console.log("Disconnected from client: ");
  ws.onerror = (e) => handleError(e);

  sockets.add(ws);

  return response;
}, { addr: ":5000" });
client/cli.ts
const yourName = prompt("Your Name: ")

const logError = (msg: string) => {
  console.error(msg);
};

const handleConnected = (ws: WebSocket) => {
  console.log("Connected to server ...");
  handleMessage(ws, "Welcome!");
};

const handleMessage = (ws: WebSocket, data: string) => {
  console.log("SERVER >> " + data);
  const reply = prompt("Client >> ");
  ws.send(`[${yourName}] ${reply ?? "No reply"}`);
};

const handleError = (e: Event | ErrorEvent) =>
  console.log(e instanceof ErrorEvent ? e.message : e.type);
console.log("Connecting to server ...");

try {
  const ws = new WebSocket("wss://<your domain>:5000");
  ws.onopen = () => handleConnected(ws);
  ws.onmessage = (message) => handleMessage(ws, message.data);
  ws.onclose = () => logError("Disconnected from server ...");
  ws.onerror = (e) => handleError(e);
} catch (err) {
  logError("Failed to connect to server ... exiting");
}

Deploy手順

  1. GitHubにRepository作成
  2. Deno DeployにSign-inして[+ New Project]
  3. [Deploy from GitHub]から上記作成したRepo内のEntrypointファイルを選択

動作確認

動いてそう。

ちなみに、デプロイ後はこんな感じの画面で管理できるので、Logの確認であったり、実行時に与える環境変数(左TreeのSettings->Environment Variables)だったりもいじることができます。OutboundのTLS接続をサポートしたので、外部DBとつないだりもできるようです。

ドメイン名晒してしまってますが、記事公開時点では閉じてるか変更してるはずです。

あと、ドメイン名は任意に変更可能っぽいので、好きな名前をつけてみんなと勝負!

終わりに

メチャクチャ簡単に、簡易的なリアルタイムサーバーを建てて遊ぶことができました。
当たり前ですが、DenoのRuntimeしかないのでDeno以外動かないとか、いろいろ制約はあるものの、簡単にいくつものProjectを建てられるのは楽しそう。

VercelでFrontendを動かして、Deno Deployで複数のBackendを動かすことで、簡単なシステムくらいなら自由度高く作れると思うので、いろいろ試してみたいところ。

一方、正直なところDenoのWSライブラリ等の癖がつよかったり、Documentが揃ってなかったりもあってそこそこ躓いたので、ぐーぐるぢからが求められました。
今一番かんたんにBackend Serverを建てるなら、やっぱりふつうにDeno以外のRuntime使ってHerokuでホスティングする、が良い気もしました😄😄😄(おわり)

https://github.com/sandship/deno-deploy-chat

Discussion