Babel: Babel "babel-plugin-transform-runtime" transpiled file throws "regeneratorRuntime is not defined" error (T6676)

Created on 22 Nov 2015  Â·  34Comments  Â·  Source: babel/babel

Issue originally made by @d6u

Bug information

  • Babel version: 6.2.1
  • Node version: 0.10.40
  • npm version: 2.14.12

    Options

package.json

  "dependencies": {
    "babel-core": "^6.2.1",
    "babel-plugin-transform-runtime": "^6.1.18",
    "babel-preset-es2015": "^6.1.18",
    "babel-runtime": "6.0.8"
  },
  "devDependencies": {
    "babel-cli": "^6.2.0"
  }

.babelrc

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

Terminal

$ babel index.es6 > index.js
$ node index.js

/Users/daiwei/dev/temp/babel6/index.js:57
      throw _iteratorError;
            ^
ReferenceError: regeneratorRuntime is not defined
    at iter (/Users/daiwei/dev/temp/babel6/index.js:16:10)
    at Object.<anonymous> (/Users/daiwei/dev/temp/babel6/index.js:42:51)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:935:3

Input code

index.es6

function *iter() {
  yield 1;
  yield 2;
  yield 3;
}

for (let n of iter()) {
  console.log(n);
}

Description

When transpiling es2015 scripts into es5, and run in node 0.10. regeneratorRuntime is not defined in transpiled es2015 file. The first few lines of the es5 file looks like:

"use strict";

var _getIterator2 = require("babel-runtime/core-js/get-iterator");

var _getIterator3 = _interopRequireDefault(_getIterator2);

var _regenerator = require("babel-runtime/regenerator");

var _regenerator2 = _interopRequireDefault(_regenerator);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var _marked = [iter].map(_regenerator2.default.mark);

function iter() {
  return regeneratorRuntime.wrap(function iter$(_context) {
    while (1) switch (_context.prev = _context.next) {
      case 0:
        _context.next = 2;
        return 1;
....
....

Where regeneratorRuntime was never defined. Requiring babel-polyfill will solve the problem, but requiring babel-ployfill is not necessary in Babel 5. In Babel 5 with --optional runtime, the output es5 file top looks like:

"use strict";

var _regeneratorRuntime = require("babel-runtime/regenerator")["default"];

var _getIterator = require("babel-runtime/core-js/get-iterator")["default"];

var marked0$0 = [iter].map(_regeneratorRuntime.mark);
function iter() {
  return _regeneratorRuntime.wrap(function iter$(context$1$0) {
    while (1) switch (context$1$0.prev = context$1$0.next) {
      case 0:
        context$1$0.next = 2;
        return 1;

You can see clearly _regeneratorRuntime is defined here.

outdated

Most helpful comment

Comment originally made by @tlivings

Another workaround is to add the following to the es6 file using it:

var regeneratorRuntime = require('babel-regenerator-runtime’);

All 34 comments

Comment originally made by @d6u

FYI, I intended to lock "babel-runtime" to "6.0.8" in package.json since 6.2.0 to 6.0.12 all have other bugs that's not related to this issue.

Comment originally made by @iwege

Same error here , add babel-polyfill doesn't resolve it, because nwjs has global and the script try to find regeneratorRuntime on window.

Comment originally made by @loganfsmyth

This looks to be because the regenerator Function visitor is an exit handler instead of an enter, so the body is never traversed for regeneratorRuntime.

Comment originally made by @UltCombo

Is there any wrokaround or experimental branch that fixes this?
babel-plugin-transform-runtime breaks my build if I use any generator/async functions, so I'm really stuck here.

Comment originally made by @UltCombo

Looks like there are two issues here:

  1. If the code contains generator functions and nothing else that the babel-plugin-transform-runtime would transform, then the generated code will contain:
var _regenerator = require('babel-runtime/regenerator');

var _regenerator2 = _interopRequireDefault(_regenerator);

But regeneratorRuntime is not defined. This can be worked around by adding var regeneratorRuntime = _regenerator2.default; right after the _regenerator2 definition in the generated code.

  1. If the code contains generator functions as well as static methods that are aliased to core-js (e.g. Object.assign), then the generated code will contain import _regeneratorRuntime from 'babel-runtime/regenerator';, which is not even transformed with the module formatter that I'm using (CommonJS, as part of the ES2015 preset).

Comment originally made by @tlivings

Another workaround is to add the following to the es6 file using it:

var regeneratorRuntime = require('babel-regenerator-runtime’);

Comment originally made by @apendua

Is there any good reason not to make the plugins run one after another? If transform-runtime were the last one to run, there should be no problem at all. To me this issue indicates some architectural inconsistency which suggests that we my expect more problems of this type in the future.

Comment originally made by @apendua

Turns out, the easiest way to workaround this is to run babel twice, using --plugins transform-runtime only in the second run.

Comment originally made by @TrejGun

then the generated code will contain import _regeneratorRuntime from 'babel-runtime/regenerator';, which is not even transformed with the module formatter that I'm using (CommonJS, as part of the ES2015 preset).

I have same problem :(

Comment originally made by Simon Selg (simon_selg)

Same here. using the transform-runtime plugins breaks the code, when generators are used.

But only under certain conditions, for example if the generator includes an "Array.find" or an for of loop. Would really appreciate a fix!

Comment originally made by @silkentrance

I think the problem lies in https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-regenerator/src/util.js#L15 which uses the hard coded regeneratorRuntime instead of the correct value _regenerator2.default.

So I tried replacing regeneratorRuntime with the correct value. Turns out that the value of regeneratorRuntime is used to detect whether or not babel-runtime/regenerator must be required in the transpiled code.

So, after replacing it, babel-runtime/regenerator was never required, again leading to runtime errors since _regenerator2 will never be defined.

Perhaps this can help in tracking down and fixing this bugger?

BTW, the input code here is something similar to this

function *gen()
{
    for (const item of [1,2,3,4])
    {
         yield item;
    }
}

I think that the problem lies in the code that will generate and transform the require() statements...

Doing a quick search on the existing code, it seems that babel-plugin=transform-runtime might be the culprit here, along with state.opts.regenerator !== false evaluating to false?

It seems that it might have something to do with first marking and then wrapping the transpiled code. In a different source file I have a class with a generator instance method. This will be transpiled correctly, whereas the above input code will not, which is just a simple generator function in one of my test cases. The first will have the mark/wrap sequence and the second will only include the wrap for the transpiled generator.

It actually seems to be a two phase process, with first babel-plugin-transform-regenerator first introducing regeneratorRuntime and then some second phase, which I am currently unaware of, that will then replace that by the actual import + the proper call statement.

Comment originally made by @silkentrance

Here is some more input code and the generated output code where code generation fails

function *tgen() {
    yield 1;
}


class TGen
{
    *tgen() {
        yield 1;
    }
}


function outer() {

    return function *tgen() {
        yield 1;
    };
}


const outer2 = function () {

    return (function () {

        return function *tgen() {
            yield 1;
        };
    })();
}


describe('test',
function () {

    function *tgen() {
        yield 1;
    }
});

Generated output

Global named function

function tgen() {
    return regeneratorRuntime.wrap(function tgen$(_context) {
        while (1) switch (_context.prev = _context.next) {
            case 0:
                _context.next = 2;
                return 1;

            case 2:
            case 'end':
                return _context.stop();
        }
    }, _marked[0], this);
}

Anonymous function passed as the test case or suite in a describe(), or it() mocha call:

describe('test', function () {
    var _marked2 = [tgen].map(_regenerator2.default.mark);

    function tgen() {
        return regeneratorRuntime.wrap(function tgen$(_context5) {
            while (1) switch (_context5.prev = _context5.next) {
                case 0:
                    _context5.next = 2;
                    return 1;

                case 2:
                case 'end':
                    return _context5.stop();
            }
        }, _marked2[0], this);
    }
});

Turns out that in all cases where code generation fails, the outer scope was either global or an anonymous function.

Oddly enough, in the test case where an anonymous function is called as part of the return statement which in turn then returns the generator function *tgen, everything works as expected.

Comment originally made by @silkentrance

The following "analysis" concentrates on babel-plugin-transform-runtime/lib/index

In addition, and for the very first test case which is also considered to be the input code for the following examples

function *tgen() {
    yield 1;
}

the following will be generated

var _marked = [tgen].map(_regenerator2.default.mark);

which is correct.

It seems that traversal is incomplete and that the generated return statement will never be processed, i.e.

function tgen() {
    return regeneratorRuntime.wrap(function tgen$(_context) {
        while (1) switch (_context.prev = _context.next) {
            case 0:
                _context.next = 2;
                return 1;

            case 2:
            case 'end':
                return _context.stop();
        }
    }, _marked[0], this);
}

And in fact, when I place some console.log() statements in babel-plugin-transform-runtime/lib/index near

41 console.log('ReferencedIdentifier');
 42 console.log(node);
 43 
 44         if ((node.name === "regeneratorRuntime" || node.name === "_regeneratorRuntime") && state.opts.regenerator !== false) {
 45           path.replaceWith(state.get("regeneratorIdentifier"));
 46           return;
 47         }

it shows that only the first instance of the regeneratorRuntime referenced identifier gets processed.

So given above input code, the following will be logged

tgen
ReferencedIdentifier
regeneratorRuntime
ReferencedIdentifier
_regeneratorRuntime
ReferencedIdentifier
obj
ReferencedIdentifier
obj
ReferencedIdentifier
obj
ReferencedIdentifier
obj
ReferencedIdentifier
require
ReferencedIdentifier
_interopRequireDefault
ReferencedIdentifier
_regenerator

As you can see, regeneratorRuntime gets mentioned once for the first occurrence in the interim representation of the AST, namely

var _marked = [tgen].map(_regenerator2.default.mark);

This becomes more clear when outcommenting

 44         if ((node.name === "regeneratorRuntime" || node.name === "_regeneratorRuntime") && state.opts.regenerator !== false) {
 45  //     path.replaceWith(state.get("regeneratorIdentifier"));
 46           return;
 47         }

Then, the generated code will be

var _marked = [tgen].map(regeneratorRuntime.mark);

This leads me to the conclusion that the ReferencedIdentifier in the generated code for the *tgen() function is never processed and that recursive traversal of the AST does not work at this point.

Comment originally made by @silkentrance

@loganfsmyth please have a look as no one is assigned

Comment originally made by @silkentrance

A work around for this problem, until it gets fixed, is to have a factory for generators in for example mocha test cases

function genfactory()
{
    return function *gen()
    {
        yield 1;
    };
}

or, if you need to export a generator, use this in addition to the above

export const genfun = genfactory();

Comment originally made by Bradley Farias (bradley.farias)

@loganfsmyth if this has been reverted can we reopen?

Comment originally made by @rybesh

Please re-open this bug as the commit that resolved it was reverted.

Comment originally made by @jasisk

[[ https://phabricator.babeljs.io/diffusion/BC/history/master/packages/babel-plugin-transform-regenerator/src/visit.js | Not actually reverted ]], just a stale branch.

Comment originally made by @silkentrance

The patch works fine for me. I just applied it manually and my test cases now compile and run without any complaints.

Comment originally made by @hzoo

Sorry ^, what happened was I was about to revert it (and I did in a branch) since everyone was busy. What happened was a was testing locally and realized the node_modules file was different from source so I republished and did not have to revert it. https://github.com/babel/babel/releases/tag/v6.4.4

Comment originally made by @RobinQu

The newest babel package found on npm is 6.3.26 not 6.4.4.
When will this patch be published?

Comment originally made by @hzoo

@RobinQu - like I mentioned above the release is 6.4.4 - if you go to the link it says

  • babel-plugin-transform-regenerator: Publishing issue (T2892).

The release is for babel-plugin-transform-regenerator not babel/babel-core since that package wasn't changed (so we don't need to publish a new version).

Comment originally made by @mtraynham

I'm still seeing this issue on 6.4.4.

The only way I've found to resolve the error, is at the top of the module that uses a generator function:

import 'babel-regenerator-runtime';

This adds about 24 KB to my webpack bundle (from 57 KB to 81 KB), but resolves the problem.

If I remove the line (again, using 6.4.4), it dumps:

Message:
    regeneratorRuntime is not defined
Stack:
ReferenceError: regeneratorRuntime is not defined
    at Object.<anonymous> (yieldRightSubList.js:8:26)
    at Module._compile (module.js:397:26)
    at loader (<redacted>/node_modules/babel-register/lib/node.js:130:5)
    at Object.require.extensions.(anonymous function) [as .js] (<redacted>/node_modules/babel-register/lib/node.js:140:7)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)

This is what the original module looks like:

//import 'babel-regenerator-runtime';
/**
 * From a sorted list, yield a subList where the accessor values are the same.
 *
 * @param  {Object[]} sortedList
 * @param  {Function} accessor
 */
export default function* yieldRightSubList (sortedList, accessor) {
    if (sortedList.length === 1) {
        yield {r: sortedList, val: accessor(sortedList[sortedList.length - 1])};
    } else if (sortedList.length > 1) {
        let datum,

Here is what it looks like after transformation (using the regenaratorRuntime, which is never defined).

    "use strict";

    Object.defineProperty(exports, "__esModule", {
        value: true
    });
    exports.default = yieldRightSubList;

    var _marked = [yieldRightSubList].map(regeneratorRuntime.mark);

    //import 'babel-regenerator-runtime';
    /**
     * From a sorted list, yield a subList where the accessor values are the same.
     *
     * @param  {Object[]} sortedList
     * @param  {Function} accessor
     */
    function yieldRightSubList(sortedList, accessor) {
        var datum, tmpVal, i, val, r;
        return regeneratorRuntime.wrap(function yieldRightSubList$(_context) {
            while (1) {
                switch (_context.prev = _context.next) {
                    case 0:
                        if (!(sortedList.length === 1)) {
                            _context.next = 5;
                            break;
                        }

Here is my .babelrc file:

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

So, to avoid confusion here, is babel-regenerator-runtime now required? Or is this error just supposed to go away?

If it's the former, might I suggest you make babel-regenerator-runtime a dependency of this plugin and generate the import statement during compilation.

Comment originally made by @hzoo

You should be using the runtime plugin? "plugins": ["transform-runtime"]. Also the es2015 preset contains regenerator already http://babeljs.io/docs/plugins/preset-es2015/

Comment originally made by @mtraynham

Thanks for letting me know that ES2015 preset already contained the transform-regenerator.

Adding the 'transform-runtime' plugin increases the build size to 131 KB. Without any plugin it's 57 KB, and going the route I described above (adding 'babel-regenerator-runtime', which worked) was 81 KB. Seems a bit bloated, when I'm only using one generator function through-out my entire code base... It's just unclear what else is needed to get the error to go away and package everything so that end users can use the built library out of the box without dependencies.

I think that's why some people were reserved on using the 'babel-polyfill' as I imagine that adds even more bloat (a whopping 220 KB for my build), all just to get generators to work.

So back to my question, do we just package the 'babel-regenerator-runtime' into the build? Why not import this automatically when generator functions are encountered? This seems like what Babel 5 was doing and 81 KB is a lot better than 131 KB.

Comment originally made by @AgentME

I still see this issue with https://github.com/jamestalmage/__babel-T6922 with a fresh install of the latest babel deps. (That repo was created for T6922, but it looks like that was fixed and this was re-broken.)

Comment originally made by @ashaffer

Still seeing this issue as well. Definitely not resolved.

Comment originally made by @loganfsmyth

@ashaffer Without a specific example, I'm not sure what more we can add? Are you actually using transform-runtime?

Comment originally made by @AgentME

There's an example at https://github.com/jamestalmage/__babel-T6922.

Comment originally made by Serge Paquet (spaquet)

Ran into this bug yesterday. This simple function definition is enough to trigger the miscompilation (using es2015 and stage-0 presets, transform-runtime plugin)

function* foo({bar, ...baz}) { }

In the compiled output, notice the line

var _marked = [foo].map(_regeneratorRuntime.mark);

Which should be

var _marked = [foo].map(_regenerator2.default.mark);

Comment originally made by @andru

I've already noted that I've just been stung by this over in #T7041 but just thought I'd add here that this does not seem to be resolved with [email protected], [email protected] and [email protected].

With transform-runtime enabled I get a ReferenceError because _regeneratorRuntime is undefined

    var _regenerator = __webpack_require__(740);
    var _regenerator2 = _interopRequireDefault(_regenerator);

    // snip: a lot of app specific requires...

    var _marked = [savePlantingEventFromUI].map(_regeneratorRuntime.mark);

if I use a factory to create generators as suggested by @silkentrance then the factory gets uses regenerator2 instead of _regeneratorRuntime

    var _regenerator = __webpack_require__(740);
    var _regenerator2 = _interopRequireDefault(_regenerator);

        // snip

    function sagaFactory() {
      return _regenerator2.default.mark(function savePlantingEventFromUI() {
        var action;
        return _regenerator2.default.wrap(function savePlantingEventFromUI$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                if (false) {
                  _context.next = 7;
                  break;
                }

                _context.next = 3;
                return (0, _reduxSaga.take)(SAVE_EVENT);

              case 3:
                action = _context.sent;

                console.log(action);
                _context.next = 0;
                break;

              case 7:
              case 'end':
                return _context.stop();
            }
          }
        }, savePlantingEventFromUI, this);
      });
    }

    var sagas = exports.sagas = [sagaFactory()];

Original (broken) code:

   function * savePlantingEventFromUI () {
    while (true) {
      let action = yield take(SAVE_EVENT)
      console.log(action)
    }
  }
export const sagas = [
  savePlantingEventFromUI
]

Working code using factory workaround

function sagaFactory () {
  return function * savePlantingEventFromUI () {
    while (true) {
      let action = yield take(SAVE_EVENT)
      console.log(action)
    }
  }
}
export const sagas = [
  sagaFactory()
]

Comment originally made by @loganfsmyth

There does appear to still be some weirdness here.

Comment originally made by @loganfsmyth

Read too fast last time. https://phabricator.babeljs.io/T7041 should cover the current issue.

Comment originally made by @nathanmarks

@loganfsmyth

! In T6676#74083, @loganfsmyth wrote:
Read too fast last time. https://phabricator.babeljs.io/T7041 should cover the current issue.

I'm still lost as to how I fix the import statement issue: https://files.slack.com/files-pri/T062L95S6-F0QETV44C/pasted_image_at_2016_03_04_02_54_pm.png

Where does that fit in with all of this?

EDIT: NVM, fixed in latest :)

Was this page helpful?
0 / 5 - 0 ratings