Three paintings showing the growth of the hero from a baby (version 1.0) to an adult (version 3.0)

Versions of the Language, Transpilers, Bundlers

Why you can't write a language just once or why there are so many tools around JavaScript.

Time to read: 12 min

In Brief

JavaScript, like other living programming languages, evolves. Creators and developers improve them, eliminate incorrect or strange behavior, and release fresh versions.

The difference with JavaScript is that developers do not have complete control over which version of the browser the end user will have.

This means that developers have to take not only the current version of the language into account but also some versions before it; understand in what range of environments our application can be run; and how to "prepare" the application code for release.

How to Understand

Let's start with the difference between JavaScript and ECMAScript.

What is ECMAScript?

💡 ECMAScript (or ES) is a specification. That is, a set of rules and recommendations that must be followed by the language to be considered compatible with that specification.

💡 JavaScript (or JS) is a language that conforms to the ECMAScript specification.

The difference between them is that the ES documentation tells how to create a language that will conform to the "family" of similar ECMAScript languages. The documentation for JavaScript tells how to use this particular language (JavaScript).

So, What's the Point?

The thing is, JavaScript is not the only language that follows this specification. There is also ActionScript, TypeScript, and at one time there was CoffeeScript.

To avoid describing each language in detail separately, there is a specification. It describes what is common among these languages.

Since JavaScript follows the ES specification, new features are described in it. We need this to understand how to follow the development of the language and its updates.

Updates and Versions

Until 2015, ES was updated only a few times:

Versions Year Changes
1 1997 First edition
2 1998 Editorial corrections
3 1999 Added regular expressions and try-catch
4 Never released
5 2009 Added 'use strict', support for JSON, some other features

As can be seen from the table, it did not evolve particularly rapidly.

However, by 2010 it became clear that applications that used languages according to the ES specification would become more complex and larger. And JavaScript, in its prior form, did not fully satisfy developers.

Since 2015, the ES specification has been updated every year. This means that every year it introduces improvements, modifications, and new features that later make their way into JavaScript and are used in browsers.

A Dive into History 😃

ECMAScript, 3rd Edition. In the third edition, there were not many changes:

  • added regular expressions;
  • added try/catch;
  • improved string handling and formatting;
  • added in and instanceof.

However, despite this, ES3 became very popular and widespread (even today, some tools still allow compiling code to ES3). It became the basis for many libraries, and AJAX was born during its time.

Browsers quickly learned to work with it. It seemed that the development was rapid and successful. Many were waiting for the release of ES4, but something went wrong.

ECMAScript, 4th Edition. When work on ES4 began, developers had disagreements about the vision for the language. Some believed it was time to make JavaScript a language for large-scale development and add types, classes, interfaces, generators, iterators, and a bunch of other things from "big" programming.

Another group of developers opposed such changes. In 2003, the development of ES4 was halted, and in 2008 it was decided that the 4th version would not be released.

Funny fact: some features like iterators, generators, and classes found new life in ES2015+.

You can learn more about how and why this split happened and how things developed afterward in Douglas Crockford's talk The State and Future of JavaScript.

After the developers decided to abandon ES4, they focused on ES3.1, which would later become ES5.

ECMAScript 5

From 2009 to 2015, the ES5 specification was the freshest. Its main feature, in addition to new features, was strict mode.

Strict Mode

Strict mode 'use strict' was introduced because ES broke backward compatibility.

In ES5, some non-obvious aspects of the language were reviewed and fixed. However, as these fixes changed the behavior of existing code, it was not possible to simply raise the version and release fresh updates — existing code might break.

To determine how the browser should interpret the code (old ES3 or new ES5), strict mode was introduced.

Using strict mode by default is now considered good practice.

Features

Along with strict mode, ES5 introduced:

ECMAScript 2015

ES5 brought many good features and simplified working with AJAX thanks to JSON, but it was not perfect. Developers had many complaints about it.

One such complaint was about re-binding: having to explicitly specify function execution context.

Or the lack of classes (and amusingly, the class keyword was reserved, meaning it could not be used in code ¯\_(ツ)_/¯).

Or that function declarations were "hoisted" to the top of the scope.

Or hoisting variables, where they were created not where they were declared, but at the beginning of the module.

Features

ES2015 was revolutionary. First, because it was the first update in the last 6 years. Second, because it introduced:

What Changed

Besides adding a lot of features in the new version, the specification has been updated annually since 2015.

Partly for this reason, the name no longer contains a "version number" but consists of the year number — ES2015, ES2016, ES2018, and so on.

Annual updates solve several problems:

They prevent "stagnation" and technology monopolies. A situation where a language does not evolve threatens its degradation or even extinction — a more convenient competitor could appear. It is unlikely that JavaScript would die, but still.

Create a more engaged and responsive community. When there is an opportunity to influence the development of a language that developers use every day, they are more interested in participating in discussions and helping to develop it.

Forces browsers to update to comply with the latest introductions. A situation where there is one dominant browser under which everything is developed is very dangerous. Just recall IE5–6, from whose influence on the internet we were recovering for several years.

Allows adopting best practices from other languages. Although developers try not to turn JavaScript into other languages, nonetheless, successful expressive solutions tend to find their way in.

Makes batches of changes smaller. This makes it easier for developers to study changes and adapt to them.

ECMAScript 2016+

All subsequent versions of the specification are released every year. The number of changes in each release is smaller than in ES2015, but they are still quite useful. Here are some of them:

ES2016

  • array destructuring;
  • exponentiation using the ** operator;
  • includes() for arrays.

ES2017

ES2018

  • finally() for promises;
  • updates to regular expressions;
  • spread operator for objects.

ES2019

ES2020

  • BigInt type;
  • globalThis for convenient access to the global object;
  • ?? operator for nullish coalescing.

Versions and Browsers

— Okay, okay, which version works in the browser exactly?
— It depends on the browser ¯\_(ツ)_/¯

It is considered that ES5 — the one where 'use strict' was added — works reliably. Other versions are more complicated: some browsers have already learned to work with features from later specifications, some have not, and the set of supported features can vary from browser to browser.

However, nobody wants to use ES5 anymore: this version is less convenient than modern ones.

There arises a problem: you want to use the new syntax but also want the application to work in not only the most modern browsers but also in older ones.

Transpiling should solve this problem.

Transpilation

Transpilation is the process of "translating" code from one language to another. Programs that perform transpilation are called transpilers.

So, we have a problem: we want to write in ES2015+, but browsers understand ES5. Sounds like a job for transpilers going from ES2015 to ES5. But are there even programs that translate a program from one language to the same language?

Yes, there are. Moreover, they can themselves be written in the same language 😃

Babel

One such transpiler, Babel, is actually written in JavaScript.

It not only allows translating code from ES2015 to ES5 but also, for example, translating code from TypeScript to ES5. It also provides a sandbox where you can immediately see the translation results.

Babel’s architecture is plugin-based. This means that in Babel itself is just the core functionality of the "translator," while specific rules of what to translate and how are described in plugins.

Others

In addition to Babel, there are others: Traceur or ratel-core, which is written in Rust. However, Babel is currently one of the most popular JavaScript transpilers.

Build and Automation Tools

Using transpilers alone is not always convenient. They handle translating the language, but sometimes we want to perform some additional operations on the code to prepare it for release.

For example, we want to remove unused variables and functions or minify the code. For such cases, we need other tools — for automation and building.

Building a project is turning source files into a final product.

Among such tools, Gulp and Webpack are currently the most widespread.

Gulp

Gulp allows complete "hands-on" control of the process of turning source files into the final result.

Operations to be performed on the code are called tasks, and Gulp allows them to be organized in the required order to achieve the desired outcome. Therefore, it is also called a task manager.

Webpack

Webpack, unlike Gulp, is a bundler. The difference between a task manager and a bundler lies in their approach to tasks.

Task managers are automation tools that allow you to "streamline" tasks such as code minification.

Bundlers are more powerful combiners designed for developing and building applications. Bundlers have broader functionality but are also more complex to configure.

For example, Webpack not only can minify code itself but can also replace modules "on the fly" during development, remove unused functions, find duplicate dependencies, split the code into several files based on how it will be used, and more.

It has a higher entry threshold and a more complicated configuration. Additionally, there can be a lot of unnecessary elements if you have a simple routine task that needs automation.

When to Use What

If you need to automate routine tasks — Gulp or another task manager.

If you need more serious operations on the code, complex project setup, or a more comfortable Developer Experience — Webpack or another bundler.

Build Process

— Okay, suppose we have determined the tools and transpilers we want to use. What does the process look like next?

Typically, we have a set of source files written in a language we want to use (ActionScript, TypeScript, any other language conforming to the ES specification, etc.). We configure the build tools to use the source files to prepare us a program in the target language (for example, JavaScript according to the ES5 specification).

As a result:

  • input: source files + configuration;
  • output: program in the target language + necessary resources for it.