Having access to .cljc (clojure files that can be loaded by either CLJS or standard CLJ) helps tremendously here. This means the server-side happens in Clojure on the JVM, so all of the async worries just go away entirely.
I work on server-side rendering for DoneJS[1] and ours is probably the best solution out there today, in my biased opinion. We provide:
* Fully asynchronous rendering, so you don't have to awkwardly architect your app so that it can be rendered synchronously.
* Everything is fully progressively loaded. This means if you go to a particular page in your app, only that page's JavaScript and CSS will be downloaded in the client. Additionally the correct css link elements will be inserted.
* Caching XHR requests so that they are not repeated on the client (data used to render is included in the page).
What makes our solution unique is that you have to think about the server very little, if at all. If you need to make a request to services, just make it in your code. No additional wiring is needed and everything will be server rendered.
Much of this is possible because of Zones, a spec that is being worked on for standardization in TC39. We have a library that implements Zones[2] with SSR in mind. This is what makes XHR caching possible, for example. Check out this simple jQuery example app[3] (using jsdom on the server) to see how easy Zones make things.
Sorry to nitpick, but I don't think the React example is an analogous initiative. ;)
There is a huge gulf between "synchronously render a component in Node" and "asynchronously boot an app, marshall async data, render an async UI, and do it concurrently."
I touch on this a little bit in this talk[1], but the bulk of the work we've done over the last year is conventionalizing app boot and figuring out how to run multiple instances concurrently, cheaply.
Angular 2 is much more similar to what we're doing with FastBoot, and I'm excited to see where they go with that and crosspollinate ideas. (The work they're doing with Web Worker rendering is also very exciting.)
> conventionalizing app boot and figuring out how to run multiple instances concurrently
I am a software engineer who usually develops also for the client side and I follow and experiment with the JS trends because I find them interesting. However, I don't understand what you mean by these. Could you please be more specific? Thank you.
...and "conventionalizing app boot" just means making it a few simple commands to implement for any given Ember.js application (instead of each application needing its own bespoke solution).
Author of the simple React example here – Tom says there's a "huge gulf", but forgot to mention there's literally an example[1] of an asynchronous routing and data fetching app linked to in the first section of that page that's a logical progression of the first. (and others have pointed out much more complex examples you can achieve with React if you so wish)
The goal of those small examples is to illustrate that you don't need complex frameworks to achieve server-side rendering with data fetching and routing.
I have no doubt that FastBoot was a huge undertaking, and I think a large part of the reason for that is that it's aiming to fit into a very comprehensive existing framework, with pieces for routing, fetching data, "application instances", etc – there's a lot more work involved in that (for the framework author I mean, not the end user) than there is starting off with just a view library and adding your own pieces around that.
Honestly, it comes off pretty poorly for you to downplay the work of your competitors.
It might be easier to get server-side rendering working with React, but pretending that it's not the same thing is just condescending. There are dozens of examples out there showing how to render React pages on the server, including fetching the necessary data for that rendering.
The mechanisms you use might be different, but pretending they're not analogous is duplicitous at best. Both let you ship a fully rendered first view to the client.
If I wanted to downplay competitors, why would I acknowledge that Angular 2 is doing something similar? Angular has much larger marketshare at the moment than React.
It is fundamentally different, as I outlined above. That's not downplaying the work of React—they've done significant work in advancing the state of the art of DOM rendering that has hugely inspired the work of both Glimmer and Glimmer 2, as we have said frequently and publicly.
I have tremendous respect for the Angular and React teams and consider many contributors to both to be personal friends. I'm not downplaying their work—it just really, really, really is not the same thing.
I totally believe the work you've done here is significantly more polished and "conventionalized", that is awesome and congrats! Ember's tools are really slick.
That said, everything you're describing – "asynchronously boot an app, marshall async data, render an async UI, and do it concurrently" – is really, really, really the same thing we're (my team at least) doing with React. People aren't just using `renderToString` and calling it a day.
I think this argument is coming down to semantics.
Is there an 'analagous initiative' in React? No.
Can you end up with the same result in React? Yes.
There are people doing this in React, but each team needs to do it slightly differently because their app is setup differently. There are guides and examples on how to do it, but unless you setup your project exactly like the original author, you'll have to figure out portions of it on your own.
On top of that, you won't know if the modules that you are using will play well with the offline rendering.
The convention-driven approach IS the product... You make it sound like that is just a little bit of polish, maybe a page or two of documentation... But it took over a year of planning and architecture to make all of the changes. (There was a great demo of fastboot a year ago) Because of the planning and framework changes, however, every addon that follows the conventions will 'just work' with fastboot.
When Tom says "An App"... he means "Any App"... and that isn't something that I've seen being worked towards by the React community. It IS being done by other communities, as seen in this thread, so I think that it's valid for Tom to call this out as not being analogous.
> I'm not downplaying their work—it just really, really, really is not the same thing.
The methods might very well be different, but the result is the same.
Pretending that you can't do server-side rendering with React is not helpful and untrue. Just because they haven't put the same work into conventionalizing it does not mean that analogous initiatives don't exist for React.
There are plenty of guides and tutorials out there showing how to do server side rendering in React.
From one point of view (a user of the framework who doesn't care how the sausage gets made) they are analogous. But from the point of view of someone who developed the solution or who has to micro optimize the solution I believe tom dale is right that it is quite different.
You're right that tomdale came off condescending (as he often does when promoting/defending ember...ah well). But it certainly isn't "duplicitous at best"!
> There is a huge gulf between "synchronously render a component in Node" and "asynchronously boot an app, marshall async data, render an async UI, and do it concurrently."
I dont think it is fair to say it that way. React implementation doing all this (except async/streaming rendering) is man-week at worst in existing medium sized project, and man-day for a new project with no pre-existing code.
FastRender [1] for Meteor is a similar but not analogous project. Similar in that it improves initial render speed. Different in that it does so by delivering the data required to render the page along with the initial payload so things are still client-side rendered, not rendered for you on the server.
For what its worth, FastRender was first released in 2013. The just-released Meteor 1.3 now has ES2016 module support which should enable more improvements in this area.
i'm not sure i understand the distinction you're making.
you write a client-side app and can render on server via Node and hydrate/attach the js on client after the dumped html. you get "instant" initial render and "progressive enhancement" once the js executes.
My naive understanding is fastboot actually understands stuff like your client-side routing, and how an Ember app 'loads' and fetches data (from your API) so you don't have to recreate that stuff with duplicate code on the server-side like you would have to with the aforementioned React example, and I think, your library.
i think it heavily depends on how coupled your router is to your view and data/fetch layer. with domvm everything is decoupled, so wiring any of those modules up is pretty trivial.
a more fleshed-out demo would be valuable for a more realistic comparison. they mention the non-congruence between ajax vs node's fetch, but this is easy to shim so the same code works on both.
the main complexity is the view rendering and post-render hydration.
Having access to .cljc (clojure files that can be loaded by either CLJS or standard CLJ) helps tremendously here. This means the server-side happens in Clojure on the JVM, so all of the async worries just go away entirely.