I’ve always ignored server-side rendering when worked on Virtual DOM libraries, but recently started to think how to improve SSR performance, so that it can compete with string-based template renderers.

The first idea that came to my mind was to use the same optimization techniques that were used to optimize client-side rendering. In real applications this optimization should provide a decent performance increase, but it wasn’t enough to get good results in benchmarks that were used in marketing articles by string-based template renderers.

The main bottleneck in this benchmarks is still raw render to string overhead and traditional approach doesn’t work very well, so I’ve chosen a slightly different approach to solve this problem.

Instead of focusing on micro-optimizations of existing renderToString() algorithms, we should completely hide all details about Virtual DOM data structures and algorithms behind some easy to use API that will be possible to reimplement efficiently for string rendering in Node.js environment.

By hiding all details it doesn’t mean that we should sacrifice any features that are essential to Virtual DOM libraries, like passing Virtual DOM nodes around, it just means that we should be able to change internal data structures.

Implementation

To try this new approach I’ve redesigned ivi API and implemented a new server-side renderer.

It has a blueprint optimization that were described in this article, with some modifications to reduce memory usage and cover more use cases. Also, it covers all basic stuff like escaping to protect from XSS, detects void elements, fixes rare edge cases like newline-eating tags, etc.

Benchmarks

To check how it will perform against string-based renderers, I’ve chosen benchmarks that were used by Marko library.

Also, in the article “Why is Marko Fast”, they are making a statement about performance of Virtual DOM libraries, and that they are having a huge advantage for server-side rendering compared to Virtual DOM libraries.

search-results

This benchmark has a large static html chunk, so Virtual DOM libraries will have a huge disadvantage because they are creating many nodes and then serializing them. Blueprint optimization can easily handle such situations.

ivi (0.8.0) x 6,365 ops/sec ±0.79% (93 runs sampled)

marko (4.4.16) x 3,543 ops/sec ±1.48% (85 runs sampled)

react (15.6.1) x 88 ops/sec ±2.67% (71 runs sampled)

color-picker

This benchmark generates a list of simple elements, and it is mostly dynamic, so it completely depends on how fast is raw render to string.

ivi (0.8.0) x 21,352 ops/sec ±0.74% (92 runs sampled)

marko (4.4.16) x 8,153 ops/sec ±0.99% (88 runs sampled)

react (15.6.1) x 560 ops/sec ±2.71% (79 runs sampled)

All benchmarks were running on Node v9.0.0-v8-canary. Benchmark source code is available at Github repository.

I hope that this results shows that Virtual DOM server-side rendering can be fast and it can easily compete with string-based renderers.