Hydrated component isn't initialized in prod builds when it is exported/imported under a name different from the name of the component it decorates
See original GitHub issueA bit cryptic title but let me explain what this is about 😃
Currently, in production mode code assumes that the name of the component that the withHydrate
hook decorates and the name under which the decorated component is imported into the page are the same which is not always true.
The withHydrate
hook when renders HTML stores the name of the component it decorates as a marker. The hydration code then reads the marker and tries to locate a component with this name among hydration bindings. Hydration bindings are determined based on named exports of the component file or default import names in the page component.
There are two cases when this logic fails.
A named export case:
// hydrated-component.tsx
export const HydratedComponent = withHydrate(HydratedComponentInternal);
// page.tsx
import {HydratedComponent} from './hydrated-component.tsx';
Default import case:
// hydrated-component.tsx
export default withHydrate(HydratedComponentInternal);
// page.tsx
import HydratedComponent from './hydrated-component.tsx';
In both cases in prod, the hydration code would try to locate the HydratedComponentInternal
in the binding but this attempt would fail as there would be only single binding for the HydratedComponent
.
Fixing this turned out to be tricky. The only fix I can think about is to parse hydration chunks, determine exported component names, and prefill a displayName
parameter of the withHydrate
hook with the corresponding names. This solution feels a bit hacky.
I’m wondering if you have any thoughts on what would be the right way to fix it. Take a look when you have time =)
Adding a repro below.
Steps to reproduce
- Checkout a
named-export-fix
branch in this repository. - Run
npm run serve
- Open
http://localhost:8888/
Expected behavior
The page renders, HydratedComponentA
and HydratedComponentB
get hydrated and two alert messages are shown.
Actual behavior
The page renders but no components are hydrated because of a runtime js error.
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (4 by maintainers)
Turns out traversing the AST was necessary to map the internal component name back to the exported name! Take a look at what I came up with in #149. Seems to be working well 😄
That’s an interesting idea! It should work! Adding
__isWithHydrate
and name hoisting should be straightforward.The most significant change that would be needed is to include inner component names into the
hydrateBindings
hash so that the runtime part would know a link to the file with the component that it wants to hydrate. Currently, thehydrateBindings
contains exported names of the components as they appear in the source code and not the inner component names.Maybe you see an easier way how runtime could locate a hydration chunk of an SSR rendered component?
A random idea: we could possibly add a hashed URL of the chunk next to other metadata that the
withHydration
renders in the SSR mode. Though, this would require modifying the AST just like in my pr linked above.