Category Archives: Javascript

Transforming our JavaScript code at build-time with Babel

A few months ago, we started using ES6 template strings to embed fragments of HTML and CSS in our Web SDK. Template strings allowed us to inline multi-line content and expression interpolation served all our templating needs. We used Babel of course, to transpile these template strings to regular strings in the build, since we want our code to run even on browsers that don’t support template strings.

Now the transpilation preserves all whitespace characters it encounters in the template string as-is which means all the newlines, tabs and extra spaces that were used to indent and format the HTML and CSS fragments for code readability, would show up in the output and unnecessarily bloat the shipped code. Since these whitespace characters were components of strings, even minification or any text processing couldn’t remove them (how were we to distinguish strings containing the fragments from the others). We needed a point in our build process where we could smartly detect template strings containing the fragments and strip them of unnecessary whitespace. Luckily we discovered babel-plugin-dedent and used that as a reference to write our own whitespace removal Babel plugin.

A Babel plugin is most often written for source code transformations e.g. converting the ES6 arrow functions to ES5 compatible syntax. However, there are other uses as well, such as static analysis of source code. Plugins only need to work on the transformations, Babel takes care of the hard parts – parsing your source code, constructing an abstract syntax tree (AST), traversing that AST, tracking all the transformations that plugins make on the AST and finally generating a source code out of the transformed AST for output.

A Babel plugin is simply a function returning an object of visitor methods. The names of these visitor methods indicate the type of AST nodes they want to process. While traversing the AST wherever Babel encounters a node of such a type, it calls this method passing it a path object.

Example of a basic Babel plugin (written as a CommonJS module)

module.exports = function (babel) {
  var t = babel.types;
 
  return {
    visitor: {
      BinaryExpression: function (path) {
        // *path* contains the visited node along with related nodes,
        // metadata and some utility methods
        console.log("Operator of binary expression is", path.node.operator);
      }
    }
  };
};

Coming back to our whitespace removal plugin, we had to tag our template strings containing HTML and CSS fragments in the source code. This was needed to easily identify template strings with insignificant whitespace (where extra whitespaces can be removed) later on in the build process. The name of the tag was chosen to be
nowhitespace

We wrote our plugin to visit TaggedTemplateExpression type nodes, use babel.types to check if the tag name was nowhitespace and perform the transformation i.e. remove extra whitespaces from the various parts of the template string (called quasis). We also had to remove the tag from the template string, so we simply replace the TaggedTemplateExpression node with the inner TemplateLiteral node. Plugins in babel-preset-es2015 then took care of converting TemplateLiteral nodes to a regular string.

Below’s a version of the plugin (whitespace removal code is simplified). You can see it in action at astexplorer.net.

var pattern = new RegExp("[\n\t ]+", "g");
 
function transfrom (quasis) {
  ["raw", "cooked"].forEach(function (type) {
    quasis.forEach(function (element) {
      element.value[type] = element.value[type].replace(pattern, " ");
    });
  });  
}
 
module.exports = function (babel) {
  var t = babel.types;
 
  return {
    visitor: {
      TaggedTemplateExpression: function (path) {
        let node = path.node;
 
        if (t.isIdentifier(node.tag, { name: "nowhitespace" })) {
          transfrom(node.quasi.quasis);
          return path.replaceWith(node.quasi);
        }
      }
    }
  };
};

We configured Babel to use our plugin in the build process. One can put the plugin module path in .babelrc. When Babel is used through its API, the plugin’s function can directly be passed in the plugins option

Since the first working iteration, we have generalized this plugin to do proper minification of the fragments using html-minifier and cssmin. Check out the plugin code on GitHub (note that it is still experimental).

Babel’s plugin ecosystem is growing day after day on npm. You’ll find many of them serve niche, custom use cases.

To aspiring plugin authors, we recommend reading up on the Babel Plugin Handbook by James Kyle. Also, you will find astexplorer.net quite handy in inspecting ASTs and trying out transformations.

Thanks for stopping by and happy transpiling.

'Coz sharing is caring

AngularJS vs Angular

Introduction

Probably, for most of front-end developers, Angular is a well known framework made for building web applications. If we want to use Angular in our project, we have to choose one of its versions – AngularJS or other. 
AngularJS – or as some may prefer: Angular 1 – was created in 2009. It brings us two?way data binding and lets us see data changes in JavaScript automatically shown on the UI. Furthermore, AngularJS has directives that let us create more separated and reusable code than ever before. Generally it allows us, programmers, to write applications in MVC or MVVM architecture (sometimes called MVW architecture (Model-View-Whatever) in simpler way. It made a step forward in testing front-end applications, because of its dependency injection mechanism which helps mock dependencies.

The beginning

I must say that I was really fascinated in Angular. Over time it has gained support from many developers. They’ve created a lot of useful packages that made coding even faster. More and more things were added to the core, so the Angular team decided to create a completely new framework. At first, the new framework was named Angular 2. It sometimes may cause understatements, because after time, beta version was renamed to Angular. Now, when people want to find some pieces of AngularJS code, they may find stuff connected with Angular 2 or higher. Higher, because Angular 4 was announced on December 2016. Creators purposely skipped number 3 to avoid a confusion due to the misalignment of the router package’s version, which was already distributed. Angular in 4th version is backward compatible with Angular 2.

Controllers vs components

So what’s the difference between AngularJS and Angular? First of all, Angular is based on TypeScript while AngularJS is based on JavaScript. TypeScript is a superset of ES6 and it’s backward compatible with ES5. Angular has also benefits of ES6 like: lambda operators, iterators or reflection’s mechanism. 
AngularJS uses terms of scope and controller. To scope a variable you can add many variables that will be visible in View as well as in Controller. AngularJS has also a concept of rootScope. Variables in rootScope are available on all throughout application. Angular does not have a concept of scope or controllers. Instead of them it uses a hierarchy of components as its main architectural concept. Component is a directive with a template. That is a similar approach as in ReactJS – another library used for building user interfaces.

Differences in template engine

AngularJS has many directives and every developer can also specify custom new directive. Angular also has standard directives, but they are used in a bit different way. For example: ng-model in AngularJS means that you want to create two-way binding. If you want to create one-way binding, you should use ng-bind. Angular occurs only ngModel, but if you would write it only in: “[ ]”, you’ll get one-way binding. If you want to create two-way binding you must write it in: “[( )]”. We have to write it this way because of the fact that “[ ]” is used to property binding and “( )” is used to event binding. In Angular, some directives have changed their names like ng-repeat to ngFor. When I’ve started working on projects with Angular 2 in beta version, I’ve been making common mistakes at the beginning liken trying to use ng-repeat or ngModel only in square brackets when I wanted two-way binding.

What else have changed?

Of course if Angular is newer version you can suspect that has some advantages over the old version. That’s right, Angular has many advantages. The first is modularity. Much core functionality was moved to different modules. That caused lighter and faster core, dynamic loading, asynchronous template compilation and added support for reactive programming. After beta version creators added really great thing: angular cli. With that package you can easily create scaffolding of your Angular project which will be all configured.

So AngularJS or Angular?

Wondering about version that will be the best for you? The newer version of Angular is a popular solution. Moreover, mostly it will be a better choice. Anyway, before you choose one of them to your new project, try to answer some questions: 
What libraries would you like to use? 
Are they compatible with Angular? 
What web browsers we want to support? (this one is really important)
If you choose only new browsers, then Angular is the best. It’s because it is a forward-looking library, but don’t forget about other browsers. For example: IE8 for which you should definitely use AngularJS from version 1.3 that supports IE8 and higher.

Summary

Angular is a great framework. It has many improvements in terms of AngularJS. It will become more and more popular and I think that it is well suited to small as also to bigger applications, so it is really worth learning and using.

'Coz sharing is caring