-
Notifications
You must be signed in to change notification settings - Fork 243
Upgrade to React@16 (next) #479
Comments
Gonna. Change. Everything. |
I can ... not ... wait! 😸 |
I'm excited about the SSR with streaming! |
Going to try and blog my experience |
Looks like async server stuff isn't coming until later. Either way, cant wait. |
Awesome, this gonna be a major improvement. |
Yeah, @strues is right, looks like async work didn't land into the new server renderer. Also the server renderer has a few issues and sounds quite experimental at this stage so it may be worth sitting this out a bit in a branch.
|
One cool new feature of fiber is that it is gonna be less heavy handed on the checksum validation! Allowing partial mismatches which it would try to resolve in place rather than doing a full re-render. Sounds like an awesome win for SSR as sometimes it can be tediously difficult to keep the checksum matching in place. |
With regards to next, curious what you folks think about https://github.com/faceyspacey/react-universal-component or other such newer components coming up for universal rendering? Or is |
Hey @oyeanuj - I haven't looked at it in detail yet, but it sounds very promising. Here is my brief overview of the 3: react-loadable is the library of choice if you are doing client side only. Community behind it and James is a very pragmatic and respected developer. react-async-component was my temporary solution to being able to do SSR with RR4. It gets you most of the way whilst avoiding some of the crazy webpack/babel configs that I previously had to do. react-universal-component looks like @faceyspacey has nailed out most of the issues and complexity you have around webpack config in terms of SSR, and abstracts it all away. If it gives us sync rendering on the server with a fluid dev experience thats a win in my opinion and we should consider switching. And then a final note/feeling on all of it: Ideally I would like a more native implementation, i.e. async rendering in the server render of react, however if react-universal-component may be another respectable stepping stone whilst we wait for that to happen. |
When Fiber async comes out, apparently there still won't be support for it: https://twitter.com/dan_abramov/status/893267299909554176 However, even if there were, that doesn't solve the primary problem: discovering what chunks that were rendered. Why? Because on the client, the initial So you just lost somewhere between, i dunno, 500ms and 5 seconds, via a completely async strategy. That said, if the chunks were discovered in the async rendering on the server, and available for the async rendering on the client, they would already be loaded, parsed and evaluated at the same time as So in essence even if Fiber async massaged the process here, it only removes one (now irrelevant) challenge: "weakly" requiring dynamically imported modules so they don't end up in the parent bundle. It's irrelevant now because of babel-plugin-universal-import, but would certainly be welcome if that wasn't needed. It's just not the primary challenge, though an important one to making this all frictionless and therefore accessible for wide-spread use. Either way, it doesn't sound like 2017 will see React resolving promises in I'm very excited about the new streaming aspect. I wonder if async rendering on the server jives with the streaming aspect. On a side note, the streaming strategy has its own core challenge to code-splitting: since stylesheets come at the top of the page, you have to know what stylesheet chunks to render at the start of the stream, not as you discover them midway through the rendering. By that time it will be too late. The solution I and @swernerx have come up with is to move the discovery of what chunks will be rendered to the "route level." For example, if we know that route/path There's 2 ways we've thought of thus far to address that:
At the end of the day, there's a lot more that needs to be done in this space besides just serving chunks. Serving data fetched at the component-level and then rehydrating on the server is one. The next is an interface for the client to prefetch those component-level data dependencies. That's not something I'd expect to see React helping us with any time soon. And they don't need to--it can all be done in package-land. @ctrlplusb 's react-async-bootstrapper which does most of the work has helped me build such a prototype already. It was built on the 1.0 version of react-universal-component, so I primarily need to make it work for the 2.0, but also address future considerations such as prefetching before releasing the API. One final thing: @ctrlplusb what do you think about this: if during the initial/additional |
@faceyspacey I'd love to be able to try the prototype of this data-fetching library, if available!
@ctrlplusb Have you or anyone already integrated |
...Fiber aka asynchronous rendering in React, is just a scheduling algorithm. It just allows React to interrupt itself and do something else if it recognizes that a newer, more prioritized component update will replace part of the DOM tree in the future, then it can abort, not wasting any more resources there and start working on the newest change. It ought to give better-perceived perf when many things change over a period of time. So, I'm kinda lost about how Also, I've found that the simplest way to actually get this to work, is just to be honest about the fact that you need to know your routes up front (not necessarily statically, just up front). The way we have it set up is that we just walk our routes config. We then use I thought the idea of having an
I think that's right, hope it conveys the general idea. By the time we actually do render, client and server, the components will have been resolved from import directives to just components. And it works really well. |
I'm a big fan for doing things "route level" instead of "component level" as that solves a lot of problems with SSR. Basically if you have nested components doing additional async fetches, you are greatly increasing load time on the server. And if you only have one such component that you discover per route, you're better off formalizing the contract with Routes as I promote with redux-first-router. However, the challenge in doing what you're doing here without a synchronous fallback when available is that the time till interactive (TTI) is way longer on the client. You have to wait for all the following to sequentially happen:
If your components, or in your case routes, also had webpack's
So again, I love your routes setup. I really recommend that way to go when it comes to SSR. But in terms of code-splitting, you're losing precious time (basically seconds) before the app can be fully used. Here's the beginning of how I would do your approach (it would need the infrastructure from react-universal-component and other packages from the Universal suite such as const routes = [
{
path: "/",
componentAsync: asyncComponent()(() => import("./Actual"))
componentSyncId: require.resolveWeak("./Actual")
}
];
Promise.all(
matchRoutes(routes, "/").map(
route => (route.component = route.component.resolve())
)
).then(() => render(renderRoutes(routes))); elsewhere: const isServer = typeof window === 'undefined'
const render = ({ app, chunks } ) =>
isServer
? res.send(html(app, chunks)) // injects discovered chunk <scripts> into served HTML
: ReactDOM.render(app, document.getElementById('root'))
// pseudo-ish code:
componentRoute.prototype.resolve = function() {
if (this.hasChunk()) return Promise.resolve(this.componentSync())
else return this.componentAsync() // already a promise
}
componentRoute.prototype.hasChunk = function() {
return !!__webpack_modules__[this.componentSyncId]
}
componentRoute.prototype.componentSync = function() {
// very fast (1 tick),
// but still a promise (it could be written to be completely sync though)
return asyncComponent()(() => Promise.resolve(__webpack_require__(this.componentSyncId))
} In this case,
What's missing is that ..Or instead of making my system work with Routes, just rely on react-universal-component. See, the thing is this: since RUC is able to synchronously require on the server (and more importantly again on the client), it doesn't matter if you have nested imports--they will all resolve synchronously (and therefore quickly/instantly) in these 2 key places. You don't save any time [till interactive] by doing it at the route level. Essentially you get nothing for your money by moving universal/dynamic imports to the route level like you would with async data fetches, since the components render synchronously like any other component on initial load :) One final note: overall the idea is to go back to the way traditional web apps render. But with code-splitting now on the table. So traditional web apps have SSR inherently, and on the client, the scripts just expect to render synchronously one after the other. Things are synchronous, and faster as a result, everywhere essentially. When you introduce code-splitting, everything goes haywire. Via the proposed approach, the universe is back into alignment, just with code-splitting now integrated. No, additional potentially recursive promise resolution on the client. And most importantly: no multiple stages of scripts parsing/evaluating/rendering. |
@oyeanuj we'll chat on Reactlandia Chat about it. Ultimately the amount of time I have has gone to near zero since the release of these packages. It may take significant time to bring the old prototype back to life. I rather just get the new one out as soon as possible. Ultimately, I really need help with all this stuff to take it to the obvious next levels. There's a clear vision here. One that has been needed for a very long time in Reactlandia. |
Not necessarily. The route matching algorithm is a discovery algorithm and it can run before any of the asynchronous tasks finish, so it's should only matter what the latency is for the longest running async task. We've tried to be vigilant about making sure everything which adds latency is done in true parallel fashion. I'm still assuming that if you do choose to nest routes and you're still up front about it.
What's a good metric? I think we do pretty good, 50-500 ms depending on how we measure and what extensions run in the background. Lots of noise. Again, a bit of bookkeeping is needed for this but we actually name all our chunks explicitly. I did try to figure out a more magic way to make this work but it's just too much pain to go thourgh, it's brittle and difficult to understand.
So if you hit this route, we know that we should prefetch We don't embed the javascript together with the actual first request but that could be even faster, will have to test that out later. Anyway, my journey through this has led me to conclude that it's just easier to keep all this in a configuration up front. And rely on a recursive My biggest pain right now is the CSS file, it's just a huge chunk, haven't been able to do anything about that. |
my extract-css-chunks-webpack-plugin handles that. I highly suggest you read my articles. I've solved all these precise pain points in essentially the best possible way. https://www.medium.com/faceyspacey Are using Redux? I have 2 "beats" if you will: Universal Rendering and my Redux-First Router product. They work together: https://github.com/faceyspacey/redux-first-router In short, there is a connection between routing and universal code-splitting, but that is actually only "prefetching." Prefetching potential chunks to be used like Next.js. Otherwise there isn't, and u dont need to add this complexity to your routing mechanism. However these 2 product lines work great together, while really getting routing right for Redux. There should be no pain around this stuff if you're using these tools. If you're using React Router + Redux, don't. Redux-First Router is, as several of my users have said "the router now." Sorry if im comin off abrupt, Im just laying it out there--cuz all this would mean u have nothing custom to maintain anymore, and ur up to speed with the latest and greatest. Read the articles--u sound extremely versed in this stuff. I think if u read the articles on my medium publication, u'll find a glimmer of happiness in this space (which has been a horrible ugly place to live for so long). ...I got it though, ur embedding the chunks in the initial request. That was the primary hurdle. Great work! So either way, if u research what I've setup, u'll see i also made https://github.com/faceyspacey/babel-plugin-universal-import which imports both a js chunk and stylesheet. and the extract css chunks webpack plugin insures you generate multiple stylesheets. It's all a system. It's basically dubbed as "the frameworkless approach to the best features of Next.js." Which means there is some configuration/setup, but that's the price of forgoing the limitations of a framework. Anyway, all this makes everything work as u would expect with traditional web apps, just with code-splitting adding to the mix. I'm not saying it's the only way, but truth is there has been no general frameworkless way. I'm supporting all my users vigilantly. Feel free to come chat with me in "Reactlandia Chat" linked from the top of my repos. ..You could implement this stuff in your app and have it no longer be your responsibility as a custom ad-hoc setup. Hope you come to my camp :) and thanks @ctrlplusb for all the great recommendations! It's truly a rare thing to see a developer having made similar tools recommend the work of another. Ur a gem!! |
@faceyspacey What's makes you think I haven't? ;D But it's not that easy, we know our needs and we're adapting what's there to fit and with less abstraction. I really prefer not to hide these details or rely too much on external packages for core things. I've read through many of your articles and drawing inspiration from looking at your work. Sometimes though, it's not entirely obvious how we'd pull everything together and to be honest, we just don't have the luxury to fix everything right now. Next time around, we'll make a pass over CSS again and by that time I'm hoping the webpack support is there. |
@leidegre For the code you mentioned here: I was wondering if you plan to publish it anywhere? Or is there a gist/repo with rest of the |
@leidegre that u mentioned ur CSS is one big chunk. Yes u may be waiting a lot longer than hoped for full webpack support. Extract CSS chunks webpack plugin and the dual-import package can work with ur route based strategy. That way u can forgo the bigger component based change. Client side it should just work. Server side it sounds like u already have under control--but you will have to modify it to send stylesheets (which probably can just share the same name as the js chunk but with a different extension). Check out babel-plugin-dual-import. It's for use without React Universal Component. |
@oyeanuj oh yeah, I'm not done with this yet but everything is there you can take a look here https://github.com/tessin/tessin-react the function that does that work is called @faceyspacey I would love to pick your brain about this subject at some hypothetical future point in time... |
So what is the status on this? anything holding 16 back? Are we gonna see that that sweet EDIT: nevermind, just saw its on |
Yeah, it's in progress. 😉 |
Any update? |
@ctrlplusb is it work in progress: it doesn't work yet or is it work-in-progress: not everything there yet, but what is there works? Eager to move to React 16! |
One of my favourite starters, has everything a real in-production react app would need. Would love to have react 16 features. Please let us know, if we can help. :) |
Hmm, guys, React 16 is almost the same (externally), we moved a big project to it for one hour. What is a problem to upgrade? |
@alex-shamshurin not a big deal, but a lot of stuff was flakey. We have 16 working in a opinionated fork here: https://github.com/ueno-llc/starter-kit-universally |
I have been using the |
one thing which I just realized trying to upgrade both Styled-Components and React-Helmet (rather React-Helmet-Async) to streaming is that this file will need to be reworked to enable streaming of content within Right now, the whole app gets streamed, after collecting head and style tags whereas both React-Helmet-Async and Styled-Components now allow for streaming their respective output. React-Helmet-Async: https://github.com/staylor/react-helmet-async |
I'm noticing that the react middleware still uses |
Correct, and we already have PR #564 to solve that issue. |
And eventually replace react-async-component with native async behaviour (hopefully!)
facebook/react#10294
The text was updated successfully, but these errors were encountered: