-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Cloudflare Worker Adapter - Durable Objects #1712
Comments
I can look into this feature in the coming days to see how feasible it would be to introduce it as a PR, however, if the issue requires more significant changes to the adapter I might want to wait and consult some others to learn more about the impact this feature request might have. |
I have done some more research and found a few areas the adapter can be improved. Namely, the documentation needs a significant upgrade. The documentation is confusing for new users and does not explain what the Unfortunately, I am struggling with getting ESBuild to bundle the dependencies of a sample project in when using Any help or clarification would be much appreciated! |
As a short update; I managed to get the module syntax fully compiled. I am just waiting for cloudflare to merge my PR of Most notably however, my PR will introduce a breaking change. This will likely need to be discussed further with a larger group of the community. The reason I would like to introduce the breaking change is that eventually cloudflare plans to deprecate the old syntax, and force usage of their new modular syntax. For this reason, I think it makes sense for the modular syntax to be the default for all workers created using this adapter. Luckily, the breaking change in question can easily be mitigated with a clear and concise message informing the users of how to adapt their project to compile, and it only requires a minor two line change to their |
I have the code ready for a PR, I just need to wait until this PR is merged first. |
So, few things going on here: (@DrewRidley and I also spoke in Discord a little bit, so this won't be anything new) Durable Object (DO) development is heavily tied to the ESM format for Workers. So this means that while DOs are in beta (they still are), the ESM format is in beta too, by extension. The adapter should 100% be outputting the ESM variant code only – so that the developer has the freedom to opt into DOs if/when they see fit. However, SvelteKit shouldn't be doing this until DO/ESM development is out of beta. Personally, I have no idea if there are other breaking changes on the docket for either of these, but DO is still under "beta" label intentionally, reserving that right for "last-second" changes. The @DrewRidley Changing the |
@lukeed @DrewRidley Durable Objects are now GA. Do you have the PR? |
Sorry for the delayed response! It looks like the best way to support durable objects is to have a folder of durables that is detected and injected by the adapter. I can have a PR done within the next few days. As for websockets it's probably best that we transparently pass them through in the adapter, and let the user implement them using hooks. |
Any update on this @DrewRidley? |
I'm interest in this part. A home for the DO classes and getting them compiled correctly. Seemingly need to be concatenated?
|
ProblemDurable Object classes have to be defined as named exports on the With Wrangler 2, this is no longer an issue. SolutionUnlike Wrangler 1, Wrangler 2 can resolve es modules. Simply re-export // @file ./custom-worker-entry.js
export { default } from "./.cloudflare/worker.js";
export class MyDurableObject {
// …
} …and update - main = "./.cloudflare/worker.js"
+ main = "./custom-worker-entry.js"
site.bucket = "./.cloudflare/public"
+ [durable_objects]
+ bindings = [{
+ name = "MY_DURABLE_OBJECT",
+ class_name = "MyDurableObject",
+ }] |
If you change export { default } from "./.cloudflare/worker.js"; It seems like we would probably need a way to tell the adapter where our DOs are defined, so that it can then inject something like export * from '../src/my-durable-objects.js';` (which I assume works? will confess only passing familiarity with DOs) |
The main file needs to export the DO class definitions directly, and the names of the classes must align with |
Doh… didn’t test my assumption. Sorry, folks. However, I think enabling this pattern—importing a built module into a “facade” module—makes a lot of sense. Perhaps the
This would enable the Durable Objects use-case, as well as I can take a crack at a PR, pending a maintainer’s approval of the described implementation. Gimme a 👍 if so. |
I'd suggest having the adapter(s) expect a special // src/bindings.ts
// or
// bindings.ts
export { Counter } from './other/counter.ts'; so that the final Worker output is something like: // path/to/build/worker.mjs
class C$1 {
// user source from other/counter.ts
}
export { C$1 as Counter };
const worker$1 = {
// generated (current) worker code
}
export default worker$1; |
What about the 1mb script limit tho? Seems like what we really need is guidance from Cloudflare on how this should work locally with wrangler2 and and Service Bindings (which is surely their preferred way forward, though that’s a guess on my part). Basically, all these options to me look like a surefire way to blow past the 1mb limit in a project of sufficient size, or any project given sufficient time + features. Maybe that’s not such a real concern but still. Since svelte is compiling everything down to a single worker script that’s going to bite someone at some point. note: I don’t have any insight myself, and am actively working with my account manager at Cloudflare to get guidance; the “Cloudflare way” doesn’t seem well-articulated yet. (Would love to be wrong about that tho.) |
Sorry but this concern is irrelevant because it's also applicable to every Worker authored. The point of SK here is to automate/produce a Worker file without the user having to write actual the Worker code from scratch. All Workers users – regardless of framework choice, if at all – will still be deploying the same end-results abiding by the same end-user limits. Every account exec can have the script size limits raise from 1MB, if necessary, although I strongly suspect the majority of SK apps won't need to do this. If, for whatever reason, you are running into the limit and your limit(s) can't be raised, then you should use a service binding, where Worker1 (the SK app) is bound to Worker2 (the Worker + Durable Objects) and requests can be passed off safely. Alternatively, you may skip the bindings & use Custom Domains for Workers to send Edit: Custom Domains for Workers would be my suggested & preferred route, where |
I brought up the 1mb limit as a discussion point, mostly — bundling every script and 3rd-party library together into a single worker file seems philosophically opposed to where Cloudflare is headed, as evidenced by your comment showing two similar but slightly-different approaches they've released. The trade-offs are nuanced, and are totally a broader point than "how do you bind a DO to SK with wrangler?" I was speaking up as an advocate to make this decision thoughtfully, on behalf of DX, and with architectural flexibility in mind. Edit: Cloudflare published a blog post today that backs up with Luke's saying and points to a comment of his in February explaining the division of labor between Svelte, SvelteKit, and something like worktop or workers itself. Hope it helps someone else have an a-ha moment. |
Are there any working solutions to this problem "in the wild" yet? Just ran into it today myself and it seems like such a simple problem, just export the DO classes along with the main handler, yet I have yet to see a working solution. |
@tyvdh , you can deploy DOs seperately and bind to svelte-kit app. This remedies the problem a bit. |
Yeah you can and I have but that places part of the code external to the main repo and breaks a unified deployment which is a bummer. It also introduces an extra complexity around development which I'm actually more interested in, running the entire development experience under a single repo and Which Miniflare has a concept for mounting external workers so there may still be something here I'm missing around development unification while having production separation. This would actually potentially be a preferred method as this seems to be the way Cloudflare is heading anyway. Many individual functions / services tied together via bindings during deployment. It's really just a question of maintaining a good development experience and a scaleable production environment. |
fwiw I'm currently maintaining a Here's what mine looks like:
I then call |
I've got a fully functioning repo here: Please note it's not well documented in the README but the main files are:
It's a tricky problem between the dev and production environments and trying not to duplicate configurations but I'm pretty happy with this while we wait for something simpler. Ultimately I think the answer likely lies somewhere between marrying the vite server and miniflare for development and allowing websocket endpoints to pass through the cloudflare worker adapter on production. This works though and it actually works fine for both the cloudflare worker and pages adapters. For pages you'll just have to deploy the durable objects separately and then link them manually in the dashboard as there isn't currently any way to both deploy and link when uploading a page project with durable object bindings. You could easily configure an empty worker with the durable objects to deploy as part of some separate deployment command from the git commit process that pages use for deployments. I do see eventually pages getting some sort of a configuration file though where you can both attach and deploy bindings during the automated build process. |
Hello guys, I was wondering if the cloudflare adapter supports this yet. If not, what are the recommended ways to define durable objects within a sveltekit project and have it deploy along with the built worker script? |
Until a robust solution is implemented, I think I've managed to find a way to shim in my durable objects alongside the worker script without too much fuss using @sveltejs/adapter-cloudflare-workers. I'm using wrangler3 which includes basic module support. /wrangler.toml (the adapter uses these as output paths) main = "./.cloudflare/worker.js"
site.bucket = "./.cloudflare/public" /worker.js export { default } from './.cloudflare/worker.js';
export { MyDurableObject } from './src/mydo.ts'; Then Hopefully this saves someone else a few hours of cussing 😉 |
@Klowner but do you still have Cloudflare's CI/CD on git push? So to clarify, you are not using @sveltejs/adapter-cloudflare at all? But still using SvelteKit? Moreover, how would you get TS/typings right when using the DO class? Edit: I guesss importing the type and declaring it to platform.env.YOUR_DO, right? |
@205g0 correct, I'm only using @sveltejs/adapter-cloudflare-workers, no @sveltejs/adapter-cloudflare. For CI/CD I'm just using the Github Action. In my individual DO files I include: type Bindings = Required<App.Platform>['env']
export class MyDurableObject implements DurableObject {
constructor (readonly state: DurableObjectState, readonly env: Bindings) { }
// ...
} |
I managed to get this working with In #!/usr/bin/env bash
#
# This script replaces the default _worker.js file with a new one that includes
# durable objects exported from src/lib/durable-objects/index.ts
dir=.svelte-kit/cloudflare
./node_modules/.bin/esbuild src/lib/durable-objects/index.ts \
--bundle \
--format=esm \
--sourcemap \
--target=esnext \
--outfile=$dir/_durable-objects.js \
mv $dir/_worker.js $dir/_sveltekit_worker.js
mv $dir/_worker.js.map $dir/_sveltekit_worker.js.map
echo "\
export { default } from './_sveltekit_worker.js';
export * from './_durable-objects.js';
" > $dir/_worker.js In export { MyDurable } from './MyDurable';
// Add more here In {
"scripts": {
"dev": "wrangler pages dev .svelte-kit/cloudflare",
"build": "vite build && ./scripts/include-durable-objects.sh"
}
} in build.command = "npm run build"
[durable_objects]
bindings = [
{ name = "mydurable", class_name = "MyDurable },
]
[[migrations]]
tag = "v1"
new_classes = ["MyDurable"] It works with |
I've written the simple solution (or workaround) here. I hope it will be helpful to you. |
Sorry if this is a necro, but are we saying to use DO in SvelteKit we need to deploy the worker separately and then bind through SvelteKit? There's currently no "native" way to do this within SvelteKit as such? |
@jameswoodley Yes for now, unfortunally. |
Is your feature request related to a problem? Please describe.
Cloudflare recently introduced the ability to maintain websocket connections with workers, in addition to a stateful storage solution called 'Durable Objects'. For workers, these objects are accessible through a
env
argument passed in during thefetch
invocation. More information about durable objects and their utilization can be found here.https://developers.cloudflare.com/workers/learning/using-durable-objects
Describe the solution you'd like
In my opinion, the cloudflare worker adapter should expose a way to mutate and interact with this
env
object passed in by cloudflare during a function invocation.Describe alternatives you've considered
I have not found any alternate ways of using durable objects without modifying the adapter.
How important is this feature to you?
This feature is fairly important to me personally, since it would dramatically simplify my stack if my state coordination can be done in the same worker.
The text was updated successfully, but these errors were encountered: