TanStack / router

🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering.
https://tanstack.com/router
MIT License
8.19k stars 649 forks source link

server function calls not working on Cloudflare #2633

Open dotnize opened 3 weeks ago

dotnize commented 3 weeks ago

Which project does this relate to?

Start

Describe the bug

Server functions don't work on Cloudflare deployments (via cloudflare-pages preset), wrangler dev, and apparently also on Stackblitz.

[wrangler:inf] GET / 200 OK (56ms)
✘ [ERROR] Error: Context is not available

      at Object.use
  (file:///home/nize/dev/web/tss-cloudflare-server-fn/.wrangler/tmp/pages-liyiqW/chunks/runtime.mjs:1:103891)
      at V
  (file:///home/nize/dev/web/tss-cloudflare-server-fn/.wrangler/tmp/pages-liyiqW/chunks/runtime.mjs:455:96187)
      at _
  (file:///home/nize/dev/web/tss-cloudflare-server-fn/.wrangler/tmp/pages-liyiqW/chunks/runtime.mjs:455:108302)
      at null.<anonymous>
  (file:///home/nize/dev/web/tss-cloudflare-server-fn/.wrangler/tmp/pages-liyiqW/chunks/runtime.mjs:455:107762)
      at Object.assign._ [as url]
  (file:///home/nize/dev/web/tss-cloudflare-server-fn/.wrangler/tmp/pages-liyiqW/chunks/runtime.mjs:455:108277)
      at Object.assign.url
  (file:///home/nize/dev/web/tss-cloudflare-server-fn/.wrangler/tmp/pages-liyiqW/chunks/runtime.mjs:455:106760)
      at Object.beforeLoad
  (file:///home/nize/dev/web/tss-cloudflare-server-fn/.wrangler/tmp/pages-liyiqW/chunks/runtime.mjs:455:108503)
      at null.<anonymous>
  (file:///home/nize/dev/web/tss-cloudflare-server-fn/.wrangler/tmp/pages-liyiqW/chunks/runtime.mjs:1:148928)
      at null.<anonymous>
  (file:///home/nize/dev/web/tss-cloudflare-server-fn/.wrangler/tmp/pages-liyiqW/chunks/runtime.mjs:1:152252)
      at new Promise (<anonymous>) {
    routerCode: 'BEFORE_LOAD'
  }

Your Example Website or App

https://github.com/dotnize/tss-cloudflare-server-fn

Steps to Reproduce the Bug or Issue

or stackblitz: https://stackblitz.com/~/github.com/dotnize/tss-cloudflare-server-fn

  1. pnpm install
  2. pnpm build
  3. pnpm preview via wrangler

The app doesn't work at all due to a server fn call in __root.tsx's beforeLoad. Server fn calls from other routes/loaders (like in index.tsx) also don't work.

Expected behavior

Server functions should work as expected, as it already works on local vinxi dev, node-server builds, or Vercel deployments

repo deployment on vercel, working as expected: https://tss-cloudflare-server-fn.vercel.app/

Screenshots or Videos

No response

Platform

Additional context

No response

vseventer commented 2 weeks ago

Having the same issue - one thing (possibly related) I have noted is that even the samples I checked on the website are broken with the same error, for example https://tanstack.com/router/latest/docs/framework/react/examples/start-basic-react-query)

Image

xstevenyung commented 2 weeks ago

i had the same error but in a different use.

i was calling a server function on form submit. while everything work locally, i had the same Context is not available once deployed on cloudflare but using json actually fix it for me in this specific use-case

import { createServerFn, json } from "@tanstack/start";

const action = createServerFn("POST", async () => {
  // this doesn't work on cloudflare but work locally
  // return { msg: 'hello' };
  // this works on cloudflare
  return json({ msg: 'hello' });
});

// ...

function Page() {
  return (
    <form
      onSubmit={async (event) => {
        event.preventDefault();
        event.stopPropagation();
        await action();
      }}
    >
       {/* ... */}
    </form>
  )
}

no clue if this is related in some way

xstevenyung commented 2 weeks ago

after some digging, seems like the issue might come from nitro

related issue: https://github.com/unjs/nitro/issues/1943

Talent30 commented 2 weeks ago

I got it working, this is my config

import type { App } from "vinxi";

import { defineConfig } from "@tanstack/start/config";

const tanstackApp = defineConfig({
  server: {
    preset: "cloudflare-pages",
    rollupConfig: {
      external: ["node:async_hooks"],
    },
  },
});

const routers = tanstackApp.config.routers.map((r) => {
  return {
    ...r,
    middleware: r.target === "server" ? "./app/middleware.tsx" : undefined,
  };
});

const app: App = {
  ...tanstackApp,
  config: {
    ...tanstackApp.config,
    routers: routers,
  },
};

export default app;
vseventer commented 2 weeks ago

The rollupConfig.external addition posted by @Talent30 seems to work for me too. I did have to create a wrangler.toml to set compatibility_flags = [ "nodejs_compat" ] to get it to build.

Talent30 commented 2 weeks ago

The rollupConfig.external addition posted by @Talent30 seems to work for me too. I did have to create a wrangler.toml to set compatibility_flags = [ "nodejs_compat" ] to get it to build.

Yes you need that. Nitro needs async context

Talent30 commented 2 weeks ago

If it is working for everyone we might need to submit a PR to update the deployment doc.

SeanCassiere commented 2 weeks ago

Just so I'm up to date on this thread, we are waiting on https://github.com/unjs/nitro/issues/1943 to be resolved, so that it may be updated in Vinxi, correct?

Talent30 commented 2 weeks ago

Just so I'm up to date on this thread, we are waiting on unjs/nitro#1943 to be resolved, so that it may be updated in Vinxi, correct?

Hi, @SeanCassiere.

I don't think this will be fixed by Nitro in the near future since no one has had looked at the issue for a year now.

For now, we have to set compatibility_flags = [ "nodejs_compat" ] and rollupConfig: { external: ["node:async_hooks"], } as the configuration I posted previously.

Perhaps we should update the documentation to tell people to enable compatibility_flags = [ "nodejs_compat" ] and update the cloudflare-pages default to include rollupConfig.external.

What are your thoughts?

aretrace commented 2 weeks ago

@SeanCassiere @Talent30 I'm interested in deploying to Cloudflare, definitely would want this in the docs.

schiller-manuel commented 2 weeks ago

just create PRs for the docs then?

Talent30 commented 1 week ago

just create PRs for the docs then?

Hi there,

Would you like me to put the rollupConfig.external setting in for cloudflare-pages preset as well?

xstevenyung commented 2 days ago

using the rollupConfig.external doesn't seems to fix all the issues.

i also stumble upon the same error when using getWebRequest in a server fn. it seems like the issue come from vinxi (or maybe nitro?) and that the folks at solid-start already had the same issue a while back.

Just so I'm up to date on this thread, we are waiting on nitrojs/nitro#1943 to be resolved, so that it may be updated in Vinxi, correct?

while we are waiting for nitro to integrate the support on the cloudflare preset, it's possible today to pass manually the unenv preset to fix this issue like so:

import { defineConfig } from "@tanstack/start/config";
import tsConfigPaths from "vite-tsconfig-paths";
import { cloudflare } from "unenv";

export default defineConfig({
  server: {
    preset: "cloudflare-pages",
    unenv: cloudflare,
  },
  vite: {
    plugins: [tsConfigPaths()],
  },
});

we still need the wrangler.toml node_compat flag but this seems to solve the issue

related issue: https://github.com/solidjs/solid-start/issues/1527