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

Next.js SSR example #1596

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft

Next.js SSR example #1596

wants to merge 12 commits into from

Conversation

balegas
Copy link
Contributor

@balegas balegas commented Aug 29, 2024

Items example using SSR.

Load the entire shape on the server and send it down to the client, so that the client gets the initial state of the shape on first response and can resume replication from the tip of the shape stream.

First time with nextjs, I still don't know how some things work. I suppose this is good forn an example. I'm happy to receive feedback from nextjs experts :D

Copy link
Contributor

@KyleAMathews KyleAMathews left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few comments.

Don't you want to use either https://nextjs.org/docs/pages/building-your-application/data-fetching/get-server-side-props or https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props here? Right now I don't see that any data is being cached during server rendering.

EDIT: Oh I see... this is RSC stuff

examples/nextjs-ssr-example/app/Home.tsx Outdated Show resolved Hide resolved
examples/nextjs-ssr-example/app/Home.tsx Outdated Show resolved Hide resolved
examples/nextjs-ssr-example/app/shape.tsx Outdated Show resolved Hide resolved
packages/typescript-client/src/client.ts Outdated Show resolved Hide resolved
examples/nextjs-ssr-example/app/page.tsx Outdated Show resolved Hide resolved
Copy link

netlify bot commented Oct 3, 2024

Deploy Preview for electric-next ready!

Name Link
🔨 Latest commit 2d8330e
🔍 Latest deploy log https://app.netlify.com/sites/electric-next/deploys/672ea96f3d17d70008fe3ea1
😎 Deploy Preview https://deploy-preview-1596--electric-next.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@samwillis
Copy link
Contributor

First, I think there is going to be two ways people want to do SSR with useShape:

  1. Fetch the full snapshot on the server, render it, and then include the snapshot in the HTML sent to the client. This allows the client to just continue from where it was in the stream (just as this PR does). This would make sense for smaller shapes - such as a single issue + comments on a detail view.

  2. Render a subset of the data on the server, not include the snapshot in the HTML sent to the client, and then fetch the full snapshot on the client. This would make sense for larger shapes - such as a very long list of issues, just rendering the "above the fold" on the server. Refetching already rendered data is ok in this situation.

I think we want to provide tooling for both of these cases.


On 1 - snapshot of the shape and resume

While the pattern in this PR works, having to pass the shape snapshot to the component using useShape via props is a little messy. It would be great if we could provide a cleaner API that "just works" with SSR.

I think this is doable if we create a <ShapeSsrStore> (or similar) component that the user wraps their app in. This component will keep track of all useShape calls done during SSR and then inject a <script> tag with the JSON of those shapes as a global (keyed by shapeId?). This can then be read back and used when hydrating the useShapes on the client.

We are somewhat restricted as we cant use a react context, but something like this POC is possible: https://github.com/samwillis/ssr-shape-poc (I've purposely not used any electric, just wanted to test the concept for injection)

By the user adding <ShapeSsrStore>, all useShapes would SSR with automatic resume. (We could make this opt in with a flag to the useShape options)

This is also not tied to Next, and should work with all React SSR frameworks.

image

On 2 - a minimal subset on the server

I think we should add a getServerSnapshot option to useShape that is only run on the server. The user can configure this to do a direct Postgres query to fore a subset of data for SSR. This would override the shape URL can just any snapshotting from option 1 above.

useShape({
  url: `http://localhost:3000/v1/shape/foo`,
  getServerSnapshot: () => {
    // Do and return a Postgres query
  },
})

@thruflo
Copy link
Contributor

thruflo commented Oct 8, 2024

Great stuff @samwillis :)

On 2, I wonder if there's a way of supporting order_by and limit of the shape results? An arbitrary query is powerful but means the user needs to format the results in the same way as the shape data. This will become harder as and when we support nested associations. So is there an approach where the user could order/limit/(filter?) the shape when convenient and then drop down to a function when that's not expressive enough?

Copy link
Contributor Author

@balegas balegas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samwillis inspired on your example and Nextjs docs, I gave another try. The idea here is to have a context around the component that takes the server-sent data from props and initializes the shapes on the client --- totally transparent on the client component!

Left some comments

examples/nextjs-ssr-example/app/ssr-shapes-provider.ts Outdated Show resolved Hide resolved
packages/react-hooks/src/react-hooks.tsx Show resolved Hide resolved
examples/nextjs-ssr-example/app/page.tsx Outdated Show resolved Hide resolved
packages/typescript-client/src/shape.ts Show resolved Hide resolved
examples/nextjs-ssr-example/app/Home.tsx Outdated Show resolved Hide resolved
@balegas
Copy link
Contributor Author

balegas commented Oct 25, 2024

Render a subset of the data on the server,

@samwillis, @thruflo my initial idea was to call the database directly on the server. This is a powerful pattern to show, but because of the problems with ordering and paging, I thought it would be better to build just on Shapes. The benefit of Shapes is that requests go through the cache and doesn't put load on the server db.

A naive way of rendering the subset of data on the server is to just drop the data that doesn't fit into the initial page rendering :)

@balegas
Copy link
Contributor Author

balegas commented Nov 12, 2024

@samwillis , I did a DX refactoring addressing your concerns with it being simple to specify the shapes across server and client. Have a look at it or ping me to see together.

I also want to replace the base nextjs example with this one (cc @KyleAMathews)

@balegas balegas self-assigned this Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants