From b726ad964aebf3f3713882978243d73f8b8454bf Mon Sep 17 00:00:00 2001 From: Vladimir Kutepov Date: Tue, 12 Mar 2024 23:12:32 +0700 Subject: [PATCH 1/2] WebSocket Support --- docs/routes/advanced/websocket.mdx | 53 ++++++++++++++++++++++ examples/experiments/app.config.ts | 3 +- examples/experiments/src/websocket.ts | 29 ++++++++++++ packages/start/config/index.d.ts | 1 + packages/start/config/index.js | 61 +++++++++++++++++++++++++- packages/start/package.json | 4 ++ packages/start/src/websocket/index.tsx | 9 ++++ 7 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 docs/routes/advanced/websocket.mdx create mode 100644 examples/experiments/src/websocket.ts create mode 100644 packages/start/src/websocket/index.tsx diff --git a/docs/routes/advanced/websocket.mdx b/docs/routes/advanced/websocket.mdx new file mode 100644 index 000000000..7108f3713 --- /dev/null +++ b/docs/routes/advanced/websocket.mdx @@ -0,0 +1,53 @@ +--- +section: advanced +title: WebSocket +order: 8 +--- + +# WebSocket + +WebSocket may be included by passing file you specify in your start config. + +```js +import { defineConfig } from "@solidjs/start/config"; + +export default defineConfig({ + websocket: "./src/websocket.ts" +}); +``` + +Inside the websocket file, you can export a `createWebSocket` function. + +```tsx +import { createWebSocket } from "@solidjs/start/websocket"; + +export default createWebSocket({ + upgrade(req) { + console.log(`[ws] upgrading ${req.url}...`) + return { + headers: {} + } + } + + open(peer) { + console.log(`[ws] open: ${peer}`); + }, + + message(peer, message) { + console.log("[ws] message", peer, message); + if (message.text().includes("ping")) { + peer.send("pong"); + } + }, + + close(peer, event) { + console.log("[ws] close", peer, event); + }, + + error(peer, error) { + console.log("[ws] error", peer, error); + }, +}); +``` + +See API reference on https://crossws.unjs.io/ diff --git a/examples/experiments/app.config.ts b/examples/experiments/app.config.ts index 598716fd8..97a0fb0f1 100644 --- a/examples/experiments/app.config.ts +++ b/examples/experiments/app.config.ts @@ -1,5 +1,6 @@ import { defineConfig } from "@solidjs/start/config"; export default defineConfig({ - middleware: "./src/middleware.ts" + middleware: "./src/middleware.ts", + websocket: "./src/websocket.ts" }); diff --git a/examples/experiments/src/websocket.ts b/examples/experiments/src/websocket.ts new file mode 100644 index 000000000..d0cd66055 --- /dev/null +++ b/examples/experiments/src/websocket.ts @@ -0,0 +1,29 @@ +import { createWebSocket } from "@solidjs/start/websocket"; + +export default createWebSocket({ + upgrade(req) { + console.log(`[ws] upgrading ${req.url}...`) + return { + headers: {} + } + } + + open(peer) { + console.log(`[ws] open: ${peer}`); + }, + + message(peer, message) { + console.log("[ws] message", peer, message); + if (message.text().includes("ping")) { + peer.send("pong"); + } + }, + + close(peer, event) { + console.log("[ws] close", peer, event); + }, + + error(peer, error) { + console.log("[ws] error", peer, error); + }, +}); diff --git a/packages/start/config/index.d.ts b/packages/start/config/index.d.ts index d9c62f8bc..362551ed0 100644 --- a/packages/start/config/index.d.ts +++ b/packages/start/config/index.d.ts @@ -16,6 +16,7 @@ type SolidStartInlineConfig = { appRoot?: string; routeDir?: string; middleware?: string; + websocket?: string; devOverlay?: boolean; experimental?: { islands?: boolean; diff --git a/packages/start/config/index.js b/packages/start/config/index.js index d84d8919f..491f4f2f0 100644 --- a/packages/start/config/index.js +++ b/packages/start/config/index.js @@ -51,7 +51,8 @@ export function defineConfig(baseConfig = {}) { solid: {}, server: { experimental: { - asyncContext: true + asyncContext: true, + websocket: Boolean(start.websocket) } } }); @@ -256,7 +257,63 @@ export function defineConfig(baseConfig = {}) { }) ]; } - } + }, + + ...(start.websocket + ? [ + { + name: "websocket", + type: "http", + base: "/_ws", + handler: start.websocket, + middleware: start.middleware, + extensions, + target: "server", + plugins: async () => { + const userConfig = typeof vite === "function" ? await vite({ router: "server" }) : { ...vite }; + const plugins = userConfig.plugins || []; + delete userConfig.plugins; + return [ + config("user", { + ...userConfig, + optimizeDeps: { + ...(userConfig.optimizeDeps || {}), + include: [ + ...(userConfig.optimizeDeps?.include || []), + "@solidjs/start > source-map-js", + "@solidjs/start > error-stack-parser" + ] + } + }), + ...plugins, + solid({ ...start.solid, ssr: start.ssr, extensions: extensions.map(ext => `.${ext}`) }), + config("app-server", { + resolve: { + alias: { + "#start/app": join(process.cwd(), start.appRoot, `app${entryExtension}`), + "~": join(process.cwd(), start.appRoot), + ...(!start.ssr + ? { + "@solidjs/start/server": "@solidjs/start/server/spa" + } + : {}), + ...userConfig.resolve?.alias + } + }, + cacheDir: "node_modules/.vinxi/websocket", + define: { + "import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands), + "import.meta.env.SSR": JSON.stringify(true), + "import.meta.env.START_SSR": JSON.stringify(start.ssr), + "import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay), + ...userConfig.define + } + }) + ]; + } + } + ] + : []) ] }); } diff --git a/packages/start/package.json b/packages/start/package.json index 602d66228..8aa22d67b 100644 --- a/packages/start/package.json +++ b/packages/start/package.json @@ -21,6 +21,7 @@ ".": "./dist/index.jsx", "./config": "./config/index.js", "./middleware": "./dist/middleware/index.jsx", + "./websocket": "./dist/websocket/index.jsx", "./router": "./dist/router/index.jsx", "./server": "./dist/server/index.jsx", "./server/spa": "./dist/server/spa/index.jsx", @@ -36,6 +37,9 @@ "middleware": [ "./dist/middleware/index.d.ts" ], + "websocket": [ + "./dist/websocket/index.d.ts" + ], "router": [ "./dist/router/index.d.ts" ], diff --git a/packages/start/src/websocket/index.tsx b/packages/start/src/websocket/index.tsx new file mode 100644 index 000000000..918c385eb --- /dev/null +++ b/packages/start/src/websocket/index.tsx @@ -0,0 +1,9 @@ +// @refresh skip +import { defineWebSocket, eventHandler } from "vinxi/http"; + +export function createWebSocket(args: Parameters) { + return eventHandler({ + handler: () => {}, + websocket: defineWebSocket(args) + }); +} From 8d5d498fd4817982a505b6b6afb46239b7b8cb8a Mon Sep 17 00:00:00 2001 From: Vladimir Kutepov Date: Sat, 10 Aug 2024 18:23:08 +0700 Subject: [PATCH 2/2] Update examples/experiments/src/websocket.ts Co-authored-by: chee --- examples/experiments/src/websocket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/experiments/src/websocket.ts b/examples/experiments/src/websocket.ts index d0cd66055..30781f0df 100644 --- a/examples/experiments/src/websocket.ts +++ b/examples/experiments/src/websocket.ts @@ -6,7 +6,7 @@ export default createWebSocket({ return { headers: {} } - } + }, open(peer) { console.log(`[ws] open: ${peer}`);