themashcodee / slack-blocks-to-jsx

A library for converting Slack blocks to JSX, which can be used with React.
https://www.npmjs.com/package/slack-blocks-to-jsx
11 stars 1 forks source link

Make <Message> SSR-able #11

Open StephenTangCook opened 4 months ago

StephenTangCook commented 4 months ago

For my use case, we would want the <Message> component to be server-side renderable (SSR). Specifically, we use NextJS (info).

I understand that if you want interactivity for certain blocks (e.g. buttons, inputs, etc), this won't be possible. We aren't targeting interactive blocks at the moment, but the larger majority of the components should be SSR-able. It is okay if react interactivity is isolated to those components, and those components should be marked with 'use client'.

This would require the following to be removed/refactored:

themashcodee commented 4 months ago

Hey @StephenTangCook, I have tried a few ways such as passing global data (users, channels, hooks) through prop drilling to remove useEffect and zustand (which uses useRef internally). That worked out but a few components such as plain_text_input, static_select_element, checkboxes_element, users_select_element can't work without react's useState.

Just having two components like static_select_element_client.tsx static_select_element_server.tsx

and use them based on the prop user has passed (example prop - renderingOnServer?:boolean) is not working because the useState is still in the build folder.

So the final solution could be maintaining two copies of the library and then user would be able to import it like this

import { Message } from "slack-blocks-to-jsx/client" import { Message } from "slack-blocks-to-jsx/server"

in the server we won't put useState and useEffect in the build/output folder. But having two copies of the library is little hard and would be hectic.

I understand your concern/thought of choosing SSR over client rendering. SSR indeed gives your speed. But sadly, the solution for now is to use 'use client' in the message wrapper in the end user codebase.

if you have any other idea/solution in your mind to solve this issue, let me know I would love to discuss.

StephenTangCook commented 4 months ago

and use them based on the prop user has passed (example prop - renderingOnServer?:boolean) is not working because the useState is still in the build folder.

What exactly is not working?

Please correct me if I'm not understanding the problem. Can we not just add 'use client'; to those specific component, along with prop drilling? It is okay if the interactive elements are not SSR'd. Those can be client component, and I wouldn't be using them anyways for my use case.

The only issue I foresee there is that you can't pass functions (i.e. your hooks) from server to client components. Unfortunately there is one interactive block that could contain rich text directives for the hooks: the checkbox option description can contain mrkdwn. But for now, I say let's list that as an open gap and not pass the hooks at all. Neither of us need that functionality.

themashcodee commented 4 months ago

@StephenTangCook Yeah we can add "use client" in the components where we are using the react hooks, but prop drilling will make the codebase a little bit dirty because I have a very deep nested components.

I did not get it like why we can't pass my hooks from server to client could you please explain it?

The only issue I foresee there is that you can't pass functions (i.e. your hooks) from server to client components. Unfortunately there is one interactive block that could contain rich text directives for the hooks: the checkbox option description can contain mrkdwn.

StephenTangCook commented 4 months ago

When you pass props from a server component to a client component through the server-client boundary, the props must be serializable. Functions are not serializable, so your hooks would not be able to be passed as props through the boundary.