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

Inferno hydrate promise #1459

Open
niofis opened this issue Mar 18, 2019 · 9 comments
Open

Inferno hydrate promise #1459

niofis opened this issue Mar 18, 2019 · 9 comments
Labels

Comments

@niofis
Copy link

niofis commented Mar 18, 2019

I am toying with a proof of concept for having a full app built in inferno that's server side rendered and hydrated on the client side. With the aim of having it work even if the client has no javascript enabled.

You can take a look at the current implementation here: https://github.com/niofis/ssr-todo, the only problem is, that the hydrate step clears the target DOM before the state for the components is initialized, making the app flicker on first time render.

On the server side there is a method for the components called getInitialProps, that would be very useful if it could be called client side as the hydrate step is running. But for that to happen, inferno-hydrate would need to be updated to work with promises, would you like to have that kind of functionality?

@Havunen
Copy link
Member

Havunen commented Mar 19, 2019

@niofis

the only problem is, that the hydrate step clears the target DOM before the state for the components is initialized, making the app flicker on first time render.

I cloned your repository and noticed you are doing development in minified (production) version of InfernoJS. When you do that you are missing all development warnings and validations. After changing your template infernojs source to

<script src="https://unpkg.com/[email protected]/dist/inferno.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/inferno-hydrate.js"</script>

You can see error in console. Inferno hydration: Server-side markup doesn't match client-side markup This is why the flicker happens.

@Havunen
Copy link
Member

Havunen commented Mar 19, 2019

I don't know where this getInitialProps method has come from? Maybe its been there since the first version of ssr implementation. I couldn't find any documentation about it either... Maybe @trueadm knows.

@trueadm
Copy link
Member

trueadm commented Mar 19, 2019

I'm not sure about getInitialProps either. I don't remember adding it? I believe Next.js had something similar back in the day, so maybe it's from that. Either way, in my opinion, it should be removed as it's clearly not right and is causing confusion. Props should be passed via vNodes only, having them resolve via some method breaks a lot of assertions.

@nykula
Copy link
Contributor

nykula commented Mar 19, 2019

History before monorepo says @ddibiase and @thysultan worked on experimental Render Stream API that Inferno 1.2.1 introduced in 2017. I prefer another data loading approach, which is probably similar to what they were trying to replace that however worked fine for me last year.

On server, after routing but before rendering, create stores and pass them to a static method on top-level route. JSON the stores into an initial state variable in the response. Use it to set up the stores in browser. Call that same method from componentDidMount with current props, including the injected stores, but only if data is missing, for example when the user switches the active route.

The tooling for this in my serverside tool also understands Helmet and does roundtrip optimization. Supported React too, but their internals that I used aren't compatible since they introduced code splitting. A tiny implementation of routing and state management specifically targeting Inferno went to refstore.

Nowadays I would depend on Parcel instead of monkey patching create-something-app, and transpile and bundle only the client side, while the server would directly import source JS modules, HyperScript not JSX. It rebuilds way faster, though at some cost in runtime performance. And I would structure like you're doing, without nesting directories, but that's an arguable implementation detail. Something interesting I've also seen in ssr-with-prepack-hackathon.

@niofis
Copy link
Author

niofis commented Mar 19, 2019

@Havunen exactly; that happens because on first render the markup doesn't match with the virtual dom generated by hydrate, as the components do not have the same props like the ones used when doing the server side rendering; but if the hydrate step worked the same way as streamQueueAsString does, calling getInitialProps for each compononent, then the same markdown structure could be generated and the switch from static to virtual dom would be seamless.

@trueadm getInitialProps has been in Inferno since this commit back in 2017, and it's used by streamQueueAsString to initialize the props for components before first render when doing ssr.

@makepost actually, that's the way we are currently doing ssr and hydration in the project I'm working on; stores are initialized before render/hydration and then passed down to components as props, but it's a step that could be delegated to individual components without having to rely on another library or workflow.

In any case, it could allow a different strategy for working with ssr. Currently the proof of concept I show you aims to have the same App.jsx used for both server and client side rendering with little changes, using StaticRouter in the backend to make it behave like a regular app, and like an SPA with BrowserRouter. I can update hydrate to use getInitialProps, but I'm still not sure if it would be a welcome change or other than myself would make use of it; also, I'm not aware if there could be any issues regarding side effects with other parts of inferno.

@nykula
Copy link
Contributor

nykula commented Mar 19, 2019

same App.jsx used for both server and client side rendering with little changes, using StaticRouter in the backend to make it behave like a regular app, and like an SPA with BrowserRouter

How is this part different in the current approach?

@niofis
Copy link
Author

niofis commented Mar 19, 2019

same App.jsx used for both server and client side rendering with little changes, using StaticRouter in the backend to make it behave like a regular app, and like an SPA with BrowserRouter

How is this part different in the current approach?

Currently it doesn't have any routing, I'm just expanding on what the aim is.

@nykula
Copy link
Contributor

nykula commented Mar 21, 2019

@niofis While I don't understand where in your proposal hydrate is supposed to look for the existing state and how you avoid re-fetching what the server passed but do fetch on route change, as a whole this is interesting. Please keep on.

@Havunen
Copy link
Member

Havunen commented Jul 17, 2019

@niofis What do you think about removing getInitialProps method all together. Maybe you can use constructor or other lifecycle method to do your thing?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

4 participants