Skip to Content
Author's profile photo Serban Petrescu

Bringing JSX to UI5 controls

Summary

I’ve built a Babel plugin for transpiling JSX into plain JavaScript UI5 render manager calls. Creating custom controls is a lot easier using the plugin. I’ve used it already a little, and the development “experience” is pretty much similar for Angular 2 or ReactJS (when it comes to writing up HTML into components).

Background

React

A while ago, I have been playing around with React. To be honest, I liked the JSX-based components a lot more than UI5’s own XML views. Because I learned that JSX is not really React specific, an idea started growing in the back of my mind.

Materialize

In the same period, I developed a small prototype in UI5 for a customer showcase. We wanted one of the views to have a more “shiny” design, so we decided to include Materialize CSS to have material-design-like forms. I had to make some custom controls (Input, Select, etc.) and I realized how painful it is to build the renderer functions even for simple controls.

UI5Con

Two weeks ago I joined in the fun at the UI5Con and had the pleasure of seeing a lot of very nice presentations and sessions. Two of them caught my attention in particular:

  • “UI5 Evolution” by @peter.muessig where we saw that the control renderers will be written in handlebars.
  • “Plug in your feature into WebIDE” by @wouter.lemaire. Here I saw Wouter’s plugin for building up renderer functions out of plain HTML.

The need for having declarative control rendering became more and more obvious.

The idea

It should be evident by now: let’s try to use JSX for defining the render functions of controls. The very nice thing about this idea is that, with the right JSX transpilation / interpretation mechanism, the generated code is 100% compatible with the legacy / horribly old browsers.

Another very nice feature of JSX is that you can embed regular JavaScript expressions into it without needing a specialized syntax (like UI5’s expression binding; angular’s directives and so on).

Implementation

Ok, so one version of adding support for such a feature would be to create a dedicated babel plugin. Babel is a very popular JavaScript transpiler which allows fairly easy (but not-that-well-documented) extension via plugins.

After digging a little into babel’s own repository, I was able to implement such a plugin. The code is on GitHub here: ui5-jsx-rm.

Current Features

The features themselves are described in more detail on the GitHub Readme. In a nutshell, the following things currently work:

  • Using basic HTML tags.
  • Detecting the Render Manager dynamically (based on the object on which the render method is called).
  • Embedding JavaScript expressions.
  • Specifying classes and style dynamically (similar to the ngClass concept from Angular).
  • Writing UI5 specific constructs (control data, element data, accessibility state).
  • Spreading attributes (i.e. rendering the attributes of a tag based on the keys of a JS object).

Samples

A running sample which used the plugin can be found here: GitHub Pages. The source code is also part of the repository.

Further examples can be found in the unit tests. I made two categories of tests:

  • Snapshot tests (that test the generated source code itself).
  • Execution tests (that test the output of the execution of the generated source code).

A good example is the following:

Input:

function render(oRenderManager, bInclude) {
    oRenderManager.render(
        <div>{ bInclude && <span>I am here!</span> }</div>
    );
}

Output:

function render(oRenderManager, bInclude) {
    (function () {
        oRenderManager.write("<div ");
        oRenderManager.writeClasses();
        oRenderManager.write(">");
        oRenderManager.writeEscaped((bInclude && (function () {
            oRenderManager.write("<span ");
            oRenderManager.writeClasses();
            oRenderManager.write(">");
            oRenderManager.writeEscaped("I am here!");
            oRenderManager.write("</span>");
        })()) || "");
        oRenderManager.write("</div>");
    })();
}

Tooling

Right now you must be thinking: “how can someone actually use this when building an app?”. Well, clearly browsers will not know to run the JSX code without the transpilation (even in a dev environment).

So we need some tooling to be able to use it. There are two possibilities that come to my mind:

  • Use a build script (maybe with watch and live reload functionality). I used such a script in one of my open source repositories (Grunt-based). The Gruntfile is here (it can be of course slimmed down). The script just needs to be started while doing development (similar concept to the functionality offered by react and angular’s own CLIs).
  • Use a module loader which supports in-browser transpilation like SystemJS. Here I did not get time to investigate how this can be used (instead of UI5’s standard module loading system; might be impossible).

Such a plugin can clearly be a candidate of being included / usable through the “UI5 CLI” that the UI5 guys said will be available.

Outlook

Well, there are some methods of the Render Manager that can’t be yet called through the JSX (like the one for rendering icons). So one thing that I will most likely do in the future is to get the JSX to be able to replace fully the plain Render Manger calls.

Depending if the plugin gains some traction, some optimizations could be done related to the generated code (right now, some potentially unnecessary immediate functions are generated; this can be further improved).

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Fabio Pagoti
      Fabio Pagoti

      Great stuff Serban Petrescu!

      I recently started to study react and the idea of combining its best practices seems great!!

      Congratulations for the project! I will definitely take a look in order to see JSX outside React.

      Cheers!