Forest header image

Symfony Finland
Random things on PHP, Symfony and web development

Rendering Riot.js tags in Twig using Node.js

Twig is everywhere. eZ Platform, Bolt, Drupal 8 and other popular projects have adopted it. At the same time Node.js and Web Components have risen to popularity. This article discusses merging the popular PHP templating engine Twig to Riot.js, a lightweight React-like user interface library using Node.js for server side rendering.

This Proof of Concept (POC) implementation of a Twig function to Render Riot.js components on the server side using a Yandex Maps Web Component I created before. It uses a bare bones PHP implementation with Twig, Symfony Process library and Node.js (for Riot.js).

tl;dr: Read the source on Github:

Riot.js and Server Side Rendering

Riot.js allows developers to build web components with friendly syntax. This encapsulates all resources to a single .tag file:

  • HTML Markup
  • Scoped CSS
  • JavaScript Logic

The easiest way to deploy these components is to compile them to JavaScript live on the runtime with a compiler on the browser. This works, but is not optimal for SEO or performance. Riot allows pre-rendering of the tags on the server side with Node.js.

This means the browser will receive valid markup and program code directly, without first needing to compile from intermediary formats. Similar to how preprocessing SASS to CSS on the server is superior to sending SASS to the browser and then rendering it to CSS on the client side. Native formats are native formats...

Read more about Riot.js and how it compares to other similar tools: Riot vs React & Polymer

Show me the code

The implementation launches new Node processes on each page load, and security, etc. have not been considered. I simply wanted to test if the concept is feasible at all. This implementation can be extended in the future to work with eZ Platform, Bolt, Drupal 8 or other CMSes using the Twig templating engine.

The target is to render Riot.js tags directly using Twig syntax in your templates. This is accomplished by adding a Twig Function:

This then maps to a class that extends the Twig_Extension class, who also sets the "is_safe" flag so rendered HTML output is not escaped by Twig:

Once these are available, our Twig templates can use the Twig function with parameters in our templates:

The actual merging of Riot.js and PHP happens in the Twig function riotRenderer. It makes two calls to node.js using the Symfony Process Component and passes the wanted parameters. The first call to app.js, a simple JavaScript app that renders our tag to HTML and returns the markup. The second call renders the ymap.tag to it's compiled JavaScript equivallent and writes a script tag referencing to it:

The end result is that our Twig calls render the Riot.js initial markup and script format right in the inital HTML markup:

The full code of the application, along with installation instructions is available on Github:

Why bridge Node.js rendering and Twig?

Web Components are an interesting prospect, but the adoption will take some time. Using polyfills such as Polymer or Riot.js aided with Server Side Rendering can help bridge the gap to the future. This will allows reuse of code between non-javascript server applications and the front end applications.

This is just an initial test done in a couple of hours, and I can already see plenty of improvement areas such as running Node as a rendering daemon, improved caching, better state management (the one in place is a kludge).

Reuse of JavaScript code from your PHP apps to Frontend, allowing Isomorphic JavaScript rendering blended with your standard Twig templating (this concept needs work on state) might seem like science fiction, but it'll be hum-drum everyday routine soon enough.

Or maybe we'll just send the initial JSON embedded to the HTML for a better solution. Who knows.

Written by Jani Tarvainen on Sunday September 13, 2015
Permalink - Tags: riot-js, php, symfony, twig, webcomponents

« eZ Platform: A CMS built with the Symfony Framework - Video: Symfony and Content Management »