21

I' ve come across this strange occurrence of:

ReferenceError: regeneratorRuntime is not defined

... which I've managed to reproduce in a very minimal setting (compared to similar SO questions on the same issue), and also noticed some weird behavior depending on whether scopes are used.

The following code works:

'use strict';

require('babel-polyfill');

{  // scope A (if you remove it you observe different behavior when .babelrc is present)

    function *simplestIterator() {
        yield 42;
    }

    for (let v of simplestIterator()) {
        console.log(v);
    }

}

Packages are:

$ npm ls --depth 0
simple-babel-serverside-node-only-archetype@1.0.0 /home/mperdikeas/regeneratorRuntimeNotDefined
├── babel-cli@6.7.5
├── babel-core@6.7.6
├── babel-polyfill@6.7.4
├── babel-preset-es2016@6.0.11
└── babel-runtime@6.6.1

Contents of .babelrc are:

$ cat .babelrc 
{
    "presets": ["es2016"]
}

However, when the scope is removed and the simplestIterator is placed on the global scope it fails with:

ReferenceError: regeneratorRuntime is not defined

Even more strangely, if the .babelrc file is removed/renamed the code succeeds whether the scope is present or not. BTW whether it is scope or an IIFE that encapsulates the generator makes no difference.

Minimal github repo demonstrating this behavior here.

To observe the behavior:

git clone https://github.com/mperdikeas/regeneratorRuntimeNotDefined.git
cd regeneratorRuntimeNotDefined/
npm install
npm run build && npm run start

The above will output 42 on the console. Now remove the scope and see what happens. Then rename .babelrc to see it working again (with or without scope).

My questions are:

  • why does the es2016 Babel preset trigger this error
  • why does putting the generator in a scope solves the problem?

update

Based on the accepted answer, and since this was code for a module I was writing I ended up doing:

require('babel-polyfill');
module.exports = require('./app.js');
Community
  • 1
  • 1
Marcus Junius Brutus
  • 26,087
  • 41
  • 189
  • 331

3 Answers3

48

Babel assumes that the polyfill will be loaded before anything else in your application, but you're using a function declaration, which is hoisted, meaning that it exists and is usable before require has been called.

In the case of generators, then need regeneratorRuntime which is provided by the polyfill, but the polyfill hasn't loaded when the regenerator is initialized.

The Babel team's recommendation is to make two files:

index.js

require('babel-polyfill');
require('./app');
loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
  • yeap; only changed the syntax a bit as this was inside a module (see update at the end of my question). – Marcus Junius Brutus Apr 15 '16 at 13:10
  • 1
    If you're making a published module, you shouldn't be using `babel-polyfill` at all, it is meant for top-level applications. Your library should either assume it is loaded by the application, or use `babel-plugin-transform-runtime` to inject explicit imports for ES6 library functionality. Libraries should not mutate global state by loading polyfills. – loganfsmyth Apr 15 '16 at 17:27
10

Also you could do the following with es2015 preset and transform-regenerator plugin:

.babelrc

{
  "presets": ["es2015"],
  'plugins': [
    'transform-regenerator'
  ]
}

Code

let regeneratorRuntime =  require("regenerator-runtime");
// You code with ES6 generators

P.S. Of course you should install babel-plugin-transform-regenerator npm package.

ThomasThiebaud
  • 11,331
  • 6
  • 54
  • 77
Mark Lavrynenko
  • 628
  • 9
  • 18
  • 6
    Why doesn't Babel do it by itself? We do I have to do the Babel's job? – Finesse Apr 19 '17 at 03:12
  • @Finesse because only you know the best way to include regenerator runtime to your program. For example using require function call or ES6 import statement. Or some other module implementation technique. – Mark Lavrynenko Apr 19 '17 at 09:13
  • 2
    A more general solution is `babel-plugin-transform-runtime` which includes the regenerator, but also polyfill and helpers, any of which can be turned on or off via config. In my case (babel 6+), no explicit `require` was needed. https://www.npmjs.com/package/babel-plugin-transform-runtime – Raman Sep 13 '17 at 18:36
  • 1
    @Finesse 's comment made me laugh :D :D – Praneet Nadkar Sep 06 '19 at 10:38
3

I know this has been answered but, unfortunately, they didn't fix the problem for me. what solved it was to import babel babel-polyfills inside the file

import "core-js/stable";
import "regenerator-runtime/runtime";

you can find it on the official babeljs documetation orat this article

Mike Araya
  • 155
  • 1
  • 11