So how exactly does the server perform that same fetch when attempting to hydrate the full page without actually making an HTTP request against itself?
So how exactly does the server perform that same fetch when attempting to hydrate the full page without actually making an HTTP request against itself?
There doesn't appear to be special handling for this use case. However, they use SuperAgent (https://github.com/visionmedia/superagent) for http requests and I expect implementing the behavior that you're describing is relatively easy with their plugin system. Specifically I'd bet that plugins previously designed for testing could be used to accomplish your goal (superagent-mock or superagent-mocker).
In React, people typically use the ExecutionEnvironment module [2] for this:
if (ExecutionEnvironment.canUseDOM) {
// make client side request
} else {
// make direct db request
}
...but you could also just do some simpler check, like see if `window` exists, or make up your own `IS_SERVER` global, etc.Next you'll wonder: won't that still ship the server-side code to the browser, even if it's not run, and pull in any server-only modules you're importing, e.g. database access stuff? No: you'd fix this with (for example) webpack's `DefinePlugin` [3], telling it that `ExecutionEnvironment.canUseDOM` should always be `true` wherever it occurs in your client-side JS bundle, and dead code elimination will then rip out those server-only `else` branches before that code gets shipped to the browser.
Or a similar setup, like wwalser hinted at: write 2 versions of your 'request' module: one for the client, and one for the server. Tell webpack it should point to the client-side one when you generate your client JS bundle. People use webpack because it lets you do all kinds of overrides like this.
[1]: I work at Formidable, we do a ton of React for big companies.
[2]: https://github.com/JedWatson/exenv
[3]: https://webpack.github.io/docs/list-of-plugins.html#definepl...
Imagine writing tests with mocked requests. Now apply that same logic to all calls to fetch() on the server. Does that make sense?
So to the front end when fetch() is called, it actually makes the request. On the server, when fetch() is called it hits a mock plugin which fetches "mocked" data which is just fetching data from whatever local store you normally would on your backend be it a JSON blob on the file system, a database or an in memory cache.
editing to say that @exogen gave what may be a better explanation below: https://news.ycombinator.com/item?id=12273029
That's what I'm apparently failing to describe how to accomplish :).
My team owns one special-snowflake API in React-Server. We want the API to be reachable from the client via HTTP, but also want to execute the code directly during server-side rendering, with no HTTP call. It's your exact use-case.
In order to do that, we
1. Detect if the API is invoked server-side.
2. Tell Superagent* to tell the client "hey, if you want data for $API_URL, don't make an HTTP request; the response will come inline in the page's HTML response.
3. Invoke the API code directly.
4. When the API response is ready, serialize it, and tell Superagent to pass it to the client.
We don't do this kind of thing frequently, so we haven't built any graceful tooling for it.
* I _think_ this is Superagent: https://visionmedia.github.io/superagent/https://visionmedia.... Somehow, we use it in a way that notifies the client of what HTTP requests the server is performing on its behalf; not sure if that's stock Superagent or if we added some magic to it.
There's no data caching across pages. On first page load the responses from data requests for that page are transferred to the browser and rehydrated. For a client-side transition to another page there are two options: Fetch the data from the server as a bundle (this just works... one of the cooler features of React Server, I think) or make the individual requests via xhr from the browser. Both have their place.
There's some more discussion of this here: https://react-server.io/docs/guides/client-transitions