Itsacoup
Itsacoup•14mo ago

Remix Convex Vercel

Dev environment runs great. I have chosen to use HttpClient since I struggled to set up the ReactClient in Remix with out docs and am fine with non-reactive data. Deploying to vercel and the app builds and deploys, both Remix and Convex. Any Remix pages that don't have a loader or action calling the HttpClient render as expected. Any that do use HttpClient crash the app - however I am able to log server side the expected response from the HttpClient in the remix action... So they are talking Currently adding more error logging to debug but the error I'm getting is "errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"TypeError: First parameter has member 'readable' that is not a ReadableStream."
16 Replies
Itsacoup
ItsacoupOP•14mo ago
The server logs from vercel: NOV 28 12:45:36.23 - my-domain.vercel.app [POST] /admin/login Unknown application error occurred Runtime.Unknown NOV 28 12:45:35.96 - my-domain.vercel.app [POST] /admin/login Unhandled Promise Rejection {"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"TypeError: First parameter has member 'readable' that is not a ReadableStream.","reason":{"errorType":"TypeError","errorMessage":"First parameter has member 'readable' that is not a ReadableStream.","stack":["TypeError: First parameter has member 'readable' that is not a ReadableStream."," at assertReadableStream (/var/task/node_modules/web-streams-polyfill/dist/ponyfill.js:362:19)"," at convertReadableWritablePair (/var/task/node_modules/web-streams-polyfill/dist/ponyfill.js:3524:9)"," at ReadableStream.pipeThrough (/var/task/node_modules/web-streams-polyfill/dist/ponyfill.js:3608:29)"," at fetchFinale (node:internal/deps/undici/undici:11082:56)"," at mainFetch (node:internal/deps/undici/undici:10974:9)"," at process.processTicksAndRejections (node:internal/process/task_queues:95:5)"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection: TypeError: First parameter has member 'readable' that is not a ReadableStream."," at process.<anonymous> (file:///var/runtime/index.mjs:1276:17)"," at process.emit (node:events:529:35)"," at emit (node:internal/process/promises:149:20)"," at processPromiseRejections (node:internal/process/promises:283:27)"," at process.processTicksAndRejections (node:internal/process/task_queues:96:32)"]} NOV 28 12:45:35.96 - my-domain.vercel.app [POST] /admin/login res from Convex User not found Here is the try-catch in the action that is failing and it's not running the catch which is more strange. The last request in the vercel logs is the top one at /admin/login so we never successfully redirect? try { const convex = new ConvexHttpClient(process.env.CONVEX_URL ?? ""); const userLogIn = await convex.action(api.auth.loginUser, {email, password}); console.log("res from Convex", userLogIn); if (typeof userLogIn === 'object' && userLogIn.status === 'Login successful') { return new Response(null, { headers: { 'Set-Cookie': auth=${userLogIn.token}; HttpOnly; Path=/; SameSite=Strict, 'Location': '/admin', }, status: 302, }); } return userLogIn; } catch (error) { console.error("Error calling Convex API:", error); return new Response('Error processing request', { status: 500, headers: { "Content-Type": "text/plain", }, }); } I'm using node 18 on vercel and dev - I imagine it has to do with version issue?
ballingt
ballingt•14mo ago
@Itsacoup do other fetch requests work? eg if you try fetch("http://www.example.com") does that cause the same error in the route? Know if this is running in the Vercel edge runtime or Node.js?
ballingt
ballingt•14mo ago
GitHub
convex-js/src/browser/http_client.ts at 32ff1dc1190e35223bda44c41f5...
TypeScript/JavaScript client library for Convex. Contribute to get-convex/convex-js development by creating an account on GitHub.
ballingt
ballingt•14mo ago
GitHub
convex-js/src/browser/http_client-node.ts at 32ff1dc1190e35223bda44...
TypeScript/JavaScript client library for Convex. Contribute to get-convex/convex-js development by creating an account on GitHub.
RJ
RJ•14mo ago
@Itsacoup are you interested in getting the React client working? I'm using Remix with the Convex React client; it works great and I'd be happy to share some code if you'd like.
Itsacoup
ItsacoupOP•14mo ago
Running a fetch in the action in place of await convex.httpClient. I hit a test endpoint and get answer back and the app doesn't crash? RJ this is great to here, are you deployed on Vercel? And I've did basic vercel configurations - none 18, haven't defined any edge functions. using @vercel/remix package Actually this is the response i get back from the fetch Response { size: 0, [Symbol(Body internals)]: { body: ReadableStream { _state: 'readable', _reader: undefined, _storedError: undefined, _disturbed: false, _readableStreamController: [ReadableStreamDefaultController] }, type: null, size: null, boundary: null, disturbed: false, error: null }, ..... } RJ one of the draw backs of the ReactClient is the lack of SSR - this is an ecommerce site so I chose to use HttpClient and server render most pages All this being said, I'm leaning towards this being a remix issue on vercel. My set up worked great on Dev. Loving convex btw
RJ
RJ•14mo ago
I'm using Netlify, but for the React client it shouldn't really matter. Here's the idea:
// root.tsx

export async function loader() {
const convexUrl = process.env["CONVEX_URL"];

if (convexUrl === undefined) throw "CONVEX_URL not present";

return json({
ENV: {
CONVEX_URL: convexUrl,
},
});
}

export default () => {
const data = useLoaderData<typeof loader>();
const convexReactClient = useMemo(
() => new ConvexReactClient(data.ENV.CONVEX_URL),
[data.ENV.CONVEX_URL],
);

return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<ConvexProvider client={convexReactClient}>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</ConvexProvider>
</body>
</html>
);
}
// root.tsx

export async function loader() {
const convexUrl = process.env["CONVEX_URL"];

if (convexUrl === undefined) throw "CONVEX_URL not present";

return json({
ENV: {
CONVEX_URL: convexUrl,
},
});
}

export default () => {
const data = useLoaderData<typeof loader>();
const convexReactClient = useMemo(
() => new ConvexReactClient(data.ENV.CONVEX_URL),
[data.ENV.CONVEX_URL],
);

return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<ConvexProvider client={convexReactClient}>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</ConvexProvider>
</body>
</html>
);
}
But if you need SSR, then agreed that you do probably want to get the HTTP client working either way!
Itsacoup
ItsacoupOP•14mo ago
Awesome thanks for sharing. As for the error I'm facing. It appears to be a known issue with Remix on vercel. Most of the issues appear resolved due to a patch last month... But I'm still dealing with it 🫠 gonna investigate in Remix discord https://discord.com/channels/770287896669978684/1166834027228041297
ballingt
ballingt•14mo ago
@Itsacoup thanks for investigating, if you can find a fetch() that works (e.g. node-fetch) and call setFetch() with it hopefully that makes things work.
RJ
RJ•14mo ago
No problem, thanks for sharing your research as well!
ballingt
ballingt•14mo ago
@itsaBrandon reading that issue, it sounds like they think they've fixed it; since you're seeing the issue with the Convex HTTP client but not with a normal fetch, maybe the way they fixed it was swapping out fetch at a later point. If they do that then this let localFetch = fetch would be a problem, it could still be using the old broken fetch? You might try calling setFetch(fetch) each time before you call fetch. If this is the issue we can fix this.
Itsacoup
ItsacoupOP•14mo ago
@ballingt first thanks for the support trying to figure this out! But regarding your suggestion I guess I'm a little confused. What is the fetch that I'm trying to set? I tried using just fetch API on a test endpoint (JSON placeholder) which did resolve. But the code I actually want to run accesses resources through the http client using generated API as an arg (e.g. api.auth.checkAuth < the function resource) Is there resources/endpoint exposed from the generated API that I could hand into fetch() or am I missing something?
ballingt
ballingt•14mo ago
The Convex HTTP client exports a setFetch() function that you can use to choose the fetch implementation that is uses It's possible that calling this setFetch() function with the global fetch would be an improvement because currently whatever the global fetch is at import time is used. This is just a guess based on the behavior you see of fetch() calls working, but the Convex HTTP client not working. That seems pretty weird to me and all I can think of is that what the global fetch function is changes between import time and when you use it.
Itsacoup
ItsacoupOP•14mo ago
Only able to import it from node_modules directly import { setFetch } from "node_modules/convex/dist/esm-types/browser/http_client"; This leads to a rutime error [ERROR] Could not resolve "node_modules/convex/dist/esm-types/browser/http_client" app/routes/_index.tsx:31:25: 31 │ ...ch } from "node_modules/convex/dist/esm-types/browser/http_clie... ╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can mark the path "node_modules/convex/dist/esm-types/browser/http_client" as external to exclude it from the bundle, which will remove this error. Tried adding to serverDependenciesToBundle in remix.config (transpile) but doesn't resolve it. I'm going to keep pushing on the vercel/remix front. Requests to convex resolve cause I can log the responses and see them in the vercel server log - yet I still get this error and it's only on pages with action/loaders that use the httpclient so theres a connection there....
ballingt
ballingt•14mo ago
Ah shoot, I didn't realize it wasn't exposed! We'll either expose this in the next client release of fix the issue
Itsacoup
ItsacoupOP•14mo ago
@ballingt update for ya on this. The closed issue on vercel/remix https://github.com/vercel/remix/issues/62 got replied to, and they may take a look. I build a demo app https://convex-remix-demo.vercel.app/ with minimal code and replicated the error. https://github.com/baberMatt/convex-remix-demo

Did you find this page helpful?