Real-World ES6 Examples in Meteor

Today the ES6 specification was finalized. JavaScript now officially has got new features but it will take some time until browsers adapt them. My last article ES6 in Meteor shows how to use ES6 today, compatible with most browsers and the server. But some people I have talked to said they “don’t have the time to get into ES6” or that it’s “next on the to-do list”. That’s why I wrote this article to give real-world examples of how ES6 can be used in Meteor applications.

Examples

Here are some common use-cases for ES6 features that currently require inconvenient work-arounds. The examples cover Arrow Functions, Const and Let, Destructuring, Spread and Rest operator, Enhanced Object Literals and Classes.

Arrow Functions

Arrows are a function shorthand using the => syntax […]. Unlike functions, arrows share the same lexical “this” as their surrounding code.
babeljs.io

Arrow functions are useful for template-level subscriptions in Meteor. The subscription in the following example should rerun every time the Session variable changes. To achieve this, the subscription has to be encapsulated within an autorun function.

What’s inconvenient about this is that we need the variable self to keep a reference to the context. We can avoid self by using an arrow function instead, because then the context doesn’t change. So this still refers to same context. Here’s the same code in ES6:

Const and Let

You may have noticed that var filter was changed to const filter as well. This solves one major problem var has. Every variable defined with var is scoped within the parent function, not the parent block like you would expect. With ES6, you can avoid var altogether. Simply replace the keyword with let.

const is also block-scoped. It is for single-assignment variables. This doesn’t mean the value of the variable never changes, it means the reference never changes. You can have const obj = {}; and later edit the object with obj.x = 5; You could also have an array and push onto it or pop from it. But you cannot assign a variable defined as const to a whole new thing (primitive value), because then the reference would change [mdn-primitive, mdn-const].

Parsing the versions file

Every Meteor application has got an internal file called .meteor/versions. It contains the version of each package the app uses. It looks something like this:

autopublish@1.0.3
autoupdate@1.2.1
base64@1.0.3
binary-heap@1.0.3
blaze@2.1.2

Assume the content of this file is already stored in an array. Each item contains one line of the input, e.g.:

var lines = ['autopublish@1.0.3', 'autoupdate@1.2.1', ..];

The goal is to get every package associated with its version. Here’s how the parser looks in ES5, using an object to store the package name as the key and the version as the value.

A temporary variable had to be created. This can be avoided by using destructuring. In ES6, the information can also be stored in a Map instead of an object.

This looks better. No more unnecessary temporary variable. But actually this can be expressed even shorter.

Here, the spread operator (three dots) is used to spread the array returned from line.split(‘@’) as arguments to versionsMap.set. This works only by chance, because the method Map.prototype.set conveniently accepts the arguments in the same order as line.split returns them. In the real app, I settled with the version using destructuring as it is simpler; i.e. easier to grasp for other developers reading my code.

Using ES6 the original 7 lines of code can be written with just 2 lines of code. But it’s not only about writing less. The code is also more explicit of what it wants to achieve by eliminating unnecessary parts (temporary variables).

Rest Operator

Let’s assume we want to build a template helper that sums up all arguments, e.g. {{sum 1 5 6}} would return 12. The solution in ES5 has to convert the array-like arguments into a real array by using the awkward Array.prototype.slice.call. Another downside is that arguments is magically available to you. That’s why it’s recommended to place a comment inside of the function definition.

The following example is actually a more common use case of the three dots, in which they are called a rest operator. They work as a replacement of the problematic keyword arguments. We can also use the function reduce of the array to sum up the values.

Once again 9 lines of ES5 can be expressed in 6 lines of ES6. And once again the code is simpler.

Enhanced Object Literals

This time it is actually about writing less, with Enhanced Object Literals. They offer a way to define properties whose values are functions with less overhead.

This also works great when defining Meteor.methods and Template.events.

Classes

Classes in ES6 are somewhat controversial. But one place where they could be used is when getting documents from the database and transforming them back into actual object instances.

Be careful here, as class Tweet equals the definition of var Tweet, so Tweet will only be available within that specific file. One workaround would be using Tweet = class Tweet { /* … */ }.

Closing thoughts

I hope this article gave you a sneak peek of what is possible with ES6 and motivates you to start using ES6 right now. Meteor Development Group has also started working on official support for Babel through packages. If you want to read on about why Babel matters, I recommend this article. There’s also an in-depth book by @rauschma called “Exploring ES6". It is free if you read it online.

Moving to ES6 will not break existing ES5 code, because great care was taken to make ES6 nearly identical with existing ES5 features. This means you can start adding ES6 features to your code step by step.

So, get into it!

Oh,

and ES6 is actually called ES2015. It’s just that not a lot of people use that name. But at least now you know. \_(ツ)_/¯


You can follow me on twitter: @dferber90
I tweet about Javascript, Meteor and new web technologies.