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: Support RSC & App Layouts #3297

Open
KATT opened this issue Nov 27, 2022 · 56 comments
Open

feat: Support RSC & App Layouts #3297

KATT opened this issue Nov 27, 2022 · 56 comments

Comments

@KATT
Copy link
Member

KATT commented Nov 27, 2022

Describe the feature you'd like to request

We should make official support for Next 13 app layouts & RSC.

Describe the solution you'd like to see

Being able to transparently use tRPC identically in RSC-components and in "use client"-components.

This is very open-ended and hard to answer without tonnes of exploration.

We've done some in https://github.com/trpc/next-13 and experiments of new Next.js adapters in https://github.com/trpc/examples-next-app-dir

Rough outline / sketches

Leverage "forked" versions of the tRPC client outlined by @sebmarkbage in this tweet.

Folder structure

.
├── pages
│   └── api
│       └── [trpc].ts
└── trpc
    ├── index.ts # entrypoint for TS to be happy. Actually not used, `package.json` will magically route to `/entrypoints`
    ├── package.json 
    ├── context.ts
    ├── entrypoints
    │   ├── client.ts # <-- this is what gets magically imported when importing `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/trpc` on the client
    │   └── rsc.ts # <-- gets imported when importing `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/trpc` in RSC
    └── routers
        ├── _app.ts
        └── example.ts

With this structure we should be able to streamline the API to be exactly the same within RSC & in "use client" components.

Usage

Again, it should not matter if the below is done within a RSC-component or in a "use client" one.

import { use } from 'react';
import { trpc } from '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/trpc';

function MyComponent() {
  const post = use(trpc.post.byId.query({ id: "1" }))

  // [..]
}
createContext()

In the createContext function we'll need to be able to distinguish what type of call it is.

Next 13 have some new magical headers() and cookies - we should probably call these or allow for a way of calling them within RSC.

function createContext(opts: CreateTRPCContextNextAppLayout /* maybe CreateTRPCContextNextAppLayoutEdgeApi too */ ) {
  if (opts.type === "rsc") {
    opts.headers
  } else {
     opts.req.headers
  }
}

Additional information

Open questions

  • How do we hydrate a fetch call made in "use client" that is fetched through SSR & when it's mounted on the client? React Query doesn't seem to support this yet (& I'm guessing it's because lack of support from React)
  • Do we still use React Query? I think it makes sense, but we could mimick most of the React Query features through links
  • Do we make some CLI util to make the setup easy? There's a few new files now.
  • Do we make an ssrLink to avoid calls over the network?

Update - Prior art:

From SyncLinear.com | T-74

Funding

  • You can sponsor this specific effort via a Polar.sh pledge below
  • We receive the pledge once the issue is completed & verified
Fund with Polar
@toddgeist
Copy link

toddgeist commented Dec 18, 2022

tldr; Have createTRPCNext return a Provider like the creatTRPCReact version, and have it follow the srr:false config

We have settled on using the Next13 app directory but not using any new data-fetching stuff yet. We are still trying to use TRPC for client-side data fetching. This seems to work so far, although getting set up is a bit tricky.

The main idea is to think of it as using plain node or express on the back end and a separate react app on the front. There are two configs for TRPC, one for the Next API handler and one for the client. This works, but since we are running next, those client components may run on the server on the first-page load, which breaks stuff. The workaround is to only do the TRPC queries inside dynamically imported components with ssr:false

All this works, but it is a bit of a pain, and I feel some tweaks could make this setup easier.

And most importantly, I think this is a worthwhile goal. The ultimate expression of what TRPC needs to be in the new RSC paradigm is an important question, but it will take some time to figure out. But in the meantime, if we could make this approach easier, it would give more people an opportunity to try out TRPC in next13 and provide feedback.

I don't feel I know the codebase well enough to tackle a PR on my own, but perhaps with some guidance I could get something together.

Thoughts?

@AlanMorel
Copy link

Hello, I was wondering if there's been any progress on this issue.

With Next.js working towards stabilizing the app directory, more people will be switching over and with that wishing to use tRPC with it.

Cheers!

@spencerbart
Copy link

Cheering on this development! I'm excited to see it soon.

@ansh
Copy link

ansh commented Feb 8, 2023

I stopped using the app directory because of this issue

@akomm
Copy link

akomm commented Feb 9, 2023

I don't say that everything is fine and perfect, just try to figure out what we have right now and what probably works:

Server:
The API itself isn't a problem, remained the same within pages/api.

Client:
I think you can make it work without breaking RSC and turning everything into a client component. Don't follow the client part of usage with Next.js, instead follow that of usage with React.

Create a TrpcProvider as a client-component:

"use client"

import {QueryClient, QueryClientProvider} from "@tanstack/react-query"
import {httpBatchLink} from "@trpc/client"
import {useState} from "react"
import {trpc} from "~/utils/trpc"

export const TrpcProvider: React.FC<{children: React.ReactNode}> = p => {
  const [queryClient] = useState(() => new QueryClient())
  const [trpcClient] = useState(() =>
    trpc.createClient({
      links: [
        httpBatchLink({
          url: "http://localhost:3000/api/trpc"
        })
      ]
    })
  )
  return (
    <trpc.Provider client={trpcClient} queryClient={queryClient}>
      <QueryClientProvider client={queryClient}>
        {p.children}
      </QueryClientProvider>
    </trpc.Provider>
  )
}

You don't have to, but you can even use it at the root level of your layout app/layout.tsx, the content within the provider still be rendered as RSC:

// app/layout.tsx
import {TrpcProvider} from "~/utils/trpc"

export default function Layout({children}: {children: React.ReactNode}) {
  return (
    <TrpcProvider>
      <html>
        <head>{/* snip */}</head>
        <body>{children}</body>
      </html>
    </TrpcProvider>
  )
}

I've tested it and the content is rendered on the server. Its supposed to work this way. Actually its one of core concepts of the new next 13 RSC implementation.

Now this is for using trpc on the client. So if I get it correct, the whole missing point currently is to be able to run it on the RSC as well, right? Or are there some "details" that make the approach above inefficient or bad also on client in some way?

@akomm
Copy link

akomm commented Feb 10, 2023

I think the following needs to be considered - the doc page is already there, even though the link to it is disabled:
https://beta.nextjs.org/docs/api-reference/file-conventions/route
(feature might not be ready yet, otherwise they would have linked it)

This will eliminate the need to use pages/api eventually.

@michaelhays
Copy link

Route handlers just dropped!

@KATT Any word about progress on this? I assume there will be some work to do with this announcement but I'd love to hear from the team on where things are at :)

@Fredkiss3
Copy link

@michaelhays I migrated my trpc apis to route handlers, and it was simple, you just have to use the fetch adapter instead of nextjs api routes adapter :

  1. I created a file under the path app/api/trpc/[trpc]/route.ts
  2. I copied the adapter code like instructed in the docs :
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from './context.ts';
import { appRouter } from './router.ts';

const handler = (request: Request) => {
  return fetchRequestHandler({
    endpoint: '/api/trpc',
    req: request,
    router: appRouter,
    createContext,
  });
}

export const GET = handler;
export const POST = handler;

Keep in mind that you would have to change your createContext function signature also.

@ansh
Copy link

ansh commented Feb 17, 2023

@Fredkiss3 Does that work without “use client”?

@Fredkiss3
Copy link

Fredkiss3 commented Feb 17, 2023

@ansh It doesn't, what I did is just move the tRPC api endpoint from next api routes to route handlers.

@revmischa
Copy link

revmischa commented Mar 5, 2023

How would one get access to the current next-auth session in createContext?

Trying to do something like this:

export async function createContext({ req, resHeaders }: { req: NextApiRequest; resHeaders?: Record<string, string> }) {
  const session = await getServerSession(req, resHeaders, authOptions)

Fails because getServerSession appears to want a res object but resHeaders is not that.

I'm using appDir and next-auth and would like my resolvers to have access to the current user.

--

Edit: this appears to work but I'm not sure how correct it is

export async function createContext({ req }: { req: NextApiRequest }) {
  const res = new ServerResponse(req)
  const session = await getServerSession(req, res, authOptions)

  return {
    user: session?.user,
  }
}

@mysterybear
Copy link

mysterybear commented Mar 13, 2023

@Fredkiss3 how are you then calling/querying that from the front-end components and bringing types through?

my invocation of an exported trpc created with createTRPCNext is giving me this

image

Unhandled Runtime Error
TypeError: Cannot destructure property 'abortOnUnmount' of 'useContext(...)' as it is null.

Source
Object.useQuery$1 [as useQuery]
node_modules/@trpc/react-query/dist/createHooksInternal-de11647d.mjs (294:16)
eval
node_modules/@trpc/react-query/dist/createHooksInternal-de11647d.mjs (57:0)
Object.apply
node_modules/@trpc/server/dist/index-972002da.mjs (18:0)

maybe you're using the "usage with React" rather than "usage with Next" guidance as @akomm suggested above? I'll try that now also

edit: yeah everything works when following @akomm 's suggestion, my bad

@StringKe
Copy link

@akomm Can you share the whole project structure? I've encountered some similar problems and I'd like to know how to deal with it.

@akomm
Copy link

akomm commented Mar 14, 2023

As I've explained here, don't use the next HOC, use the react approach:
#3297 (comment)
(pay attention to "use client" at the top of the provider example)

Judging by @mysterybear's comment he used HOC. And if you have the same problem, it will be for the same reason. Unless something changed in some recent update.

@StringKe
Copy link

@akomm There is a trpc.Provider in your case and I'm not quite sure where he came from, I checked @trpc/client and @trpc/next and it doesn't seem to expose the provider.

@akomm
Copy link

akomm commented Mar 14, 2023

It comes from the page I've linked:
https://trpc.io/docs/react#2-create-trpc-hooks

// utils/trpc.ts
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '../path/to/router.ts';

export const trpc = createTRPCReact<AppRouter>();

@AlanMorel
Copy link

I realize this is potentially a lot to ask of someone, but if somebody who has it working already could create a tiny barebones repo, I think it would clear up a lot of back and forth here

@devietti
Copy link

@AlanMorel I have been trying to port an existing Next 13 app, so I ended up assembling a little example repo. Only the client makes RPC calls, though, no RPCs from RSCs.

@stychu
Copy link

stychu commented Apr 18, 2023

Any more movement on this @KATT ?? Seems like app dir is becoming stable with next minor release so it should be marked as "production" ready I suppose? Would be cool to have tRPC available with it to <3

@KATT
Copy link
Member Author

KATT commented Apr 18, 2023

Planning to work on this thursday and friday.

It's hard to design an API when the full story isn't there yet:

  • Still don't know how to hydrate "use client" components on first SSR w/o wrapping it in a RSC-component which to me feels completely redundant
  • Mutation API still missing

@KATT
Copy link
Member Author

KATT commented Apr 18, 2023

We might release something prefixed as unstable_ soon

@Thinkscape
Copy link

We might release something prefixed as unstable_ soon

Do you anticipate something wildly different to the approach in https://github.com/trpc/next-13 ?
NGL it was a bit confusing at first, but I was able to stabilise it in my app against trpc10 and latest next.

I share your concern about the userland API that is a bit unergonomic ATM (on top of the server/client boundary nesting doll pattern)

@matannahmani
Copy link

any updates regarding the unstable release?

@413n
Copy link

413n commented May 4, 2023

In Next.js 13.4.0 they released Server Actions in Alpha.
I hope that this unlocks the work for tRPC to fully support the App Directory.
Looking at what tRPC did for Next with /pages, when it will also support /app it will be HUUGE!

@kimdanielarthur-cowlabs
Copy link

kimdanielarthur-cowlabs commented Sep 13, 2023

For using trpc on the server side in nextjs 13 app router I used the createTRPCProxyClient approach. This in the case where the trpc endpoints are served from another backend.

trpcServerComponent.ts

import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
import type { AppRouter } from "../../trpc-server-in-monorepo/src/trpcRouters";
export const trpcProxyClient = createTRPCProxyClient<AppRouter>({
	links: [
		httpBatchLink({
			url: TRPC_SERVER_URL,
		}),
	],
});

And using it for example to generate page metadata:
page.tsx

import { trpcProxyClient } from "../../utils/trpcServerComponent";

type Params = {
	slug: string;
};

type Props = {
	params: Params;
	searchParams: { [key: string]: string | string[] | undefined };
};

export async function generateMetadata({ params, searchParams }: Props, parent: ResolvingMetadata): Promise<Metadata | undefined> {
	return trpcProxyClient.endpoint.query({slug:params.slug}).then((response)=>{ return {title: response.title}})
}

export default async function Page(......

This seems to work well, however is this a bad approach with drawbacks?

@me-imfhd
Copy link
Contributor

me-imfhd commented Oct 3, 2023

DARN, this thing hasn't been released to work with, and I've been stuck on it for so long that I even ended up reading API codes, LOL. I hope support for the app router is released as soon as possible; it would be a fantastic!

@bibblebabl
Copy link

DARN, this thing hasn't been released to work with, and I've been stuck on it for so long that I even ended up reading API codes, LOL. I hope support for the app router is released as soon as possible; it would be a fantastic!

AFAIK there is a way to use it with App Router already.

I don't know why TRPC team hasn't updated the doc with these examples, but it's actually working solutions you can adapt.

https://youtu.be/qCLV0Iaq9zU?si=-Cf4ZmpsgSDUzeJ7

https://youtu.be/hp-z01yAaRU?si=qJehUg5cGeD3ECIL

https://youtu.be/iHJuJdw1jEM?si=swarcGwsBpy2vtG_

@me-imfhd
Copy link
Contributor

me-imfhd commented Oct 5, 2023

yeah i know this, but it uses createTRPCReact and not createTRPCNext, also it uses adatapter as fetch instead of next,
so next is basically limited to pages router due to createTRPCNext, it does not has that feature to be used in app router the way it is used in pages router, in the first first video i guess the guy mentions this but not sure

@Azgaar
Copy link

Azgaar commented Oct 5, 2023

Yes, tried it, it doesn't work fine. The session is getting lost

@giomogna
Copy link

giomogna commented Oct 5, 2023

There is a PR open on the T3 Stack using this approach, seems to be working flawlessly

t3-oss/create-t3-app#1567

@ajdiyassin
Copy link

Any progress on this, now that server actions are stable? nextjs.org/blog/next-14

@natedunn
Copy link

@ajdiyassin Depends what you are asking for specifically. I am using tRPC with RSC's and App dir, but if you are asking specifically about out-of-the-box server actions, I'd keep an eye on #4567 reopening once they make progress.

@ian-os
Copy link

ian-os commented Oct 27, 2023

@ajdiyassin We're using the ts-oss repo recommendation from @giomogna and it's working well. I'd suggest starting there.

@shammalie
Copy link

T3 app router seems to work well, however, i'm struggling with getting subscription websocket server to work because of createTRPCContext uses next headers. This causes header invariant warnings because of passing the context and router to applyWSSHandler.

@thacoon
Copy link

thacoon commented Jan 13, 2024

@shammalie agree, t3 experimental app router works fine, but I also can't get subscriptions running. If anyone has an example using the t3-stack as a base and could share it, that would be fantastic :)

@ItzDerock
Copy link

@thacoon, this might not be exactly what you're looking for, but for websockets, I ended up using a custom router on top of a t3 app scaffolded using the experimental app router feature. It's not the most ideal solution (I'm not sure if you can deploy this to vercel), but it works for my use case and depending on yours, it might work too.

my server entrypoint
const app = next({
  dev: env.NODE_ENV !== "production",
  hostname: env.HOSTNAME,
  port: env.PORT,
  customServer: true,
});

await app.prepare();

const getHandler = app.getRequestHandler();
const upgradeHandler = app.getUpgradeHandler();

const server = createServer((req, res) => {
  // routes starting with /api/trpc are handled by trpc
  if (req.url?.startsWith("/api/trpc")) {
    const path = new URL(
      req.url.startsWith("/") ? `http://127.0.0.1${req.url}` : req.url,
    ).pathname.replace("/api/trpc/", "");

    return void nodeHTTPRequestHandler({
      path,
      req,
      res,
      router: appRouter,
      createContext: ({ req }) => {
        return createTRPCContext({
          req,
          res,
        });
      },
    });
  }

  getHandler(req, res).catch((error) => {
    logger.error(error);
    res.statusCode = 500;
    res.end("Internal Server Error");
  });
});

// create the websocket server
const wss = new WebSocketServer({ noServer: true });
const trpcHandler = applyWSSHandler({
  wss,
  router: appRouter,
  createContext: ({ req }) => {
    return createTRPCContext({
      req,
    });
  },
});

process.on("SIGTERM", () => {
  logger.warn("SIGTERM received, shutting down...");
  trpcHandler.broadcastReconnectNotification();
  server.close(() => {
    process.exit(0);
  });
});

// handle the upgrade
server.on("upgrade", (req, socket, head) => {
  // send trpc requests to the trpc server
  if (req.url?.startsWith("/api/trpc")) {
    wss.handleUpgrade(req, socket, head, (ws) => {
      wss.emit("connection", ws, req);
    });
  } else {
    void upgradeHandler(req, socket, head);
  }
});

server.listen(env.PORT, env.HOSTNAME, () => { ... });

@thacoon
Copy link

thacoon commented Jan 13, 2024

@ItzDerock thanks for your quick reply.

I also just made it worked (for development) based on https://github.com/trpc/examples-next-prisma-websockets-starter, this example is not using the app router but it helped me solving it.

Details

Project is based on the t3-stack using app router.

My src/server/wsServer.ts looks like this now (copied from the example above):

import {
  applyWSSHandler,
  type CreateWSSContextFnOptions,
} from '@trpc/server/adapters/ws';
import { WebSocketServer } from 'ws';
import { appRouter } from '~/server/api/root';
import { type CreateNextContextOptions } from '@trpc/server/adapters/next';

const wss = new WebSocketServer({
  port: 3001,
});

export const createContext = async (
  opts: CreateNextContextOptions | CreateWSSContextFnOptions
) => {
  return {};
};

const handler = applyWSSHandler({
  wss,
  router: appRouter,
  createContext,
});

wss.on('connection', (ws) => {
  console.log(`➕➕ Connection (${wss.clients.size})`);
  ws.once('close', () => {
    console.log(`➖➖ Connection (${wss.clients.size})`);
  });
});
console.log('✅ WebSocket Server listening on ws://localhost:3001');

process.on('SIGTERM', () => {
  console.log('SIGTERM');
  handler.broadcastReconnectNotification();
  wss.close();
});

The types for createContext is wrong right know and I need to fix it but it works, after some hours of trial and error.

And my src/server/trpc/react.tsx:

'use client';

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import {
  createWSClient,
  loggerLink,
  unstable_httpBatchStreamLink,
  wsLink,
} from '@trpc/client';
import { createTRPCReact } from '@trpc/react-query';
import { useState } from 'react';

import { type AppRouter } from '~/server/api/root';
import { getUrl, transformer } from './shared';

export const api = createTRPCReact<AppRouter>();

export function TRPCReactProvider(props: {
  children: React.ReactNode;
  cookies: string;
}) {
  const [queryClient] = useState(() => new QueryClient());

  const [trpcClient] = useState(() =>
    api.createClient({
      transformer,
      links: [
        loggerLink({
          enabled: (op) =>
            process.env.NODE_ENV === 'development' ||
            (op.direction === 'down' && op.result instanceof Error),
        }),
        wsLink({
          client: createWSClient({
            url: `ws://localhost:3001`,
          }),
        }),
        unstable_httpBatchStreamLink({
          url: getUrl(),
          headers() {
            return {
              cookie: props.cookies,
              'x-trpc-source': 'react',
            };
          },
        }),
      ],
    })
  );

  return (
    <QueryClientProvider client={queryClient}>
      <api.Provider client={trpcClient} queryClient={queryClient}>
        {props.children}
      </api.Provider>
    </QueryClientProvider>
  );
}

And similar to the example I have this in my package.json:

{
  ...
  "scripts": {
    ...
    "dev:wss": "dotenv tsx watch src/server/wsServer.ts --tsconfig tsconfig.json",
    "dev:next": "next dev",
    "dev": "run-p dev:*",
    ...
  },
 ...
}

@shammalie
Copy link

shammalie commented Jan 13, 2024

@thacoon I've tried to reuse the context in T3 app router, but i get errors with next-auth, since the app router context collects the session via getServerAuthSession(), this proceeds with the following: ProviderX is not a function, ProviderX being Discord in this example, or any provider. I'm realativly new to typescript so it could be a config issue, but i beleive the function error comes from the module augmentation because the compiler can't find next-auth module?

The error above comes from running the WSServer.

Here's the repo i use to test weird and wacky things with T3 stack.
https://github.com/shammalie/playground-t3-app

@shammalie
Copy link

@ItzDerock I tried your example below but couldn't get it to work, could you have a look?
https://github.com/shammalie/playground-t3-app/blob/main/src/server/prodServer.ts

@thacoon
Copy link

thacoon commented Jan 17, 2024

Off topic

@thacoon I've tried to reuse the context in T3 app router, but i get errors with next-auth, since the app router context collects the session via getServerAuthSession(), this proceeds with the following: ProviderX is not a function, ProviderX being Discord in this example, or any provider. I'm realativly new to typescript so it could be a config issue, but i beleive the function error comes from the module augmentation because the compiler can't find next-auth module?

The error above comes from running the WSServer.

Here's the repo i use to test weird and wacky things with T3 stack. https://github.com/shammalie/playground-t3-app

In your local .env I think you need to assign DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET some value (at least just something), I think this is the error you get if they are empty.

@xsjcTony

This comment was marked as abuse.

@KATT
Copy link
Member Author

KATT commented Feb 10, 2024

There is an experimental release. I will start adopting RSC myself in prod over the next few months and it'll get more love gradually throughout that - some other core members are actively looking at this too.

Please do not @ OSS-maintainers to do things for you - you're free to sponsor the issue using the link above and/or try to contribute to the project and/or suggest good APIs how it'd look like. If you're not contributing financially nor with work, please be patient with us when we do mostly work on this mostly for free.

@michaelhays
Copy link

Nothing but love and respect for everything you do here Alex!

If anything, I do understand the desire to stay in the know for these things that impact the future of the library so much, just for an understanding of where they are in the pipeline. I've been trying to follow along by checking various branches and PRs here and in T3 every couple of weeks, but haven't been able to figure much out.

Even a short message from time-to-time such as "This isn't stable enough in Next.js, we're going to wait at least several months before releasing something" or even "We're working on other things for now" is always much appreciated :)

@rwieruch
Copy link
Contributor

@KATT where can we find the experimental release so that we can test it too? :) Thanks for all your hard work! 💯

@TzviPM
Copy link

TzviPM commented Feb 15, 2024

I would be willing to build out a POC for this if it hasn't been done yet. My proposed approach would be to move the react query client from context into the trpc client or a wrapper. This would allow us to provide react query's prefetchQuery functionality inside of server components. We already seem to have this functionality, it's just accessed with useContext, which won't work in a server component. Thoughts?

@prashantbhudwal
Copy link

prashantbhudwal commented Apr 4, 2024

For folks who want to use tRPC with app router and seek examples, this the best in-prod codebase out there -
https://github.com/documenso/documenso.git

Till we get something stable, this is a great stopgap.

@iantanwx
Copy link

For folks who want to use tRPC with app router and seek examples, this the best in-prod codebase out there - https://github.com/documenso/documenso.git

Till we get something stable, this is a great stopgap.

Can confirm documenso solution is a solid one. I have used it to bootstrap a new SaaS, albeit with v11 beta.

@vertis
Copy link

vertis commented May 8, 2024

As far as I can tell from the github.com/documenso/documenso.git repo this is just doing client side support. Doesn't (that I could see) have any RSC, SSR elements.

FWIW It's pretty similar to the setup I'm currently using, which I did not get directly from that repo but is possibly inspired by. I can confirm that it does work but not for prefetching (or equiv)

@prashantbhudwal
Copy link

prashantbhudwal commented May 10, 2024

@vertis documenso uses data fetching with async functions in server components, and when they mutate the data using trpc, they just call router.refresh() after the mutation. That way, you get SSR and mutation capabilities from trpc. So.

In server components

  • fetch data with async functions/fetch and pass it down to client components

In client components

  • use this data directly (without adding it as initial values to query)
  • call router.refresh() after mutation is done using tRPC/query
    • Props change, and client is re-rendered

Again, everything is a stopgap.

(You can also use this: https://youtu.be/qCLV0Iaq9zU?si=HSqR_FIEWsOz2F-b&t=933)

@musjj
Copy link

musjj commented May 10, 2024

There is a lot of info on this thread and I'm kinda lost. But just to get it straight, is the best approach of using trpc with the App Router is to use createTRPCReact instead of createTRPCNext?

This seems to be the approach used by the repo examples I've gathered:

Am I getting this right?

EDIT: Some nice info here (seems relevant even though it's 2 years old): #3185 (comment)

@prashantbhudwal
Copy link

@musjj The repo mentioned there has been archived. Here is the latest one with the official trpc roadmap for rsc support.

https://github.com/trpc/examples-next-app-dir

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 🚧 In Progress
Development

No branches or pull requests