-
Notifications
You must be signed in to change notification settings - Fork 778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: implement service bindings + local mode dev
#1040
Comments
Instead of creating a new issue, I figured it would be better to have this discussion here. Wanted to share my use of service bindings so far to find out of I've got a reliable approach. For context, I have an app that runs on two workers. Worker A renders a web application and calls to Worker B (JSON API) for data using a service binding. In local development, I prefer running everything with From worker A, before I render the web app to an HTML string, I have to provide a Here's about what it looks like in code: // render-browser.tsx
import { hydrate } from "solid-js/web"
import { App } from "./app"
import { FetchCtx } from "./global-ctx"
hydrate(
() => (
<FetchCtx.Provider value={fetch}>
<App />
</FetchCtx.Provider>
),
document,
) // render-worker.tsx
import { renderToStringAsync } from "solid-js/web"
import { App } from "./app"
import { FetchCtx } from "./global-ctx"
export async function renderAppToString(props): Promise<string> {
return renderToStringAsync(() => (
<FetchCtx.Provider value={props.fetch}>
<App />
</FetchCtx.Provider>
))
} // worker.tsx
import { getAssetFromKV } from "@cloudflare/kv-asset-handler"
import { $fetch } from "ohmyfetch"
import { renderAppToString } from "./render-worker"
export default {
async fetch(request: Request, env: any, ctx: any): Promise<Response> {
const url = new URL(request.url)
if (/\.\w+/.test(url.pathname)) {
return getAssetFromKV(/**/)
}
let appAsStr = await renderAppToString({
fetch: async (req, opts) => {
// Use service bound fetch if exists, otherwise use builtin
let $$ = $fetch.create({
fetch: env.api?.fetch ? (...x) => env.api.fetch(...x) : fetch,
})
return $$(req, opts)
},
})
return new Response("<!doctype html>" + appAsStr, {
headers: { "Content-Type": "text/html;charset=UTF-8" },
})
},
} So far this works, but I have some thoughts and questions:
All around, love what's happening here and what this enables for folks. Cheers! |
This is really cool @chrstntdd. Thanks for the write up. I think what you are doing is pretty much the best you can manage right now. I like the way you use the |
Ah yeah, apologies for leaving that bit out. It's not too involved at the moment, but it goes like this: // env.ts
// `ENV` is injected by the build scripts with process.env.NODE_ENV or equivalent.
export const API_ENDPOINT = ENV === "production" ? "https://api.<WORKER>.com" : "http://localhost:3001" And the usage within the application like so: import { createResource } from "solid-js"
import { API_ENDPOINT } from "./config/env"
import { useFetch } from "./global-ctx"
export function App() {
let fetch = useFetch()
let [x] = createResource(`${API_ENDPOINT}/get-some-data`, async (key) => {
let content = await fetch(key)
return content
})
return (
<section>
<div>SSR data from worker:</div>
<pre>{JSON.stringify(x(), null, 2)}</pre>
</section>
)
} |
Hey @chrstntdd, would you like to try the solution we just landed in |
Hey @threepointone! // ...
fetch: async (req, opts) => {
let $$ = $fetch.create({
fetch: (...x) => env.api.fetch(...x),
})
return $$(req, opts)
}, Many thanks for the fixture you put together here 😄 |
Hi @threepointone, has this feature already merged into |
Service bindings (
[services]
) works with remote mode in wrangler dev, we should figure out how to do the same for local mode. This is part of the broader picture for multi worker, but filing this as a followup for #906 anyway.The text was updated successfully, but these errors were encountered: