vercel / remix

Build Better Websites. Create modern, resilient user experiences with web fundamentals.
https://remix.run
MIT License
65 stars 19 forks source link

`TypeError: headers.getSetCookie is not a function` #109

Open olros opened 6 months ago

olros commented 6 months ago

Hi! I'm testing the new Single Fetch behaviour in Remix, but I'm having trouble with headers.getSetCookie which seemingly isn't present when running on Vercel for some reason.

As noted in the changelog, I've enabled nativeFetch in installGlobals but the TypeError is still present. The error I get is this:

TypeError: headers.getSetCookie is not a function or its return value is not iterable
    at proxyResponseToResponseStub (/var/task/node_modules/.pnpm/@remix-run+server-runtime@2.9.1_typescript@5.4.5/node_modules/@remix-run/server-runtime/dist/single-fetch.js:292:25)
    at /var/task/node_modules/.pnpm/@remix-run+server-runtime@2.9.1_typescript@5.4.5/node_modules/@remix-run/server-runtime/dist/single-fetch.js:61:9
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Promise.all (index 1)
    at async /var/task/node_modules/.pnpm/@remix-run+server-runtime@2.9.1_typescript@5.4.5/node_modules/@remix-run/server-runtime/dist/single-fetch.js:39:19
    at async callDataStrategyImpl (/var/task/node_modules/.pnpm/@remix-run+router@1.16.0/node_modules/@remix-run/router/dist/router.cjs.js:4169:17)
    at async callDataStrategy (/var/task/node_modules/.pnpm/@remix-run+router@1.16.0/node_modules/@remix-run/router/dist/router.cjs.js:3702:19)
    at async loadRouteData (/var/task/node_modules/.pnpm/@remix-run+router@1.16.0/node_modules/@remix-run/router/dist/router.cjs.js:3677:19)
    at async queryImpl (/var/task/node_modules/.pnpm/@remix-run+router@1.16.0/node_modules/@remix-run/router/dist/router.cjs.js:3522:20)
    at async Object.query (/var/task/node_modules/.pnpm/@remix-run+router@1.16.0/node_modules/@remix-run/router/dist/router.cjs.js:3416:18)

To reproduce, simply create a new Remix-project with npx create-remix@latest and put this in the _index.tsx-file:

export const loader = () => {
  return new Response(null, {
    headers: { "set-cookie": "_cookie_name=123; maxAge=1000000; SameSite=Lax" },
  });
};

export default function Index() {
  return <h1>Welcome to Remix</h1>;
}
`vite.config.ts` ```ts import { vitePlugin as remix } from "@remix-run/dev"; import { installGlobals } from "@remix-run/node"; import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; import { vercelPreset } from '@vercel/remix/vite'; installGlobals({ nativeFetch: true }); export default defineConfig({ plugins: [ remix({ presets: [vercelPreset()], future: { unstable_singleFetch: true } }), tsconfigPaths(), ], }); ```

Then deploy to vercel.


Even without the new SingleFetch behaviour, using headers.getSetCookie still doesn't work. This can be reproduced by removing unstable_singleFetch from future in vite.config.ts, and changing the _index.tsx-file to this:

export const loader = () => {
  const res = new Response(null, {
    headers: { "set-cookie": "_cookie_name=123; maxAge=1000000; SameSite=Lax" },
  });
  console.log("getSetCookie", res.headers.getSetCookie); // -> getSetCookie  undefined
  console.log("getSetCookie values", res.headers.getSetCookie()); // -> TypeError: response.headers.getSetCookie is not a function
  return res;
};

export default function Index() {
  return <h1>Welcome to Remix</h1>;
}

Any help appreciated!

coji commented 6 months ago

I am having the same problem. It also occurs with loaders that only return json({}).

It is also reported in the issue of remix-run https://github.com/remix-run/remix/issues/9324

Perhaps I should try to use nativeFetch on runtime, but since it is vercelPreset and not a custom server, I don't know what to do.

Tsirimaholy commented 6 months ago

I'm getting this error too. I tried to use node 20 if it solves the issue, but it's the same. The server is not accessible (Just blank screen). Mine is just a local dev environment. I tried to dig deeper a little bit and there I see this line: https://github.com/remix-run/remix/blob/7b2fa032cd465c7f6e9c8d90471d6a544e0c08f6/packages/remix-server-runtime/single-fetch.ts#L350 Even the comments themselves acknowledge the presence of certain typing issues. I want to contribute to solve this issue, but i'm not a yet great JS dev myself 😅 .

coji commented 6 months ago

It would be nice to be able to control it externally somehow so that the following part called after invoking serverless functions becomes installGlobals({ nativeFetch: true }), but I wonder how to do that.

https://github.com/vercel/remix/blob/9a168473a813e42ab2dc8ae7f21a58a760b712da/packages/vercel-remix/globals.ts#L2

michalmo commented 6 months ago

So I've found a workaround using Object.defineProperty to set the globals and prevent changes to them, and by monkey-patching in an API that @ercel/remix relies on but isn't available in Headers when using nativeFetch.

Here's the gist https://gist.github.com/michalmo/d62e9a2e001183ec1df1bcac74980abb.

I call the installAndLockGlobals helper at the top level of app/entry.server.tsx (https://vercel.com/docs/frameworks/remix#using-a-custom-app/entry.server-file).

Hope this helps somebody :)

cyberdude commented 4 months ago

So I've found a workaround using Object.defineProperty to set the globals and prevent changes to them, and by monkey-patching in an API that @ercel/remix relies on but isn't available in Headers when using nativeFetch.

Here's the gist https://gist.github.com/michalmo/d62e9a2e001183ec1df1bcac74980abb.

I call the installAndLockGlobals helper at the top level of app/entry.server.tsx (https://vercel.com/docs/frameworks/remix#using-a-custom-app/entry.server-file).

Hope this helps somebody :)

Thank you sooo much!! You saved me a couple of headaches

cyberdude commented 4 months ago

@brophdawg11 Do you have an update regarding these or how can we help? Seems that this is an issue on the Vercel Side of things since locally is running ok

brophdawg11 commented 4 months ago

If Vercel needs a polyfill and doesn't have a fetch implementation, they will need to let you call installGlobals({ nativeFetch: true }) to get a single-fetch compatible polyfill (see https://github.com/vercel/remix/issues/109#issuecomment-2081349578). remix-serve does this conditionally based on the flag https://github.com/remix-run/remix/blob/main/packages/remix-serve/cli.ts#L103

Ehesp commented 3 months ago

Although the installGlobals({ nativeFetch: true }) fix solves this, I'm unable to use fetcher.submit from Remix, getting the error:

TypeError: RequestInit: duplex option is required when sending a body.
    at new Request (/var/task/website/node_modules/undici/lib/web/fetch/request.js:537:15)
    at createRemixRequest (file:///var/task/website/build/server/nodejs-eyJydW50aW1lIjoibm9kZWpzIn0/server-index.mjs:61:10)
    at Server.default (file:///var/task/website/build/server/nodejs-eyJydW50aW1lIjoibm9kZWpzIn0/server-index.mjs:80:19)