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

feat: NextJS EdgeRuntime support #2697

Closed
1 task
fortezhuo opened this issue Sep 13, 2022 · 7 comments
Closed
1 task

feat: NextJS EdgeRuntime support #2697

fortezhuo opened this issue Sep 13, 2022 · 7 comments

Comments

@fortezhuo
Copy link

Describe the feature you'd like to request

Since vercel/next.js#39462 applied on NextJS 12.3.*'s EdgeRuntime, an internal server error occurs like below statement

ready - started server on 0.0.0.0:3000, url: http://localhost:3000
warn  - You have enabled experimental feature (runtime) in next.config.js.
warn  - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk.

warn  - You are using the experimental Edge Runtime with `experimental.runtime`.
event - compiled client and server successfully in 1406 ms (232 modules)
wait  - compiling / (client and server)...
event - compiled client and server successfully in 860 ms (385 modules)
[Error: A Node.js API is used (setImmediate) which is not supported in the Edge Runtime.
Learn more: https://nextjs.org/docs/api-reference/edge-runtime]
[Error: A Node.js API is used (setImmediate) which is not supported in the Edge Runtime.
Learn more: https://nextjs.org/docs/api-reference/edge-runtime]
wait  - compiling /api/trpc/[trpc] (client and server)...
wait  - compiling /_error (client and server)...
event - compiled client and server successfully in 318 ms (451 modules)
error - (middleware)/node_modules/.pnpm/@trpc+server@10.0.0-proxy-alpha.74/node_modules/@trpc/server/dist/adapters/next.mjs (11:0) @ getPath
error - Cannot read properties of undefined (reading 'trpc')
null
 [TRPCClientError: Unexpected token < in JSON at position 0] {
  meta: undefined,
  shape: undefined,
  data: undefined,
  name: 'TRPCClientError'
}

To Reproduce Error

  1. Clone or run npx create-next-app --example https://github.com/trpc/trpc --example-path examples/next-minimal-starter trpc-minimal-starter
  2. Enable EdgeRuntime with create next.config.js
module.exports = {
    experimental: {
        runtime: "experimental-edge",
      },
}
  1. Run next dev

Describe the solution you'd like to see

TRPC can run well on NextJS EdgeRuntime. Maybe add some polyfill of setImmediate like https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js

Desribe alternate solutions

Additional information

vercel/next.js#40457

👨‍👧‍👦 Contributing

  • 🙋‍♂️ Yes, I'd be down to file a PR implementing this feature!
@sachinraja
Copy link
Member

sachinraja commented Sep 13, 2022

I don't know why the setImmediate error is happening, that's only in @trpc/server/adapters/ws and you would have to import that yourself. The real error here though is that tRPC's Next adapter expects req.query.trpc to exist but it does not in the edge runtime, which uses the Fetch API. What you should really be using is the Fetch adapter:

/**
 * This is the API-handler of your app that contains all your API routes.
 * On a bigger app, you will probably want to split this file up into multiple files.
 */
import { initTRPC } from "@trpc/server";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { NextRequest } from "next/server";
import { z } from "zod";

const t = initTRPC.create();

const appRouter = t.router({
  greeting: t.procedure
    // This is the input schema of your procedure
    // 💡 Tip: Try changing this and see type errors on the client straight away
    .input(
      z
        .object({
          name: z.string().nullish(),
        })
        .nullish()
    )
    .query(({ input }) => {
      // This is what you're returning to your client
      return {
        text: `hello ${input?.name ?? "world"}`,
        // 💡 Tip: Try adding a new property here and see it propagate to the client straight-away
      };
    }),
  // 💡 Tip: Try adding a new procedure here and see if you can use it in the client!
  // getUser: t.procedure.query(() => {
  //   return { id: '1', name: 'bob' };
  // }),
});

// export only the type definition of the API
// None of the actual implementation is exposed to the client
export type AppRouter = typeof appRouter;

// export API handler
export default (req: NextRequest) => {
  return fetchRequestHandler({
    router: appRouter,
    req,
    endpoint: "/api/trpc",
    createContext: () => ({}),
  });
};

@fortezhuo
Copy link
Author

@sachinraja thanks for your reply. But I have tried to add

export default (req: NextRequest) => {
  return fetchRequestHandler({
    router: appRouter,
    req,
    endpoint: "/api/trpc",
    createContext: () => ({}),
  });
};

and still not working.. can you provide complete solution for this case ?

@sachinraja
Copy link
Member

I tested it and it worked, try clearing .next.

@fortezhuo
Copy link
Author

fortezhuo commented Sep 14, 2022

@sachinraja,
Sorry to bother u again

I try to rewrite my code based on this solution. But I have found fetchRequestHandler is missing NextResponse argument. We need to set response's headers to allow CORS. And most NextJS 3rd party modules need to consume NextResponse as argument like https://github.com/vvo/iron-session.

export function withIronSessionApiRoute(
  handler: NextApiHandler,
  options: IronSessionOptions | GetIronSessionApiOptions,
): NextApiHandler {
  return async function nextApiHandlerWrappedWithIronSession(req, res) {
    let sessionOptions: IronSessionOptions;

Please elaborate how to integrate the modules by using fetchRequestHandler

@sachinraja
Copy link
Member

You can't pass a response object because tRPC needs to set the body of the response. You can set the response headers using the response returned from fetchRequestHandler.

And most NextJS 3rd party modules need to consume NextResponse as argument like https://github.com/vvo/iron-session.

You can also use the Response returned from fetchRequestHandler for this.

@fortezhuo
Copy link
Author

Found issue while using Prisma : prisma/prisma#15313

@github-actions
Copy link

github-actions bot commented Oct 4, 2022

This issue has been locked because it had no new activity for 14 days. If you are running into a similar issue, please create a new issue. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants