Decoding JS (Part - 3): Polyfills and Transpilers

Decoding JS (Part - 3): Polyfills and Transpilers

Polyfills

A polyfill is a piece of code, in JavaScript that is used to provide some functionality in a browser, that does not natively support it. They are written to replicate an API that is available in some browsers, for those who don't have it or don't have it completely working.

Sometimes, they are also used to solve the issue of different browsers implementing the same feature in different ways and giving JavaScript a standard-compliant way of accessing the feature - this reason for poly-filling was prevalent in the old IE6 and Netscape days, where each browser used to implement different features differently.

Simply put, one can imagine a polyfill as a common paste which can be used to fill holes and cracks to smooth out any defects in a wall. In the UK there is a popular brand name for this paste which is called “Polyfilla”. The JavaScript Polyfill fills in for the same pieces of missing functionality across browsers. Interesting stuff!

Some Examples

Modern language features, not only include operators or syntactic constructs but also functions or methods. Consider the String.prototype.startsWith() method - It is used to determine if a string begins with the characters of a specified string, returning true or false as appropriate. Example -

// startsWith(searchString)
// startsWith(searchString, position)
const myString = 'I am learning polyfill';

console.log(myString.startsWith('I am'));
// Expected output: true
console.log(myString.startsWith('hello', 3));
// Expected output: false

Say there exists some super legacy browser, which doesn't support this method, and it would not perform as expected in this browser - to make up for it, we need to write a polyfill for this method. It would look something like this -

// If the method doesn't exist - 
if (!String.prototype.startsWith) {

 // Use a function that takes the same params, with position defaulting to 0 if not supplied and perform the same functionality as the original method, using the substr method.

 String.prototype.startsWith = function (searchString, position) {
    position = position || 0;
    return this.substr(position, searchString.length) === searchString;
  };
}

Let's take another example -
Math.trunc(n) is a function that “cuts off” the decimal part of a number, e.g Math.trunc(1.11) returns 1.

If this function is not supported in some browsers, this function may fail there.

A polyfill for it may look like this -

if (!Math.trunc) { // if no such function implement it
    Math.trunc = function(number) {
    // Use the Math.ceil and Math.floor methods supported in legacy browsers to implement it
    return number < 0 ? Math.ceil(number) : Math.floor(number);
  };
}

The Number.isNaN feature earlier had limited support in several browsers. A popular polyfill for it looks like -

// NaN !== NaN returns a true, and hence this logic and exception :) 
if (!Number.isNaN) {
    Number.isNaN = function isNaN(x) {
        return x !== x;
    };
}

Also, remember - Not all new features are fully polyfillable. Sometimes most of the behaviour can be polyfilled, but there are still small deviations. You should be really, really careful in implementing a polyfill yourself, make sure you are adhering to the specification as strictly as possible. Or better yet, use an already vetted set of polyfills that you can trust, such as those provided by ES5-Shim and ES6-Shim.

Packages like Core-js can help here.

Transpilers

A transpiler is software that would translate one piece of code to another.

It can read modern source code and rewrite it for legacy browser engines, using older syntactic constructs.

A popular example is the nullish coalescing operator (??), JavaScript before 2020 didn't have this operator, so older browser engines would fail to understand something like name = name ?? "No name" .

A transpiler would understand this and rewrite it to -

// before transpiling
name = name ?? "No name";

// after transpiling
name = (name !== undefined && name !== null) ? name : "No Name";

This code could be understood by older browsers.

Developers run the transpiler on their computers and deploy this code to the servers. Some popular transpilers include - Babel.

Build systems or bundlers such as webpack, provide a means to run a transpiler automatically on every code change. So, they could be integrated into development processes.

TL: DR;

In this article, we learned about ways to fill in missing syntactic or functional holes in JavaScript. Polyfills provide a way to fill in functional holes. So you have a way to fill in for that new shiny, blazing-fast feature in your oldie browsers.

However, syntactic gaps are hard to fill, since they are just unrecognizable symbols for older engines. Transpilers provide a way to fill in just that.