Server-side Rendering Shootout with Marko, Preact, Rax, React and Vue
Last week Alibaba announced a React-like library called Rax. Rax is a more lightweight implementation of the React renderer and it’s “universal”. It can run in Node.js, in the browser, and on top of Weex (which is pretty cool).
One of the things that Rax is touting is its server rendering performance. It’s prominently featured in their README and it initially showed that they were rendering at about the 5 times the speed of React using
renderToString on the server. Note: This was not accurate as React was running in dev mode.
The impressive rendering speed was the topic of much discussion and Rax quickly hit 2k stars on their GitHub repo. Meanwhile, Vue was added to the benchmark and it was pointed out that the benchmark was not running in production mode (using
process.env.NODE_ENV = 'production' ) and that could skew results.
Luckily, Evan You made a PR to fix things. The new benchmark now showed Rax (and Vue) as just under twice as fast as React.
There’s a lesson here: make sure you’re following the instructions of a library for production builds before benchmarking!
Soon after, it was suggested that Preact be added to the benchmark and sobear (the original benchmark author) added it and continued to work on making the benchmark more fair and meaningful. Preact impressively outperformed the competition.
But others want to keep pushing the limits. Can we get faster?
I want to show you something.
WHAT!? This can’t be right. How is this possible? And what is Marko?
That data is correct. This graph was made from data gathered from the same benchmark above (after adding Marko).
Before going any further, I want to point out that there is one other PR by Sasha Aickin currently open that uses a minified build on the server which results in React’s ops/sec sitting just above Rax and under Vue.
But let’s talk Marko. Marko is a UI library that’s been in use at eBay for the past few years. Marko offers a very similar approach to building UI components:
When compiled for the browser, rendering builds a virtual DOM tree that can be diffed directly with the browser’s DOM (powered by morphdom)— similar to the approaches in these other libraries. But when running on the server, Marko forgoes a virtual DOM completely and writes directly to a string buffer (which also happens to support streaming for progressive HTML rendering).
HTTP can only send strings/bytes, so it makes sense to start there and skip the overhead of building up a virtual DOM representation first. There’s a reason string based templating languages are so much faster than our modern frameworks using a virtual DOM implementation.
Virtual DOM will never be the fastest on the server — you just can’t beat strings. But, as Marko shows, it is viable to use strings on the server and still get performant diffing on the client via a virtual DOM. I’m excited to see how the landscape evolves in the future.
If you’re interested in Marko 4.0, you can use our release candidate (currently
firstname.lastname@example.org) and while we’re updating the docs, you can check out our UI components playground. To get notified of our official release follow @MarkoDevTeam on twitter and star us on GitHub.
Update March 2017: Marko 4.0 is here 🚀 🎉