From ad0ed1c6fad12f995b4dde0293e869ad2a744e9e Mon Sep 17 00:00:00 2001 From: tknkaa Date: Wed, 9 Apr 2025 10:55:51 +0900 Subject: [PATCH 01/17] write a title --- src/content/docs/web-api/t2-websocket.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/content/docs/web-api/t2-websocket.md diff --git a/src/content/docs/web-api/t2-websocket.md b/src/content/docs/web-api/t2-websocket.md new file mode 100644 index 0000000..ece7eec --- /dev/null +++ b/src/content/docs/web-api/t2-websocket.md @@ -0,0 +1,3 @@ +--- +title: WebSocket API +--- \ No newline at end of file From c920c6b7cbefc96d1c64405af8c1ab22f5880dda Mon Sep 17 00:00:00 2001 From: tknkaa Date: Wed, 9 Apr 2025 16:40:08 +0900 Subject: [PATCH 02/17] write a intro --- src/content/docs/web-api/t2-websocket.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/content/docs/web-api/t2-websocket.md b/src/content/docs/web-api/t2-websocket.md index ece7eec..c0ed8e7 100644 --- a/src/content/docs/web-api/t2-websocket.md +++ b/src/content/docs/web-api/t2-websocket.md @@ -1,3 +1,8 @@ --- -title: WebSocket API ---- \ No newline at end of file +title: WebSocket +--- + +## WebSocket について +ut.code(); Learn では ToDo アプリを通じてフルスタックアプリの開発について学んできましたが、ここではチャットアプリを作ることを考えてみましょう。チャットアプリでは、ユーザー A がサーバーにメッセージを送ったときに、ユーザー B の画面にもそのメッセージが表示される必要があります。つまり、サーバーからクライアントへイベントを送信する必要があるのです。そこで、[WebSocket](https://developer.mozilla.org/ja/docs/Web/API/WebSockets_API) や [Server-Sent Events](https://developer.mozilla.org/ja/docs/Web/API/Server-sent_events/Using_server-sent_events) を用います。 +今回は特に WebSocket を用いてチャットアプリを作ってみます。WebSocket とは、双方向通信を行うためのプロトコルで、初回リクエストは HTTP を用いますが、そこからは TCP 上で動きます。 + From b2cdfdf997acd5bfcf86e3281496f3d59fca540b Mon Sep 17 00:00:00 2001 From: tknkaa Date: Wed, 21 May 2025 22:47:53 +0900 Subject: [PATCH 03/17] change intro a little --- src/content/docs/web-api/t2-websocket.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/web-api/t2-websocket.md b/src/content/docs/web-api/t2-websocket.md index c0ed8e7..7470d51 100644 --- a/src/content/docs/web-api/t2-websocket.md +++ b/src/content/docs/web-api/t2-websocket.md @@ -4,5 +4,5 @@ title: WebSocket ## WebSocket について ut.code(); Learn では ToDo アプリを通じてフルスタックアプリの開発について学んできましたが、ここではチャットアプリを作ることを考えてみましょう。チャットアプリでは、ユーザー A がサーバーにメッセージを送ったときに、ユーザー B の画面にもそのメッセージが表示される必要があります。つまり、サーバーからクライアントへイベントを送信する必要があるのです。そこで、[WebSocket](https://developer.mozilla.org/ja/docs/Web/API/WebSockets_API) や [Server-Sent Events](https://developer.mozilla.org/ja/docs/Web/API/Server-sent_events/Using_server-sent_events) を用います。 -今回は特に WebSocket を用いてチャットアプリを作ってみます。WebSocket とは、双方向通信を行うためのプロトコルで、初回リクエストは HTTP を用いますが、そこからは TCP 上で動きます。 +今回は特に WebSocket を用いてチャットアプリを作ってみます。WebSocket とは、双方向通信を行うためのプロトコルで、HTTP リクエストのように一度きりではなく、一度確立されると接続が維持され続けます。接続確立時(ハンドシェイク時)には HTTP を利用しますが、その後のメッセージには HTTP ヘッダーがなく軽量です。 From 53b681c840cd643380d0ccfcb587c30a84fa5adb Mon Sep 17 00:00:00 2001 From: tknkaa Date: Fri, 23 May 2025 23:20:55 +0900 Subject: [PATCH 04/17] feat: Add WebSocket chat app example with Bun's Pub/Sub --- src/content/docs/web-api/t2-websocket.md | 173 +++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/src/content/docs/web-api/t2-websocket.md b/src/content/docs/web-api/t2-websocket.md index 7470d51..ef884ca 100644 --- a/src/content/docs/web-api/t2-websocket.md +++ b/src/content/docs/web-api/t2-websocket.md @@ -6,3 +6,176 @@ title: WebSocket ut.code(); Learn では ToDo アプリを通じてフルスタックアプリの開発について学んできましたが、ここではチャットアプリを作ることを考えてみましょう。チャットアプリでは、ユーザー A がサーバーにメッセージを送ったときに、ユーザー B の画面にもそのメッセージが表示される必要があります。つまり、サーバーからクライアントへイベントを送信する必要があるのです。そこで、[WebSocket](https://developer.mozilla.org/ja/docs/Web/API/WebSockets_API) や [Server-Sent Events](https://developer.mozilla.org/ja/docs/Web/API/Server-sent_events/Using_server-sent_events) を用います。 今回は特に WebSocket を用いてチャットアプリを作ってみます。WebSocket とは、双方向通信を行うためのプロトコルで、HTTP リクエストのように一度きりではなく、一度確立されると接続が維持され続けます。接続確立時(ハンドシェイク時)には HTTP を利用しますが、その後のメッセージには HTTP ヘッダーがなく軽量です。 +## 早速つなげてみよう +フロントエンドは `bun create vite@latest web`、バックエンドは `bun create hono@latest server` でそれぞれのディレクトリを作成します。 +```svelte +// /web/src/App.svelte + + +
message: {message}
+ +``` +```ts +// /server/src/index.ts +import { Hono } from "hono" +import { createBunWebSocket } from "hono/bun" +import { type ServerWebSocket } from "bun" + +const { upgradeWebSocket, websocket } = createBunWebSocket() + +const app = new Hono() + +app.get("/", (c) => { + return c.text("Hello Hono") +}) + +app.get( + "/ws", + upgradeWebSocket((c) => { + return { + onMessage(event, ws) { + console.log(`Message from client: ${event.data}`) + ws.send("Hello from server!") + }, + onClose: () => { + console.log("Connection closed") + }, + } + }) +) + +export default { + fetch: app.fetch, + websocket +} +``` + +## Bun の Pub/Sub 機能について +サーバーがどのクライアントにメッセージを送るべきかを考えてみましょう。 +たとえばチャットアプリでは、自分が送ったメッセージを自分に返しても意味がないし、関係ない人全員に見せてしまうのも困りますよね。 +そこで役立つのが「Pub/Sub(パブ・サブ)機能」です。 +これは、「トピック」という名前のグループを作り、 + +- 誰かがトピックにメッセージを送る(publish) + +- そのトピックに登録している人だけがメッセージを受け取る(subscribe) + +という仕組みです。 +たとえば「room1」というチャットルームにいる人だけが「room1」に送られたメッセージを受け取る、そんなイメージです。 +Bunでは、このPub/Subの仕組みを簡単に使えるAPIが用意されています。 + +## リアルタイムチャットアプリを作ってみよう +ディレクトリ構成は先ほどのまま、ファイルを書き換えてみましょう。 +```svelte +// /web/src/App.svelte + + +
    + {#each messages as message} +
  • {message.text}
  • + {/each} +
+ + + +``` + +```ts +// /server/src/index.ts +import type { ServerWebSocket } from "bun"; +import { Hono } from "hono"; +import { createBunWebSocket } from "hono/bun"; +import { cors } from "hono/cors"; + +const { upgradeWebSocket, websocket } = createBunWebSocket(); + +type Message = { + text: string; +}; + +const messages: Message[] = [{ text: "Hello" }]; + +const chatRoom = "chat-room"; + +const app = new Hono(); + +const server = Bun.serve({ + fetch: app.fetch, + websocket, +}); + +app.use("/*", cors()); + +app.get("/", (c) => { + return c.text("Hello Hono"); +}); + +app.post("/message", async (c) => { + const message: Message = await c.req.json(); + messages.push(message); + server.publish(chatRoom, JSON.stringify(messages)); + return c.text("hoge"); +}); + +app.get( + "/ws", + upgradeWebSocket((c) => { + return { + onOpen(event, ws) { + ws.raw?.subscribe(chatRoom); + ws.send(JSON.stringify(messages)); + }, + onClose: (event, ws) => { + ws.raw?.unsubscribe(chatRoom); + }, + }; + }), +); + +export default app; + +``` \ No newline at end of file From 82c2ba2112cafe75d72749bd3ec1fed039f2e79c Mon Sep 17 00:00:00 2001 From: tknkaa Date: Fri, 23 May 2025 23:25:39 +0900 Subject: [PATCH 05/17] docs: Clarify WebSocket topic description --- src/content/docs/web-api/t2-websocket.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/content/docs/web-api/t2-websocket.md b/src/content/docs/web-api/t2-websocket.md index ef884ca..7b207ea 100644 --- a/src/content/docs/web-api/t2-websocket.md +++ b/src/content/docs/web-api/t2-websocket.md @@ -72,7 +72,6 @@ export default { これは、「トピック」という名前のグループを作り、 - 誰かがトピックにメッセージを送る(publish) - - そのトピックに登録している人だけがメッセージを受け取る(subscribe) という仕組みです。 From c6ac8f020aa74d36d2a2f620a913b6155a19187b Mon Sep 17 00:00:00 2001 From: tknkaa Date: Fri, 23 May 2025 23:54:48 +0900 Subject: [PATCH 06/17] feat: Implement real-time chat with WebSocket in t2-websocket.md --- src/content/docs/web-api/t2-websocket.md | 27 ++++++++---------------- 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/content/docs/web-api/t2-websocket.md b/src/content/docs/web-api/t2-websocket.md index 7b207ea..972a5eb 100644 --- a/src/content/docs/web-api/t2-websocket.md +++ b/src/content/docs/web-api/t2-websocket.md @@ -79,7 +79,7 @@ export default { Bunでは、このPub/Subの仕組みを簡単に使えるAPIが用意されています。 ## リアルタイムチャットアプリを作ってみよう -ディレクトリ構成は先ほどのまま、ファイルを書き換えてみましょう。 +ディレクトリ構成は先ほどのまま、ファイルを書き換えてみましょう。以下のコードでは、あるタブで送信したメッセージが、他のタブにもリアルタイムで反映されます。 ```svelte // /web/src/App.svelte