-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
Revisit server-side API and isolate into subdir #3290
Comments
|
Ah, you're right. Man, now I really want to kill I'll update the OP. We can still have a |
It's not just Also, SSR still requires a |
You mean as a consumer of the router? Or are you talking about some work you did in the router itself? |
I mean in adding proper support for this in the router. #2965 was required to fully support this for async |
Hmm, I remember that code being a lot more painful to write when I first wrote it. Looking back at the diffs, it doesn't look as bad as I remembered. |
Gotcha. The ideal situation for a client-side app is to not do any async matching at all on the initial render, but that's a limitation of our current code splitting approach. In other words, the initial Also, webpack 2 makes all calls to Synchronous |
Sorry, tired – what I mean is, users can do arbitrary async things in |
Ya, you're right. Still, it's kind of annoying that people can't opt-in to a synchronous |
This also begs the question as to what on earth you're rendering while we do async work in |
The browser is rendering the initial server-sent HTML. No client-side React rendering will yet have run. It won't have any event handlers or whatever wired up, so mostly the page won't respond in any JS-enabled way (though if you click on a In other words, the same as what you get with SSR normally; it's just that you don't start loading the extra chunks until after you've finished parsing the entry chunk and running |
With some care, it's possible to shim the |
When using the router to render server-side, the HTML from the server is generated by the router. Either the server or the client should be responsible for the match, but not both. |
Like jimmy said, you either call match on the client to tickle the code The use case of code splitting and server rendering together is low
|
It's super important to a product I'm about to start work on next month. I need the slimmest possible entry bundle for fast load times and server side rendering for SEO purposes. Unfortunately, outside of going back to Router.run, React's lack of support for async rendering means you have to go outside of ReactDOM.render to make this happen. You need match (really "syncify") in order to wait for anything async. The good part is that it's optional, so you don't have to use it until you want to get into SSR and async routing behaviors. |
Without getting too deep into the weeds here, I think that's a matter of semantics – isomorphism requires both the client and the server to run an initial router match, and most likely if it's async on the server, the router will have to also support doing it in an async manner on the client (when using Can you clarify what the action item here is? It's not ideal to discourage users from using |
On second thought, there is something here – the client and server APIs are not the same. The client API expects a We've seen people get confused by using the wrong form of the match function on the client and ending up with markup mismatches. Maybe it'd be best to split these up. |
We need histories on the server because they know how to // server
const history = useNamedRoutes(createMemoryHistory)({ routes })
match({ history, location, routes })
// client
const history = useNamedRoutes(createBrowserHistory)({ routes })
<Router history={history}/> The only difference between the client and server API is where you pass the history. If we figured out some separation between the history and the path creator/active checker thing it becomes something like: // server
const pathThing = createNamedRoutesPathThing({ routes })
match({ pathThing, location, routes })
// client
const history = useNamedRoutes(createBrowserHistory)({ routes })
<Router history={history}/> The client doesn't change, but the server API is now even farther from the client API and router extensions, like use-named-routes, have to provide two APIs, before they only needed to provide one. In the case of code-splitting + server rendering, we either be okay with using match({ routes, history, window.location }, cb)
// becomes
tickle(routes, cb) No matter what you've got to deal the statefulness of the render lifecycle on the client and the one-shot-get-everything-we-need-to-render of the server (and, indirectly, the checksum match on the client w/ async route config behaviors). We tried to make it "the same" in both places with But here's what I really think:
https://twitter.com/sebmarkbage/status/720389596261953537
We should probably just keep doing what we're doing and wait to see what business @jordwalke and @sebmarkbage are cooking up. |
I agree that we can't change the guts of how things work. I think there's room for a small DX affordance, though.
These two versions of |
Err, I think I might have just said the same thing as @ryanflorence's |
I'm not sure I can 👍 it w/o being named |
Will everyone please stop reminding me of how code I wrote works? :) Thanks. I obviously overlooked the server-side use case when working on the If I could break down responsibilities we need on either side, it would probably look something like this: Stuff we need on the server:
Stuff we need on the client:
These responsibilities are different enough that I think it justifies us using a different API server-side than we use on the client, akin to how React itself uses |
Only brought it up because your example code in the OP doesn't account for any of that and other people read these issues. |
I brought this up on remix-run/history#231 (comment), but what do we think of making a Then use that for server-side rendering. I think it gets us most of what we want with "not having a history on the server" and making that API fully stateless, but doesn't require rethinking the history enhancer thing. |
I hope it is ok to continue the discussion (the part related to
@timdorr, I guess it is not the case, because |
There's no real difference between the two components in terms of API, though. The server-side and client-side |
Folded into #3611. |
I've seen a few people do weird things like try to use
match
on the client side. We should probably followreact-dom
's lead and isolate our server-side API into areact-router/server
directory in our build. This would make it obvious to people using it that it should only ever be used on the server and never on the client.Potential API could be:
This would also hopefully make it more clear to people that they shouldn't be using a memory history on the server.
The text was updated successfully, but these errors were encountered: