Skip to content
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

enable getCloudflareContext to work in middlewares via a new enableEdgeDevGetCloudflareContext utility #265

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

dario-piotrowicz
Copy link
Contributor

@dario-piotrowicz dario-piotrowicz commented Jan 17, 2025

This PR addresses the fact that getCloudflareContext can't work in dev (next dev) inside middlewares.

The issue is that those are always run in the edge runtime, although in production this is not a problem, in development (next dev) this prevents us from being able to import and use the wrangler node.js APIs from there.

I've tried to come up with some nice solutions but unfortunately I think the best we can do is basically borrow the setupDevPlatform next-on-pages idea and require users to call a function in their Next.js config file (this function then patches the vm.runInContext function to make the cloudflare context available in the "dev edge runtime").

So my solution here consist in having everything still working exactly the same for standard nodejs routes (if you don't call getCloudflareContext from a middleware you don't need to worry about anything), but for edge runtime routes/middlewares a utility called enableEdgeDevGetCloudflareContext needs to be invoked in the next config file.

We can properly document this, not invoking the function while invoking getCloudflareContext in a middleware also provides a helpful error that should hopefully make this very easy to follow:
Screenshot 2025-01-17 at 18 49 51

Note

The Next.js docs say that middelwares currently run in the edge runtime, so maybe this can change in the future making this use case rarer

fixes #226

Copy link

changeset-bot bot commented Jan 17, 2025

🦋 Changeset detected

Latest commit: 1c298b1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@opennextjs/cloudflare Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dario-piotrowicz dario-piotrowicz force-pushed the dario/226/cloudflare-context-middleware branch from 2447a8a to f6510ac Compare January 17, 2025 19:05
Copy link

pkg-pr-new bot commented Jan 17, 2025

Open in Stackblitz

pnpm add https://pkg.pr.new/@opennextjs/cloudflare@265

commit: 1c298b1

@dario-piotrowicz dario-piotrowicz force-pushed the dario/226/cloudflare-context-middleware branch 4 times, most recently from 6648525 to 09b33de Compare January 17, 2025 22:39
examples/middleware/e2e/base.spec.ts Outdated Show resolved Hide resolved
packages/cloudflare/src/api/cloudflare-context.ts Outdated Show resolved Hide resolved
/** @type {import('next').NextConfig} */
const nextConfig = {};

enableEdgeDevGetCloudflareContext();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about renaming this function to initOpenNextCloudflare()

I think it's easier for the user to understand as we expose lesst techincal details and we could add to this function later if needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mh... my idea was that people would not have to always include this but only when they face the cloudflare context in the edge runtime issue (a problem that can happen to a subset of users and one that hopefully can go away in the future if Next.js decides to support nodejs middlewares), that's why I made the name more specific

initOpenNextCloudflare() sounds like something they always need to have (similar to setupDevPlatform in next-on-pages)

we could add to this function later if needed.

That's true, but again your comment makes it sound to me like moving forward we'd want to recommend all users to include this, which I am not sure about 😕

So based on the above I think I do prefer something like enableEdgeDevGetCloudflareContext which makes it very clear to the user what this function does and when/why is needed besides making clear(er) that this is optional

But if you strongly prefer a generic name like initOpenNextCloudflare() I'd be ok with using that (although that's not my preference)

packages/cloudflare/src/api/cloudflare-context.ts Outdated Show resolved Hide resolved
packages/cloudflare/src/api/cloudflare-context.ts Outdated Show resolved Hide resolved
@vicb
Copy link
Contributor

vicb commented Jan 20, 2025

Thought: Maybe we can getPlatformProxy(...) in initOpenNextCloudflare() so that getCloudflareContext could be made sync?

This comment says "the function is an async one but it doesn't need to be awaited", it might be nice to add the rationale if we add the implementation to our repo.

@dario-piotrowicz dario-piotrowicz force-pushed the dario/226/cloudflare-context-middleware branch from 09b33de to 59419ca Compare January 20, 2025 10:58
… `enableEdgeDevGetCloudflareContext` utility

use `process.env.NEXT_RUNTIME` to detect the edge runtime instead of try-catching
@dario-piotrowicz
Copy link
Contributor Author

Thought: Maybe we can getPlatformProxy(...) in initOpenNextCloudflare() so that getCloudflareContext could be made sync?

Yes, we could, this would mean that everyone would always have to call initOpenNextCloudflare(), I mentioned in my comment that we don't need to go that route as not forcing users to do that might provide a better DX

but again if you strongly prefer us to go that route I'm ok with it

This comment says "the function is an async one but it doesn't need to be awaited", it might be nice to add the rationale if we add the implementation to our repo.

Yes, given the implementation of next dev, it takes some time from when Next.js loads the config and when it serves the app, we did see that that amount of time is enough for the proxy to be ready in time. It would require very little changes here, just removing the on-the-fly proxy generation from getCloudflareContext and changing the function signature to be sync

… `enableEdgeDevGetCloudflareContext` utility

clarify args of `runInContext`
… `enableEdgeDevGetCloudflareContext` utility

create new `monkeyPatchVmModuleEdgeContext` commented function
… `enableEdgeDevGetCloudflareContext` utility

amend `monkeyPatchVmModuleEdgeContext`
… `enableEdgeDevGetCloudflareContext` utility

add comment to `getCloudflareContext`
@dario-piotrowicz dario-piotrowicz requested a review from vicb January 20, 2025 11:48
@dario-piotrowicz
Copy link
Contributor Author

dario-piotrowicz commented Jan 20, 2025

@vicb I've addressed all the feedback, the only thing left is to decide whether we want to force this sort of thing via a initOpenNextCloudflare() and potentially convert getCloudflareContext to be sync or not

up to you, just let me know if you want to me make the change 👍
(it doesn't really take much effort to do code-wise, it's just a matter of DX)

@vicb
Copy link
Contributor

vicb commented Jan 20, 2025

@vicb I've addressed all the feedback, the only thing left is to decide whether we want to force this sort of thing via a initOpenNextCloudflare() and potentially convert getCloudflareContext to be sync or not

up to you, just let me know if you want to me make the change 👍 (it doesn't really take much effort to do code-wise, it's just a matter of DX)

Give me some time to think about it, I'm not settled.

Some thoughts I have for now about initOpenNextCloudflare()

Cons:

initOpenNextCloudflare() always need to be called but we can have an error message when it's not called

Pros

  • I think it's easier to document (i.e. "always call initOpenNextCloudflare()" vs " call enableEdgeDevGetCloudflareContext if you call getConflareContext from a middleware"). I think Vercel is working on the ability to run middlewares on the node runtime and we will add support for routes on the edge runtime at some point. It will make it harder to explain
  • I think it's easier for users to understand (They don't have to understand what "EdgeDev" is)
  • We could setup the cloudflare context in there so that getCloudflareContext() becomes sync. A lot of user are complaining about that on Discord and GH - See how it impacts us in the KVCache
  • Calling the init on a per need basis (vs always calling initOpenNextCloudflare()) could introduce unrelated test failures when you start adding the call - i.e. how you had to bump the timeout in this PR

@dario-piotrowicz
Copy link
Contributor Author

Give me some time to think about it, I'm not settled.

Some thoughts I have for now about initOpenNextCloudflare()

...

Well there is only one con and many pros, I dislike that we need to then ask users to always call the function, but given the benefits it does seem like it might be worth it

By the way, either way I am not too convinced about the name since this is a dev (next dev) only thing and in my opinion extremely unlikely to be useful outside of dev (because we have other places where we could accept options/tweak things, like in our templates, in the open-next config, etc...) for this reason I would really prefer it if the function had dev somewhere in its name (e.g. initOpenNextCloudflareForDev())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] TypeError: A dynamic import callback was not specified when using getCloudflareContext
2 participants