Issue originally made by @d6u
Bug information
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
index.es6
function *iter() {
yield 1;
yield 2;
yield 3;
}
for (let n of iter()) {
console.log(n);
}
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.
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:
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.
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
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 :)
Most helpful comment
Another workaround is to add the following to the es6 file using it: