4

I've been learning through a course how to use babel in Javascript, I understood the idea that babel with the preset "env" transpiles later versions of ES into ES5. However I've come across a scenario where the array "includes" method is not changed at all by babel and doesn't work on IE11, to fix this I've read that there is a babel polyfill which can be used.

I've come across an answer which tried to explain this but I didn't follow it at all. Could someone simply explain why babel by default doesn't handle all ES transpilations and requires a polyfill.

If I understand correctly then a polyfill is something designed to fill a gap to make something work that isn't supported but I thought this is the job that babel is meant to be doing by default.

j obe
  • 1,759
  • 4
  • 15
  • 23

2 Answers2

4

A polyfill uses the older version of the language itself to implement the newer feature. For example, Babel supports ES6 array.includes by implementing the method in ES5 itself. Something like

Array.prototype.includes = function(val) { 
    return this.indexOf(val) >= 0;
}

On the other hand, babel's core library is a transpiler. This is responsible for converting features of newer versions of javascript to older versions that aren't possible via writing a polyfill in the older version. For example, it would be impossible to write a polyfill for converting ES5's let or const into var, or converting arrow functions into traditional functions. Operations like these need a transpiler to walk through the code and convert it.

Jake Browning
  • 218
  • 1
  • 9
  • 1
    Ok, I'm still not clear from your answer, surely a transpiler eventually has to use an older version of the language to implement the new feature as well, so same definition. Also why can't babel do this by default? why is a separate polyfill package needed? – j obe Aug 14 '22 at 20:41
  • 1
    A transpiler uses whatever language it's written in to traverse through the source code of the target file and spit out the transpiled version. I could write a javascript transpiler in C that walks through ES6 source code and simply replaces every instance of `const` or `let` with `var`. That's an example of a very simple transpiler. "why is a separate polyfill package needed?" -- Transpiling is very different to polyfilling, and babel is primarily a transpiler. I guess it was a design decision made by the Babel team to keep them separate. – Jake Browning Aug 14 '22 at 20:47
  • 1
    If includes is a new array method, why doesn't babel create that method by default so it can be used in older browsers, why is the babel polyfill needed? If babel transpiles const and let to var isn't the principle the same, taking things that aren't supported and creating supported version? – j obe Aug 14 '22 at 20:55
  • 1
    I guess your question is basically "why doesn't babel include its polyfills in its core package"?. Probably because polyfills slow down JS at runtime, and babel core is very minimal by design. You could then ask "why doesn't babel transpile `includes` instead of polyfilling"? Probably because polyfilling old features where possible speeds up transpile time. I imagine this is a balance of trade-offs considered by the Babel maintainers. If one happens across this thread they could give a more definite answer – Jake Browning Aug 14 '22 at 21:03
  • Thanks for your replies, I guess in this case the line between polyfill and transpile seems a bit blurred to me as it's an array method which they just leave as it is when for other things such as `const` they use older code to make the new syntax work – j obe Aug 14 '22 at 21:08
  • 2
    I understand why it's confusing that Babel would support some ES6 features by default but not others. I think in an ideal world Babel would support all of them out-the-box, but their decision to exclude the polyfills are at least partly because of the limitations I mentioned above. As for the line being blurred, Babel's polyfilling and transpiling have the same goal -- supporting newer JS -- but those two processes are totally different things. It might help to look more into the technical differences between them. – Jake Browning Aug 14 '22 at 21:17
  • Check my answer about why include needs to be polyfill, but to transpile. – Qiulang Feb 19 '23 at 02:52
0

To understand your problem you need to know the difference between transpiler and polyfill, for example, check here What is the difference between polyfill and transpiler? or https://javascript.info/polyfills, simply put, transpiler for new grammar, polyfill for new api.

Babel is a transpiler, whose initial name called 6to5 but that was in 2015. So your words babel with the preset "env" transpiles later versions of ES into ES5 are NOT correct. Babel will transpile your codes for the browsers in your browserslist setting. If you have IE 11 in your browserslist it may transpile the code into ES5 for IE only, but not for other browsers.

But Babel doesn't do polyfill itself, it delegates that to corejs.

Then comes the core question, which part of your codes babel will transpile and which part of your codes babel will let corejs do polyfill. Your second assessment that this is the job that babel is meant to be doing by default is not correct. Babel do that based on browserslist setting in @babel/preset-env. So if your setting do not include IE, or maybe just { "browserslist": "> 1%, not dead" } babel won't do any work for IE.

@babel/preset-env in babel 7 makes babel setting a lot easier. I have several projects started before babel 7, so I have the preset setting like following (with this setting babel will transpile & polyfill for IE 10/11),

        "presets": [
            [
                "env",
                {
                    "targets": {
                        "browsers": [
                            "last 5 Chrome versions",
                            "last 1 Firefox versions",
                            "last 2 Safari versions",
                            "ie 10-11",
                            "last 3 edge versions"
                        ]
                    }
                }
            ]
        ],

PS, for why String.includes belongs to polyfill but not transpiler, you can also check Compiling vs Polyfills with Babel (JavaScript) and Array.includes is the same.

Qiulang
  • 10,295
  • 11
  • 80
  • 129
  • "*But Babel doesn't do polyfill itself*" - whether it *delegates* that to some other library or not is irrelevant. Babel *does* add polyfills to the code when asked to transpile it to a different version of JS. – Bergi Feb 19 '23 at 03:06