The ECMAScript Ecosystem

Laurie - Feb 11 '20 - - Dev Community

JavaScript is a wonderful language. It's constantly evolving, adding new features and functionality. However, it can be a challenge to figure out whether or not you can use a particular piece of syntax. Depending on your project, there are various factors at play. So let's talk about it!

New Syntax

let thing = obj?.node?.thing ?? 2
Enter fullscreen mode Exit fullscreen mode

The example above uses two brand new pieces of JavaScript syntax. Optional chaining, denoted as ?., and nullish coalescing, ??. Suppose you wanted to use this line of code in your project. What would you need to do? What part of the tech stack even determines what is valid JavaScript?

ECMAScript

To answer the above questions, we have to start at the beginning. JavaScript is based on a standard for scripting languages called ECMAScript. The standard itself is constantly changing and adding new features. This process is controlled by a committee called TC39.

Proposals for additions can be made by any member of the JavaScript community. As they're evaluated for inclusion, they go through multiple stages. There are complexities to this, but in general, proposals pass through Stage 1, Stage 2, and Stage 3. Stage 3 proposals must have an implementation in Babel -- we'll get to this shortly.

The final stage is stage 4. That's where optional chaining and nullish coalescing are now. Proposals in this stage are considered adopted! They're part of a dynamic ECMAScript version referred to as ESNext. ESNext includes features that are set to be part of the next release. ECMAScript releases occur yearly and include all the Stage 4 proposals from the previous year. For example, ES2019 was released in June 2018.

However, a feature reaching Stage 4 doesn't necessarily mean you can use it yet. If you want to include bleeding-edge syntax you'll want to understand how the ECMAScript standard is adopted and supported.

Babel

Your best chance at being able to use a brand new Stage 4 proposal (or even an earlier stage if you want to provide feedback) is to include the Babel plugin in your project. Why Babel?

Babel is a transpiler for JavaScript. It allows you to write JavaScript using modern syntax and then compile that code into "older" JavaScript; so it can run in situations where that modern syntax is not yet supported.

Babel can be run on its own, but it's often bundled with tools like webpack. When you build your JavaScript project the output is still JavaScript. Though it's often significantly less readable than before, depending on what your build process looks like. We'll assume for the sake of this post that we're talking about a production build.

The next step is to run that built JavaScript somewhere. That somewhere is considered your target environment.

JavaScript is Everywhere

We often joke that JavaScript is everywhere, but it's kind of true. When creating a JavaScript project you don't always know where it's going to run. Instead, you focus on the minimum version of the target environment that you're going to support. But what is considered a target environment?

JavaScript runs in browsers. Browsers exist on desktop and mobile devices, so all of those are potential target environments. JavaScript can also run server-side when using node. Knowing your server-side target environment is more likely than having confidence all your users will use a specific browser version. However, your target environment influences what ECMAScript features you can use, whether it's server-side or client-side.

JavaScript Engines

JavaScript runs using a Just-In-Time compiler. It's an engine that compiles and interprets the code. As it turns out, all JavaScript engines are created to match the ECMAScript standard. The engine translates valid JavaScript (as defined by the standard) to valid machine code.

Because each engine is written to match the ECMAScript standard, the engine itself determines what syntax you can use in your project. And each target environment has its own engine! What browser is your user accessing your site on? What engine is in that browser? Does that engine support the syntax you're trying to use in your code?

Compatibility

So we know JavaScript engines are written to support the ECMAScript standard. And as a result, those engines are the ultimate arbitrator of whether a given piece of syntax works. But we also know the standard is constantly evolving. So how do you know whether the engine you're targeting has included the feature you're trying to use?

There are multiple projects across the web dedicated to keeping an updated compatibility table. These tables track available compilers/polyfills, browsers and node versions and match ECMAScript features to note whether they're supported.

There are also great sites like https://caniuse.com/

"Versions"

The columns of the compatibility table cluster various types of technologies together. Browsers (we'll lump mobile and desktop in together), compilers/polyfills and server/runtime JavaScript.

Browsers release updates periodically and attach version numbers. The compatibility table takes into account the most recent and popular stable releases and notes whether or not the internal JavaScript engine supports a particular ECMAScript standard (and the associated syntax). Mobile device browsers are also included.

The compilers/polyfills section includes a handful of different technologies. Note that the Babel and Typescript columns include core-js version numbers. This is referring to a library that provides JavaScript polyfills. While Babel is transpiling much of the existing syntax, there are some things that are just missing like new keywords or fat arrow notation. That's why the core-js version is noted.

Note that @babel/polyfill exists and uses core-js under the hood. However, it was deprecated in favor of using core-js directly.

The final set of columns in the table relate to server/runtime JavaScript. I'll focus on node here. Node includes a number of things that allows JavaScript to run server-side and one of those is a JavaScript engine. In this case, it uses the v8 engine. This is actually the same engine that the Chrome browser runs on. Node itself has versions. Each version is bundled with the v8 engine, and depending on what ECMAScript standard that v8 version is up to date with determines what syntax is valid JavaScript.

Supporting a JavaScript Application

Part of what is wonderful about JavaScript is that there are numerous ways to write it and see it in action right away. But as it turns out, production JavaScript involves a lot more under the hood.

It'd be incredibly challenging to write code using syntax that was compatible with the lowest common denominator target environment. If that was the threshold then we wouldn't be able to use optional chaining for many years until all browsers in use supported it. Or we'd limit our users to only the very latest phones and/or browser updates. As you might suspect, developers don't want to do that.

Production applications ask the compatibility question of the built JavaScript. Is the included syntax compatible with the engines inside our minimal target environments? That's why projects use transpilers like Babel. To create JavaScript that is compatible across older browsers. So that you can use optional chaining even if Internet Explorer doesn't support it yet, or ever.

You can develop amazing JavaScript projects without knowing a lot of this information. But if you're curious about how new features come to be, or want to find a way to support something on the bleeding edge in your project, it's nice to understand these details.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .