withastro / adapters

Home for Astro's core maintained adapters
64 stars 33 forks source link

WebSocket / WebSocketPair not available #154

Open Ehesp opened 8 months ago

Ehesp commented 8 months ago

Astro Info

Astro                    v4.2.6
Node                     v18.17.0
System                   macOS (arm64)
Package Manager          unknown
Output                   server
Adapter                  @astrojs/cloudflare
Integrations             @astrojs/tailwind
                         @astrojs/react

Describe the Bug

I'm running astro with the Cloudflare adapter, and everything is working great apart from the WebSocket and WebSocketPair classes not being available in the server runtime.

export default defineConfig({
  // Mimics the behavior of Wrangler running locally so we don't have to alter the Cloudflare Tunnels
  server: {
    host: true,
    port: 8788,
  },
  // Server output is required for Cloudflare Workers
  output: "server",
  adapter: cloudflare({
    runtime: {
      mode: "local",
      type: "pages",
      bindings: { ... },
   }
  })
})

Local mode says: uses a local runtime powered by miniflare and workerd, which supports Cloudflare’s Bindings.. I might have missed the point here, but I was hoping that those classes would be available since they are on miniflare / workderd?

What's the expected result?

Works just like Cloudflare (as the declarations are available via:

/// <reference types="@cloudflare/workers-types" />

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-8ghpcm?file=src%2Fpages%2Findex.ts

Participation

alexanderniebuhr commented 8 months ago

Thanks for the issue. This is similar to https://discord.com/channels/830184174198718474/1168702512782659664 We still figure out a way to make this available in astro dev. If you build the project and deploy it, it will work already.

Ehesp commented 8 months ago

Thanks! Would it be possible to import https://www.npmjs.com/package/@miniflare/web-sockets and provide it as a global via vite config in the adapter?

Probably not that straightforward 😅

Ehesp commented 8 months ago

I need to validate this actually works, but something like this might be the best workaround for now:

let WebSocketImpl: typeof WebSocket;

if (import.meta.env.DEV) {
  const wsModule = await import("ws");
  WebSocketImpl = wsModule.default as unknown as typeof WebSocket;
} else {
  // Fallback to the global `WebSocket` in production
  WebSocketImpl = WebSocket;
}

let WebSocketPairImpl: typeof WebSocketPair;

if (import.meta.env.DEV) {
  // Use @miniflare/web-sockets in development
  const { WebSocketPair: MFWebSocketPair } = await import(
    "@miniflare/web-sockets"
  );
  WebSocketPairImpl = MFWebSocketPair as unknown as typeof WebSocketPair;
} else {
  // Assume WebSocketPair is globally available in production (Cloudflare Workers)
  WebSocketPairImpl = WebSocketPair;
}

export { WebSocketImpl as WebSocket, WebSocketPairImpl as WebSocketPair };
Ehesp commented 7 months ago

@alexanderniebuhr ive just seen https://vitejs.dev/blog/announcing-vite5-1.html

Would this new api allow us to hook directly into workerd? Found via https://twitter.com/pcattori/status/1755632675103080521?t=C0blapvcX2HNq-zTgw3vpw&s=19

alexanderniebuhr commented 7 months ago

We are looking into this internally already, but that's still experimental.

Ehesp commented 7 months ago

I think this might be moot anyway based on https://github.com/withastro/astro/issues/10057#issuecomment-1934782142 :(