Open jplhomer opened 2 years ago
How do we get Vite to behave differently based on react-server context? React uses node --conditions react-server. Do we need two separate server builds or dev processes (this seems inefficient)? Is there a better way to do this?
There are two type of way node --conditions react-server
flag is being use
I am not exactly sure what to do with 1, but for two I am curious to explore loading the correct module base on file post fix. ie. if the file importing it is .server.js
, load the node version, if its .client.js
, load the browser version. I think this can be done with some sort of Vite plugin.
So I've been tinkering with the offical RSC and found out it directly crashes when a Provider is used. Since our dev project is full of providers, I'm testing with a dummy app without any providers (we are supposed to remove them anyway). The whole tree looks like this (CartIcon is the only Client Component):
<div>
<div>hello!</div>
<CartIcon />
</div>
RSC response using our custom RSC implementation (in main branch):
M1:{"name":"CartIcon","id":"/Users/frandiox/src/github.com/Shopify/hydrogen/packages/dev/src/components/CartIcon.client.jsx","named":false}
J0:["$","div",null,{"children":[["$","div",null,{"key":0,"children":"hello!"}],["$","@1",null,{"children":null}]]}]
RSC response using the official implementation:
M1:{"id":"/Users/frandiox/src/github.com/Shopify/hydrogen/packages/dev/src/components/CartIcon.client.jsx","name":"CartIcon","named":false}
J0:["$","div",null,{"children":[["$","div",null,{"children":"hello!"}],["$","@1",null,{}]]}]
The only different is that the official approach is missing "key": 0
.
However, when adding Suspense to the root of the dummy app, this happens.
RSC response using our custom RSC implementation (with Suspense):
M1:{"name":"CartIcon","id":"/Users/frandiox/src/github.com/Shopify/hydrogen/packages/dev/src/components/CartIcon.client.jsx","named":false}
J0:["$","div",null,{"key":1,"children":[["$","div",null,{"key":0,"children":"hello!"}],["$","@1",null,{"children":null}]]}]
RSC response using the official implementation:
S1:"react.suspense"
M2:{"id":"/Users/frandiox/src/github.com/Shopify/hydrogen/packages/dev/src/components/CartIcon.client.jsx","name":"CartIcon","named":false}
J0:["$","$1",null,{"children":["$","div",null,{"children":[["$","div",null,{"children":"hello!"}],["$","@2",null,{}]]}]}]
@wizardlyhel @jplhomer Do you think these differences are normal? Is the Suspense supposed to appear in the payload of the official implementation? 🤔
NOTE: this is still using our custom logic in the browser to parse the RSC response, that's why I'm passing "named" instead of "chunks".
@frandiox Yup - the S1:"react.suspense"
is normal. Think of them are acting like client components waiting to be downloaded.
I'm gonna defer to @jplhomer on how he implemented Suspense with our custom implementation with key
@frandiox Yep you're spot-on. key
is probably there because of my super hacky parsing mechanism 😬 we should trust whatever the official RSC implementation offers.
Additionally, the official RSC implementation uses name: <name>
rather than named: true/false
, and that matches how RSC resolves everything in the client. (this is before I learned how all of this worked)
Blocked by:
@shopify/react-testing
doesn't work with React 18 experimental.~ (fixed in #312 )react-server
and react-client
packages (they won't be published).~Update: Since react-server
and react-client
packages won't be published to NPM, we need to make a PR to React repo instead: https://github.com/facebook/react/pull/22952
This might be packaged into React core as a sibling package to
react-server-dom-webpack
, e.g.react-server-dom-vite
. Alternatively, it might be a standalone plugin or package. It depends on what direction the core team decides and what other meta-frameworks do (like Next.js).react-server
flag is present.pipeToNodeWritable
React function on the server, which generates the RSC responseOutstanding questions:
react-server
context? React usesnode --conditions react-server
. Do we need two separate server builds or dev processes (this seems inefficient)? Is there a better way to do this?react-server
condition going to work in a Workers runtime, where a single bundle is present and executed in a v8 isolate? How is this going to work?Note: This is a bit of a moving target, as we've recently embarked on a mission to help React bundle client components more efficiently: https://github.com/facebook/react/issues/22314
So whatever we build for Vite should match the output of those explorations.