146

I just started to use Babel to compile my ES6 javascript code into ES5. When I start to use Promises it looks like it's not working. The Babel website states support for promises via polyfills.

Without any luck, I tried to add:

require("babel/polyfill");

or

import * as p from "babel/polyfill";

With that I'll get the following error on my app bootstrapping:

Cannot find module 'babel/polyfill'

I searched for the module but it seems I'm missing some fundamental thing here. I also tried to add the old and good bluebird NPM but it looks like it's not working.

How to use the polyfills from Babel?

Liam
  • 27,717
  • 28
  • 128
  • 190
Shlomi
  • 3,622
  • 5
  • 23
  • 34

7 Answers7

69

This changed a bit in babel v6.

From the docs:

The polyfill will emulate a full ES6 environment. This polyfill is automatically loaded when using babel-node.

Installation:
$ npm install babel-polyfill

Usage in Node / Browserify / Webpack:
To include the polyfill you need to require it at the top of the entry point to your application.
require("babel-polyfill");

Usage in Browser:
Available from the dist/polyfill.js file within a babel-polyfill npm release. This needs to be included before all your compiled Babel code. You can either prepend it to your compiled code or include it in a <script> before it.

NOTE: Do not require this via browserify etc, use babel-polyfill.

vdclouis
  • 1,196
  • 9
  • 13
  • 6
    I am still not entirely sure on when the polyfill is needed. Why do ES6 modules just work with babel.js but `Array.protorype.findIndex()` does not work without the polyfill and babel will not raise an exception when it is transpiling? Is that the nature of a Polyfill™? – RemEmber Nov 17 '15 at 15:02
  • 5
    Basically Babel polyfill is just https://github.com/facebook/regenerator and https://github.com/zloirock/core-js combined. Check out those 2 repos to know if you actually need the polyfills. – vdclouis Nov 17 '15 at 16:33
  • 7
    I think that the reason one works and the other not is that Babel, when transpiling, targets a hypothetical JS engine with a certain level of support. Real browsers can end up supporting more or less than this hypothetical engine. In practice I think the hypothetical browser they target is somewhere at the IE10 level, so older browsers may have some issues. By putting the fixes for this in a separate polyfill they leave the decision whether you want to support such older browsers to you. A bit like jQuery with it's 1.0 branch that does, and 2.0 branch that does not support IE8. @RemEmber – Stijn de Witt Jan 14 '16 at 15:39
  • They updated the babel-polyfill code. They're not using facebook's regenerator repo anymore. Check it out: https://github.com/babel/babel/blob/master/packages/babel-polyfill/package.json – vdclouis Jan 15 '16 at 13:29
  • So in order to get `Array.protorype.findIndex()` to work I need to include babel-polyfill, which increases my resulting bundle by .08mb... seems wasteful :/ – dougmacklin May 05 '16 at 20:40
  • 2
    @dougmacklin if findIndex is the only polyfill you need, you can just include that one somewhere in your code. Check MDN for polyfills: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex – vdclouis May 06 '16 at 10:13
  • 1
    @vdclouis, how would you go about including that polyfill code via webpack so that it's available everywhere in the project? – dougmacklin May 06 '16 at 22:36
50

The Babel docs describe this pretty concisely:

Babel includes a polyfill that includes a custom regenerator runtime and core.js.

This will emulate a full ES6 environment. This polyfill is automatically loaded when using babel-node and babel/register.

Make sure you require it at the entry-point to your application, before anything else is called. If you're using a tool like webpack, that becomes pretty simple (you can tell webpack to include it in the bundle).

If you're using a tool like gulp-babel or babel-loader, you need to also install the babel package itself to use the polyfill.

Also note that for modules that affect the global scope (polyfills and the like), you can use a terse import to avoid having unused variables in your module:

import 'babel/polyfill';
ssube
  • 47,010
  • 7
  • 103
  • 140
  • 4
    Just to add a note, and I'm not 100% sure if this is entirely correct, but I attempted just using `import 'babel-core/polyfill'` without installing `babel` and it worked just fine. – Nathan Lutterman Aug 05 '15 at 05:30
  • 2
    _Zaemz_, I guess you already have installed babel, so `import 'babel-core/polifyll'` works. I tried it without installed `babel` and it didn't work for me. By the way: _ssube_ advise works. – WebBrother Aug 12 '15 at 14:53
  • 4
    When using webpack where do you include it? – theptrk Sep 10 '15 at 01:28
  • 2
    @theptrk Using webpack, you can simply import it as a module, since webpack allows importing npm packages. For Karma, you [set it up as a file](https://github.com/ssube/web-template/blob/master/gulpfile.js#L77) to be included before you tests. – ssube Sep 11 '15 at 17:19
  • 3
    Thanks, maybe I had a different version but I had to use babel-core instead => "import 'babel-core/polyfill'; – theptrk Sep 16 '15 at 06:30
  • 1
    see @vdclouis' answer below for important additional details, critically `npm install babel-polyfill` – XML Dec 08 '15 at 06:27
  • 2
    Should you include babel polyfill as an entry point in a webpack config? That is: `{ entry: ['babel-polyfill', './app/entry.js'] }` – corvid Jul 07 '16 at 13:41
29

For Babel version 7, if your are using @babel/preset-env, to include polyfill all you have to do is add a flag 'useBuiltIns' with the value of 'usage' in your babel configuration. There is no need to require or import polyfill at the entry point of your App.

With this flag specified, babel@7 will optimize and only include the polyfills you needs.

To use this flag, after installation:

npm install --save-dev  @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill

Simply add the flag:

useBuiltIns: "usage" 

to your babel configuration file called "babel.config.js" (also new to Babel@7), under the "@babel/env" section:

// file: babel.config.js

module.exports = () => {
   const presets = [
      [
         "@babel/env", 
         { 
             targets: { /* your targeted browser */ },
             useBuiltIns: "usage"  // <-----------------*** add this
         }
      ]
   ];

   return { presets };
};

Reference:


Update Aug 2019:

With the release of Babel 7.4.0 (March 19, 2019) @babel/polyfill is deprecated. Instead of installing @babe/polyfill, you will install core-js:

npm install --save core-js@3

A new entry corejs is added to your babel.config.js

// file: babel.config.js

module.exports = () => {
   const presets = [
      [
         "@babel/env", 
         { 
             targets: { /* your targeted browser */ },
             useBuiltIns: "usage",
             corejs: 3  // <----- specify version of corejs used
         }
      ]
   ];

   return { presets };
};

see example: https://github.com/ApolloTang/stackoverflow-eg--babel-v7.4.0-polyfill-w-core-v3

Reference:

apollo
  • 2,467
  • 1
  • 20
  • 29
  • 1
    Do you use this in production env ? any risk ? – Roy Jan 30 '19 at 08:51
  • `useBuiltIns: "usage"` doesn't work on my side. It just doesn't include any polyfils in bundle (example: I use generators and get an error "regeneratorRuntime is not defined"). Any ideas? – WebBrother Feb 19 '19 at 12:06
  • @WebBrother, works for me... see eg: https://github.com/ApolloTang/stackoverflow-eg--babel-polyfill – apollo Feb 20 '19 at 00:36
  • @Roy, I am actually in the process of migrating an enterprise project from babel@6 to babel@7 so that I can use @babel/preset-typescript. This is still a work in progress, but I am following instruction from babel official document (see reference links in my answer). So far everything seem to be working, but I have not sent my migration/upgrade work to QA yet, I will post here if any problem arise. – apollo Feb 20 '19 at 00:53
  • I still get this error `Opening developer tools in the browser... Cannot find module 'metro/src/lib/polyfills/require.js' Require stack:` – Siddharth May 04 '21 at 14:05
19

If your package.json looks something like the following:

  ...
  "devDependencies": {
    "babel": "^6.5.2",
    "babel-eslint": "^6.0.4",
    "babel-polyfill": "^6.8.0",
    "babel-preset-es2015": "^6.6.0",
    "babelify": "^7.3.0",
  ...

And you get the Cannot find module 'babel/polyfill' error message, then you probably just need to change your import statement FROM:

import "babel/polyfill";

TO:

import "babel-polyfill";

And make sure it comes before any other import statement (not necessarily at the entry point of your application).

Reference: https://babeljs.io/docs/usage/polyfill/

l3x
  • 30,760
  • 1
  • 55
  • 36
  • 3
    In this answer the babel-polyfill package is listed under 'devDependencies'. Doing this will result in babel-polyfill not included in deployment. You should not install babel-polyfill with -D flag but with -S flag so it is listed under 'dependencies', and therefore included in your deployment. – apollo Oct 26 '18 at 16:19
9

First off, the obvious answer that no one has provided, you need to install Babel into your application:

npm install babel --save

(or babel-core if you instead want to require('babel-core/polyfill')).

Aside from that, I have a grunt task to transpile my es6 and jsx as a build step (i.e. I don't want to use babel/register, which is why I am trying to use babel/polyfill directly in the first place), so I'd like to put more emphasis on this part of @ssube's answer:

Make sure you require it at the entry-point to your application, before anything else is called

I ran into some weird issue where I was trying to require babel/polyfill from some shared environment startup file and I got the error the user referenced - I think it might have had something to do with how babel orders imports versus requires but I'm unable to reproduce now. Anyway, moving import 'babel/polyfill' as the first line in both my client and server startup scripts fixed the problem.

Note that if you instead want to use require('babel/polyfill') I would make sure all your other module loader statements are also requires and not use imports - avoid mixing the two. In other words, if you have any import statements in your startup script, make import babel/polyfill the first line in your script rather than require('babel/polyfill').

tbodt
  • 16,609
  • 6
  • 58
  • 83
ChetPrickles
  • 820
  • 13
  • 8
8

babel-polyfill allows you to use the full set of ES6 features beyond syntax changes. This includes features such as new built-in objects like Promises and WeakMap, as well as new static methods like Array.from or Object.assign.

Without babel-polyfill, babel only allows you to use features like arrow functions, destructuring, default arguments, and other syntax-specific features introduced in ES6.

https://www.quora.com/What-does-babel-polyfill-do

https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423

zloctb
  • 10,592
  • 8
  • 70
  • 89
3

Like Babel says in the docs, for Babel > 7.4.0 the module @babel/polyfill is deprecated, so it's recommended to use directly core-js and regenerator-runtime libraries that before were included in @babel/polyfill.

So this worked for me:

npm install --save core-js@3.6.5
npm install regenerator-runtime

then add to the very top of your initial js file:

import 'core-js/stable';
import 'regenerator-runtime/runtime';
Fred K
  • 13,249
  • 14
  • 78
  • 103