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

@trpc/next with ssr: true breaks getServerSideProps #596

Closed
akomm opened this issue Jun 25, 2021 · 33 comments
Closed

@trpc/next with ssr: true breaks getServerSideProps #596

akomm opened this issue Jun 25, 2021 · 33 comments
Labels
blocked 🐛 bug Something isn't working wontfix This will not be worked on by KATT

Comments

@akomm
Copy link

akomm commented Jun 25, 2021

Notes by @KATT:


@trpc/next: 8.0.0-alpha.6

Using:

export default pipe(
  App,
  withTRPC({
    ssr: true,
    config: (_ctx) => ({
      url: "http://localhost:3000/api/trpc",
      queryClientConfig: {
        defaultOptions: {
          queries: {
            staleTime: 600
          }
        }
      }
    }),
  })
)

Any page with getServerSideProps, for example:

export const getServerSideProps: GetServerSideProps<Props> = async () => {
  return {
    props: {
      user: {
        name: 'x',
        email: "y"
      }
    }
  }
}

Will receive undefined props, then get refreshed with props (the latter usually never executes due to errors using undefined)

Removing withTRPC hof stops this behavior.

@KATT
Copy link
Member

KATT commented Jun 26, 2021

Sounds like a bug.

On holidays for two weeks now, so if you want it fixed before that, submit a PR and I'll prob be able to review/merge/release.

I personally never use getserversideprops as it adds delay on route changes

@KATT

This comment has been minimized.

KATT added a commit that referenced this issue Jul 12, 2021
shows #596 being a non-issue
@KATT

This comment has been minimized.

@KATT KATT closed this as completed Jul 12, 2021
@KATT KATT added the 👻 invalid Invalid bug report label Jul 12, 2021
@akomm

This comment has been minimized.

@KATT

This comment has been minimized.

@KATT

This comment has been minimized.

@akomm

This comment has been minimized.

@KATT

This comment has been minimized.

@etienne-dldc

This comment has been minimized.

@KATT

This comment has been minimized.

@etienne-dldc

This comment has been minimized.

@KATT
Copy link
Member

KATT commented Aug 2, 2021

@etienne-dldc do you think there's anything that can be done inside of tRPC to counter it then?

Personally I never need to use getServerSideProps as I just expose whatever I want as a tRPC route that I use useQuery() on.

getServerSideProps slows down route changes, but getInitialProps doesn't.

@etienne-dldc
Copy link

Not sure, the problem come from ssrPrepass and I'm not sure to understand what it does.

In my case I was experimenting with Trpc but I rolled back because of this issue.

getServerSideProps slows down route changes, but getInitialProps doesn't.

I'm not sure about that, can you elaborate ?

@akomm
Copy link
Author

akomm commented Aug 4, 2021

@etienne-dldc even when you navigate client-side, the router still needs to execute the "getServerSideProps" on the server to get the props. Its done via a background fetch to the route, which only retrieves the result of getServerSideProps as json, instead of the whole rendered component. Then the props are populated on client-side. This trip to fetch the props and populate is what cause a delay on navigation and I guess what @KATT means.

However, getInitialProps implies using class components, which is quite an expectation. Unless I'v missed some other way around it, then please correct me.

@etienne-dldc
Copy link

@akomm @KATT The server call to getServerSideProps does not slow down the page it only change the order in which event happen. Instead of PageChange -> Load Data you get Load Data -> PageChange.

@akomm You can use getInitialProps with function component: https://nextjs.org/docs/api-reference/data-fetching/getInitialProps

@KATT
Copy link
Member

KATT commented Aug 4, 2021

@akomm @KATT The server call to getServerSideProps does not slow down the page it only change the order in which event happen. Instead of PageChange -> Load Data you get Load Data -> PageChange.

  • getServerSideProps: user clicks -> routeChangeStart --> ⏳ [..delay] --> routeChangeComplete
  • getInitialProps: user clicks -> routeChangeStart --> 🚀 instant --> routeChangeComplete

The difference is that you'll have to handle the loading client-side with getInitialProps.

For an implementation of this with tRPC doesn't require a loading you can check out https://typescript.careers which optimistically loads the data of all routes on mount (as 1 single batch request), making navigation feel instant.

If you use getStaticProps you can get instant loading as well.

See https://nextjs.org/docs/api-reference/next/router#routerevents

@akomm You can use getInitialProps with function component: https://nextjs.org/docs/api-reference/data-fetching/getInitialProps

That's what we do in tRPC - see https://github.com/trpc/trpc/blob/main/packages/next/src/withTRPC.tsx#L85

@KATT KATT reopened this Aug 16, 2021
@KATT KATT changed the title @trpc/next another withTRPC bug - breaks SSR on pages @trpc/next with ssr: true breaks getServerSideProps Aug 16, 2021
@KATT KATT added 🐛 bug Something isn't working and removed 👻 invalid Invalid bug report 🔎 needs more investigation/info labels Aug 16, 2021
@KATT
Copy link
Member

KATT commented Aug 17, 2021

This issue seems valid after all. Sorry for initially closing it. It's for the same as urql can't do it, see here - urql-graphql/urql#1091.

I'm doing some exploratory stuff to see if there's a workaround.

@KATT
Copy link
Member

KATT commented Aug 17, 2021

Yes, for most applications this is true, but as a library author getInitialProps is super useful as it's the only thing that can do a prepass render the whole tree and do things like caching useQuery-calls, etc. And as I previously mentioned, the DX/UX you can get thanks to this is unparallel.

tRPC's plugin is largely based on urql's implementation - you can read more details about theirs here: https://formidable.com/open-source/urql/docs/advanced/server-side-rendering/

@KATT
Copy link
Member

KATT commented Aug 18, 2021

Solving this is blocked by vercel/next.js#28183.

@GuiSim
Copy link
Contributor

GuiSim commented Nov 27, 2021

I just encountered this issue.
I wanted to use getServerSideProps for authorization but the page still gets rendered before the props gets loaded (and then re-rendered after that).

Steps to reproduce:
Create a sample project
npx create-next-app --example https://github.com/trpc/trpc --example-path examples/next-prisma-starter trpc-prisma-starter

Create src/pages/home.tsx

export default function Home(props) {
  console.log('Rendering with props '   JSON.stringify(props));
  return (
    <>
      <h1>Props v</h1>
      <p>{JSON.stringify(props)}</p>
    </>
  );
}

export async function getServerSideProps(context) {
  console.log('Getting server side props');
  return {
    props: {
      firstName: 'Hello',
    },
  };
}

Going to localhost:3000/home will log the following in the server's console:

Rendering with props {}
Getting server side props
Rendering with props {"trpcState":{"json":{"mutations":[],"queries":[]}},"firstName":"Hello"}

Expected:

Getting server side props
Rendering with props {"trpcState":{"json":{"mutations":[],"queries":[]}},"firstName":"Hello"}
  • getServerSideProps gets called before the Home page is rendered. The page gets rendered with a full props object.

Actual:

  • The page is rendered with empty props, getServerSideProps is then called and the page is re-rendered with the props.
Rendering with props {}
Getting server side props
Rendering with props {"trpcState":{"json":{"mutations":[],"queries":[]}},"firstName":"Hello"}

@GuiSim
Copy link
Contributor

GuiSim commented Nov 27, 2021

Setting ssr to false "solves" this issue.

I'm unsure what the drawbacks of this are but it seems like a workaround at the moment.

@akomm
Copy link
Author

akomm commented Nov 29, 2021

I guess the query hook will only run on client and not server then. When I last read the docs it was not explained, this is just what I think it does and would make sense to me. I sometimes wish docs for components that are isomorphic clearly states "this can run ssr/client", this not. You have to guess and test often times. Sometimes its almost obvious, but you are never really sure.

@KATT
Copy link
Member

KATT commented Nov 29, 2021

I'm a one man band making tRPC, all example projects, and docs.. there are limits to what I have bandwidth to do. Super keen to take on pull requests from contributors with the gaps as you learn the edge cases.

This issue of combining getSSR getSSG and getInitialProps is out of my hands to fix as it's an issue with Next.js - if you have ideas for workarounds, they are welcome as well.

If you encounter this, set ssr: false in your _app.tsx.

@KATT
Copy link
Member

KATT commented Nov 29, 2021

Note: it's still possible to do manual server-side rendering or static props with ssr: false using the getSSGHelper - https://trpc.io/docs/ssg

@GuiSim
Copy link
Contributor

GuiSim commented Nov 29, 2021

Alex, I truly appreciate what you've done with this library and I understand that this is a limitation of Next.js.

I'm glad we have a workaround and I don't mean to put pressure on you to deliver anything here. Thanks again for the solid lib.

For me, the main value of TRPC is a typesafe API between my frontend and my backend using shared types. The rest is just gravy on top :)

@mmkal
Copy link
Contributor

mmkal commented Jul 18, 2022

Worth watching:

@apieceofbart
Copy link

apieceofbart commented Sep 17, 2022

Thank you for the this thread, I had a hard time figuring out why the props are undefined :)
Could someone explain to me why ssr: false actually fixes this? I can see the server returning the html just as I would expect.
I mean It's counterintuitive since we want to enable ssr, right?

@akomm
Copy link
Author

akomm commented Sep 19, 2022

@apieceofbart there are two independent things that aren't exactly the same.

  1. Your components (JSX/TSX) can re rendered on server or client.
  2. The getServerSideProps can be used when rendering component on server or client.

IIRC, its a while back:

the option ssr in trpc only affects the rendering of JSX/TSX server-side. It uses getInitialProps. But in getInitialProps you don't get access to the result ofgetServerSideProps - this is why its currently undefined with ssr: true. When you set ssr: false you do not disable getServersideProps, so everything that comes from it as a result can be rendered server-side, once the ssr feature is disabled, because then getInitialProps is not used.

@apieceofbart
Copy link

@akomm Thank you for your comment - I do not fully understand it but I'll read some more about trpc. From what I understand it uses getInitialProps behind the scenes when ssr is set to true.

@kamilogorek
Copy link
Member

@KATT Should this issue be closed if its a wontfix?

@akomm
Copy link
Author

akomm commented Feb 27, 2023

Since it depends on a change on next-side and I don't think they will mess with it a lot because the future is probably their app system rework / RSC, so this is obsolete anyway.

@kamilogorek
Copy link
Member

Default GH search includes all closed issues, so this issue will still pop up when searching for getServerSideProps or ssr (more keywords, yay) in case someone wants to read on this issue.
If more people will report this instead of searching, we can reopen/pin it.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
blocked 🐛 bug Something isn't working wontfix This will not be worked on by KATT
Projects
None yet
Development

No branches or pull requests

7 participants