Blog
Learning material for professionals eager to explore the science behind building a successful online product

#ASKTHEINDUSTRY 13: Can Web Components be rendered server-side?

I feel you. Web Components have always been worrying me for they depend on JavaScript to kick in. If for whatever reason it fails to load or, even worse, it takes a lot of time to download and execute, nothing gets painted for ages.

A first take at the problem could be rendering skeletons, meaning using CSS to target a Web Component and draw placeholders that will then be replaced by the actual content, as soon as it arrives. This technique improves the perceived performance, however a couple of downsides come to mind:

  1. If the JS completely fails to load, the user gets nothing. Just meaningless shapes and boxes.
  2. SEO is probably killed (I guess?, not sure on this one)
  3. It’s very limited in aesthetics, unless you also add dummy markup.

There might be another solution. A couple of days ago, Server Side Rendering came up. As you may recall, it is a technique that allows the server to send down an initial render of the page, so to speed up the First Paint. Can we do the same with Web Components?

Indeed we can. However, there are some challenges involved:

  • First, you need a way to run your components’ definitions on the server. It’s not trivial, since global variables like document and HTMLElement are not available in Node.
  • You need to parse the HTML and recognize the Web Components
  • You need to bootstrap the components and let them render their content.
  • Finally, you can send the rendered HTML to the client.

Step 2 and 3 have been taken care of by this really promising library: server-components.

Step 1 is the missing part. I experimented a bit and here is what I came up with:

First we’re going to require server-components and one of its dependencies: domino.

// Require dependencies
var domino = require( 'domino' );
var components = require( "server-components" );

Then, we expose HTMLElement globally and rename components.registerElement into document.registerElement.

// Set up globals
global.HTMLElement = domino.impl.HTMLElement;
global.document = {
  registerElement: components.registerElement.bind( components )
};

We can now require the bundle containing our elements definitions

// Require elements
require( './public/bundle.js' );

Finally, we’ll set up an Express server and send the rendered HTML when requested

// Set up server
var app = express();
var home = fs.readFileSync( 'public/index.html' );
// Render page
app.get( '/', function( req, res ) {
  components.renderPage( home )
    .then( function( output ) {
      res.send( output );
    } );
} );

It surely is a very simple use case, but I think this might be the right path towards fast-loading Web Components based apps.

You can find the code on GitHub

I read each and every comment, and look forward to answer to your questions! This piece is part of the #ASKTHEINDUSTRY project, which is supposed to be about your questions :) Drop a comment if there is anything I can help you with!

Care to leave a comment? Drop down a line on the Twitters