What is the javascript compiler babel used for

David Else Follow TypeScript/JavaScript software developer | elsewebdevelopment.com

Why you dont need Babel

7 min read 2175

In 2020, frontend developers are still wasting a lot of time with excessive tooling. Babel is seen by some as a necessity, but I aim to show you that its not.

By the end of this article, you will know:

  • How to confirm which browsers actually need supporting on a case-by-case basis
  • How to lint with Visual Studio Code to avoid the need for Babel
  • Another software alternative to get the same job done faster

What is Babel and what problem does it solve?

Babel is a compiler that converts your modern JavaScript to run in older browsers. It can also perform other jobs such as converting JSX syntax, but it is not the only tool for that.

As browsers evolve, new APIs and ECMAScript features are added. Different browsers evolve at different speeds and prioritize different features. This leaves us with a tricky problem to solve: how can we support them all and still use modern features? Some will be incompatible.

A common solution is to write using the latest features and transpile down to older-style code the browser will understand. Transpiling describes a specialized type of compilation. It has different meanings in different contexts. In our case, there are also two separate parts to transpiling.

The difference between transpiling and polyfilling

Transpiling is the process of converting newer language syntax that old browsers cant understand into the old syntax they recognize.

Here is an example of transpiling the let statement:

// the new syntax `let` was added in ECMAScript 2015 aka ES6 let x = 11; // `let` transpiles to the old syntax `var` if your transpiler target was ES5 var x = 11;

Polyfilling is the process of adding the missing methods, properties, or APIs to the old browsers by supplying your own version of the missing native code.

It can be thought of as filling in the gaps. For example, here is a polyfill for isNaN:

// check if the method `isNaN` exists on the standard built-in `Number` object if (!Number.isNaN) { // if not we add our own version of the native method newer browsers provide Number.isNaN = function isNaN(x) { return x !== x; }; }

The best place to get polyfils is via core-js.

We made a custom demo for .
No really. Click here to check it out.

Click here to see the full demo with network requests

Transpiling and polyfilling are sometimes impossible and can add a lot of code bloat, its best to avoid them altogether if possible. That is why the first alternative were going to discuss is the best one.

Alternative No. 1: Dont support ancient browsers

If users would just upgrade their browsers, we could avoid the hassle of transpiling and they could enjoy the enhanced features and performance of the new browser. Unfortunately, things arent that simple.

The main culprit is large corporations having to support legacy software. The classic example is Internet Explorer, which has been a blight on web development from the beginning.

That said, things have improved a lot in recent years. Now, most browsers are evergreen, meaning theyre constantly updated. Microsoft now promotes its evergreen Edge browser, which, conveniently, uses the same V8 engine as Chrome, meaning one fewer engine to support.

To determine whether you have to support a particular browser, ask yourself the following questions.

1. Which browsers are your customers currently using?

If you already have a website or app that serves the same customer base, you can get this information from the analytics software. Below are some recent statistics from a UK-based sound engineering website Im managing. If it were a JavaScript application with the same customers demographic, I would assume they would be using the same browsers.

If you dont have analytic software installed, you wont know which browsers you need to support. Youll have to make an educated guess. If you have corporate customers, its far more likely youll need to support IE11 than if youre marketing to web-literate technology fans.

When you support a browser, you make a commitment. Do you really want to have additional tests on every release, additional build tooling to configure, and extra dependencies to babysit?

There must be a clear financial reason to go to through all this bother. Will losing those customers who cant access your site or app cost more than it would to support the browser?

2. Which modern browser features do you want to use?

Using modern language features and browser APIs makes writing code easier, faster, and more fun. It also makes your code more maintainable.

If youre happy writing ES5 and using XMLHttpRequest(), you definitely dont need Babel, but you might need some kind of therapy.

3. Which modern browser features do your customers browsers support?

This data is available on via Can I use, but its a waste of time to manually look it up. Now that you know the names of the browsers you want to support, looking up compatible features can be automated with the awesome Browserlist application (more on this in the next section).

Alternative No. 2: Use eslint-plugin-compat

You can avoid the entire transpiling process altogether and instead allow your code editor to alert you if youre using any features that are too modern for your customers browsers. This is the simplest option because it:

  • Eliminates any reliance on transpilers
  • Gives you back hands-on control over your production code

If theres a modern feature you cant live without, you can manually polyfill it. Otherwise, you can just use the older syntax when needed.

Create a test

Before we can break down the pros and cons, we need to confirm that our Babel alternatives can do the same basic job. Lets create a small test.

Below is the modern code we want our target environment to support once transpiled.

After the transportation, theres a console.assert for each function to verify its working as intended. In the case of eslint-plugin-compat well instead check that the incompatible code is being flagged in the linting.

test.js

// test nullish coalescing - return right side when left side null or undefined const x = null ?? "default string"; console.assert(x === "default string"); const y = 0 ?? 42; console.assert(y === 0); // test optional chaining - return undefined on non existent property or method const adventurer = { name: "Alice", cat: { name: "Dinah", }, }; const dogName = adventurer.dog?.name; console.assert(dogName === undefined); console.assert(adventurer.someNonExistentMethod?.() === undefined); // use browser API fetch, to check linting fetch("//jsonplaceholder.typicode.com/todos/1") .then((response) => response.json()) .then((json) => console.log(json));

Using the eslint env property with eslint-plugin-compat

We need a workaround for linting both language features and browser APIs together.

You can use eslint to check for the language syntax. To do that, change the env property down from es2020.

To check browser API compatibility, use eslint-plugin-compat. It uses the same Browserlist config used by Babel and other tools.

Full instruction can be found in the eslint-plugin-compat repo. Well use the browserlist defaults preset to use the default settings. Replace this with your own selection based on your analytics.

What is browserlist?

Browserlist automatically selects a list of browsers based on various criteria you give it.

Have a look at the list of browsers supported by the defaults setting for browserlist. defaults is a shortcut for:

  • > 0.5 percent (browser versions selected by global usage statistics)
  • Last two versions (of every not dead browser)
  • Firefox ESR
  • Not dead (browsers without official support or updates for 24 months)

Head to GitHub for the full list of queries available to choose your supported browsers.

Setting up eslint-plugin-compat for Visual Studio Code

Add the following packages to your project.

npm install --save-dev eslint eslint-plugin-compat

Add the following to package.json.

"browserslist": [ "defaults" ]

Create the following .eslintrc.json file or add these settings to your current one.

{ "extends": ["plugin:compat/recommended"], "env": { "browser": true, "es2020": true } }

Make sure you have the VS Code ESLint extensioninstalled

Now any browser API that is incompatible with the browserlist config in your package.json is shown as a linting error. You can separately control which version of ECMAScript you want to support using the env property in the .eslintrc.json file.

It would be nice if the eslint-plugin-compat automatically linted the language features as well, but this is currently an open issue.

With the IE 11 setting selected

our fetch() API is flagged.

Change the env property to es6.

Youll immediately see an error trying to use nullish coalescing, which was released as part of Es2020.

Alternative No. 3: Use other software to replace Babel

Before we look at alternatives, lets quickly review how to use Babel.

Using Babel to transpile and polyfill

First, create a mini-project directory and install the dependencies we need.

mkdir babel-test cd babel-test npm init -y mkdir src dist npm install --save-dev @babel/core @babel/cli @babel/preset-env npm install --save @babel/polyfill

Add the following to your package.json.

"browserslist": "defaults",

Write the test.js file into src, and then issue the following command.

npx babel src --out-dir dist [emailprotected]/env

Finally, run the file to check that the tests still work.

node dist/test.js

There should be no assertion errors, but it will say fetch is not defined since Node.js has no fetch() method. Here is the resulting transpiled code. Observe all the extra cruft and bloat added.

"use strict"; var _ref, _, _adventurer$dog, _adventurer$someNonEx; // test nullish coalescing - return right side when left side null or undefined var x = (_ref = null) !== null && _ref !== void 0 ? _ref : "default string"; console.assert(x === "default string"); var y = (_ = 0) !== null && _ !== void 0 ? _ : 42; console.assert(y === 0); // test optional chaining - return undefined on non existent property or method var adventurer = { name: "Alice", cat: { name: "Dinah", }, }; var dogName = (_adventurer$dog = adventurer.dog) === null || _adventurer$dog === void 0 ? void 0 : _adventurer$dog.name; console.assert(dogName === undefined); console.assert( ((_adventurer$someNonEx = adventurer.someNonExistentMethod) === null || _adventurer$someNonEx === void 0 ? void 0 : _adventurer$someNonEx.call(adventurer)) === undefined, ); // use browser API fetch, to check linting fetch("//jsonplaceholder.typicode.com/todos/1") .then(function (response) { return response.json(); }) .then(function (json) { return console.log(json); });

The pros and cons of using Babel

Pros:

  • This most basic setup was relatively straightforward
  • Babel has a large community for support and continued updates with 36.8k GitHub stars at the time of writing

Cons:

  • Slow compile time
  • A lot of dependencies, even if they are dev-dependencies (269 packages installed)
  • 39M of disk space used, as reported by du -sh
  • 5728 files installed, as reported by find . -type f | wc -l

Using swc to transpile and polyfill

swc is a new competitor to Babel. It is written in Rust and up to 20 times faster. This can be very important if you find yourself waiting a long time to build your project.

To set it up:

mkdir swc-test cd swc-test npm init -y mkdir src dist npm install --save-dev @swc/cli @swc/core browserslist

Add the following to your package.json.

"browserslist": "defaults",

Write the .swcrc config file into the project root.

{ "env": { "coreJs": 3 }, "jsc": { "parser": { "syntax": "ecmascript" } } }

Write your test file into src, then issue the following command to transpile.

npx swc src -d dist

Run the resulting file to check that the tests still work.

node dist/test.js

The resulting swc-transpiled file looks like this:

var ref, ref1; var ref2; // test nullish coalescing - return right side when left side null or undefined var x = (ref2 = null) !== null && ref2 !== void 0 ? ref2 : "default string"; console.assert(x === "default string"); var ref3; var y = (ref3 = 0) !== null && ref3 !== void 0 ? ref3 : 42; console.assert(y === 0); // test optional chaining - return undefined on non existent property or method var adventurer = { name: "Alice", cat: { name: "Dinah", }, }; var dogName = (ref = adventurer.dog) === null || ref === void 0 ? void 0 : ref.name; console.assert(dogName === undefined); console.assert( ((ref1 = adventurer.someNonExistentMethod) === null || ref1 === void 0 ? void 0 : ref1.call(ref1)) === undefined, ); // use browser API fetch, to check linting fetch("//jsonplaceholder.typicode.com/todos/1") .then(function (response) { return response.json(); }) .then(function (json) { return console.log(json); });

The pros and cons of using swc

Pros:

  • swc is much faster
  • Far fewer dependencies (43 packages installed)

Cons:

  • Not all Babel features are currently supported
  • Smaller user base and number of regular contributors

Other alternatives: Google Closure Compiler and TypeScript

I did not include Google Closure Compiler as an option because its notoriously complicated to use. That said, it can do a good job of transpiling and polyfilling. If you have some spare time on your hands, I recommend you check it out especially if you value small file sizes since its built-in minification is demonstrably superior.

You can also use TypeScript to transpile and core-js to manually polyfill, but this is a clumsy solution that could easily create more problems than it solves.

Conclusion

You dont automatically need to support old browsers. Its important to first look at your analytics data to see which browsers your customers are actually using.

If necessary, you can use linting to ensure backward compatibility. This will save you the hassle of creating a special build step and relying on transpilation.

If you do opt for automatic translating, then SWC is much faster than Babel and contains far fewer dependencies. There is also the option to use Google Closure Compiler or TypeScript, but these will require a bit more work to configure.

LogRocket: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

Try it for free.

Share this:

  • Twitter
  • Reddit
  • LinkedIn
  • Facebook
David Else Follow TypeScript/JavaScript software developer | elsewebdevelopment.com
  • Uncategorized
  • #babel
« Receiving emails with Bref PHP and SendGrid
The latest features in Next.js »

Video

Postingan terbaru

LIHAT SEMUA