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

React Server Components #166

Closed
chrisvxd opened this issue Oct 18, 2023 · 6 comments
Closed

React Server Components #166

chrisvxd opened this issue Oct 18, 2023 · 6 comments

Comments

@chrisvxd
Copy link
Member

Users have reported issues when trying to use Puck with React Server Components (RSC).

Specifically, users wish to use RSC for their individual components.

We don't have a proposal for tackling this yet, but please use the comments to report your findings.

@4leite
Copy link
Contributor

4leite commented Oct 22, 2023

I am interested in contributing to this.

Here is a working example app without modification to core using RSC for individual components: https://github.com/4leite/puck/tree/server-render-demo

Some thoughts:
This implementation passes a 'DropZone' prop to the component. When editing, we pass the DropZone component from core. When previewing or server rendering, we pass the render.tsx server component instead.

Nextjs static analysis doesn't like the "render" field on the config object (or any functions for that matter), so we need to move this out of the block component files. It makes sense to collocate the fields and default props with the component so rather than moving the whole object, we export the partial ComponentConfig and compose it with a helper function.

RSC doesn't have access to context, instead we pass the data as props to render.tsx.

We are piggybacking on the defaultProps of the item, and using 'withDropZone' to conditionally render nested DropZones. 'withDropZone' should probably live in 'item' rather than 'item.props'.

A side effect of this implementation is that it may partially solve #71 as the dropzones are no longer rendered when not editing. The flipside is there may be differences in the render for edit and preview.

Passing the DropZone also provides an avenue for implementing #103 by passing a custom DropZone wrapper.

NB: The implementation above also instantiates a libsql database using a postinstall script. This is to facilitate testing the server side render and publish defined in actions.tsx Deploying this to production would require a persistent file system, or (better) a proper database connection.

@chrisvxd
Copy link
Member Author

@4leite Passing DropZones in as props is a really interesting proposal (and quite obvious, now you mention it). Some thoughts:

  • This could easily be baked into <Render> as part of core
  • We might want to consider naming it using render props convention (renderDropZone) rather than as a component (DropZone)
  • I don't think we need to have a withDropZone boolean. We can pass renderDropZone (or DropZone) to all components.
  • We might be able to avoid a breaking change, since whilst importing DropZone from the package won't work with RSC, it would still work for non RSC builds.
  • Refactor to support static analysis makes perfect sense and is uncontroversial

If you want to contribute back with some of the above, that's awesome - otherwise, I'll take your suggestions into account when addressing this myself.

A side effect of this implementation is that it may partially solve #71 as the dropzones are no longer rendered when not editing. The flipside is there may be differences in the render for edit and preview.

As you've noted, I think the render differences between editor and render would be undesirable. We do already render a different DropZone depending on whether you're in the Editor or Render context, and I'm not sure your proposal changes what's possible.

Passing the DropZone also provides an avenue for implementing #103 by passing a custom DropZone wrapper.

That's interesting, although I think we're likely to provide first-party support for this. There's related discussion occurring in #87.

Aside, but it makes me happy to see someone writing a customer Render component on top of the Puck data model 💪

@4leite
Copy link
Contributor

4leite commented Oct 27, 2023

Update:
After some experimenting with POC I think rather than passing the DropZone we can pass an optional "renderCtx" prop.
If the prop is present we render the rsc version of DropZone.

I think I can implement the above without a breaking change.

In order to make some incremental changes rather than one large one, I've opened #192 to update the demo app with the minimal changes to show how a server rendered implementation would work. This adds dummy server actions to simulate server side data fetch and publish. I've also changed "View" button to "Preview" and added preview to the demo which uses the data from localstorage.

The next step would be to update core so that the "use client" directive can be removed from "client-render.tsx".

@4leite
Copy link
Contributor

4leite commented Nov 1, 2023

I've raise #197 which adds support for react server components to core.

A puckCtx prop enables rendering without a context provider.

A Render component that is not bundled with the core module enables importing the Render component in a server component. This solution also means that the render prop does not need to be removed from the component config, ie it is fully compatible with the current config and implementation in the demo app.

@4leite
Copy link
Contributor

4leite commented Nov 2, 2023

Also raised #199 with small changes to next app generator to show usage (depends on #197 above)

@chrisvxd chrisvxd added this to the v1 milestone Nov 2, 2023
@chrisvxd chrisvxd added ready Assumed ready enough to start and removed in triage opinions wanted labels Nov 7, 2023
@chrisvxd chrisvxd added type: feature in progress and removed ready Assumed ready enough to start type: discussion labels Nov 21, 2023
@chrisvxd
Copy link
Member Author

chrisvxd commented Nov 25, 2023

Forgot to close this! Done in #197

@chrisvxd chrisvxd removed this from the v1 milestone Feb 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants