Inline regeneratorRuntime as a normal helper#14538
Inline regeneratorRuntime as a normal helper#14538nicolo-ribaudo merged 14 commits intobabel:mainfrom
regeneratorRuntime as a normal helper#14538Conversation
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/51967/ |
bdf8a90 to
c1cf367
Compare
|
Note that the first time This is due to the fact that Failing to load the polyfills before the execution of the runtime will cause |
|
Ok so, another benefit that I didn't list in the original description:
|
...form-runtime/test/fixtures/runtime-corejs2/regenerator-runtime-old-runtime-version/output.js
Outdated
Show resolved
Hide resolved
|
Hint: there is also a ci exception about windows. |
a383f6e to
83de4f1
Compare
|
It occurred to me that we can compress the code. Size can be reduced by 30%+. |
|
@liuxingbaoyu We currently minify helpers without renaming the variables to make stack traces easier to debug. Most users run a minifier on Babel's output anyway. |
77b2176 to
ee5ed10
Compare
nicolo-ribaudo
left a comment
There was a problem hiding this comment.
I have re-reviewed this. I'll merge for 7.18.0 when CI passes 🙂
|
@nicolo-ribaudo I'm seeing babel errors for about an hour, which coincides with the publication of 7.18.0 I checked in my lock file which packages have been updated and locking the versions before 7.18.0 for these fixes these issues, and the app now runs properly. It looks like there is something broken on this version :/ |
|
Not related to this PR, but thanks for the report! I'm working on a fix. |
|
oh, my bad, I tried to trace the diffs from 7.18.0 |
|
Wow, this SO question has 800 upvotes: https://stackoverflow.com/questions/33527653/babel-6-regeneratorruntime-is-not-defined |


I wanted to test this approach before opening an issue to discuss about it, but I ended up having a complete implementation 😅 I'm marking it as
i: discussion.Also, it can be reviewed commit-by-commit.
One of the major pain points when using regenerator is that by default it relies on a globally available
regeneratorRuntimehelper. For example, if you compilefunction* f() {}you get:This means that compiled generators don't work "by default", but you have to load the runtime helper:
import "regenerator-runtime"or with a script tag@babel/preset-envor@babel/transform-runtimeto automatically inject an import/requireAdditionally,
regeneratorRuntimeis always a global: even if you use@babel/runtime(where all the other helpers are "pure"), it will self-install itself as a global variable.Why is it a problem if the helper is not be automatically available?
If you look at our closed issues, it's common for people to be surprised that they need to do "something else" other than just enabling the regenerator plugin: https://github.com/babel/babel/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aclosed+regeneratorRuntime+is+not+defined. Also, all the other helpers are automatically available and they show that a nicer DX is possible.
Why is it a problem if the
regenerator-runtimealways self-installs itself as a global?It's common agreement that libraries should not modify the global scope, now that JavaScript has a proper module system. Additionally, detecting the global object is hard: regenerator-runtime first tries with a global
regeneratorRuntime = ...assignment that only works in non-strict mode, then fallbacks toglobalThis(which only works in modern browsers), and then to eval (which may be blocked by many common CSPs).The approach I'm proposing with this PR
regeneratorRuntimecan just be a normal helper, similarly to howclassCallCheckorasyncToGeneratorwork:function* f() {}will be transpiled to something like@babel/runtime, it can inject an import like@babel/runtime/helpers/regeneratorRuntimejust exports the helper, without trying to attach it to a global variable.For compatibility with older
@babel/coreversions that don't know about the built-inregeneratorRuntimehelper, we will fallback to the old behavior relying on theregeneratorRuntimeglobal.@babel/runtimeor@babel/preset-env(viababel-plugin-polyfill-regenerator) can than take care of injecting the helper import, if they are being used.Drawbacks
The
regeneratorRuntimehelper is huge: it's about 10k, which is ~10% more than our current other biggest helper (applyDecs). It's code that users already had to load, but now you could have multiple copies of it in different files (while the old behavior was to just throw at runtime, if you don't use@babel/runtime). However, people who care about their bundle size are already highly encouraged to use@babel/runtimeto deduplicate helpers.License and code sharing
I decided to have a build-step to copy
regenerator-runtime's contents to https://github.com/nicolo-ribaudo/babel/blob/vendor-regenerator-runtime/packages/babel-helpers/src/helpers/regeneratorRuntime.js, and then to process it with the existing scripts that we have to bundle our helpers from thebabel-helpers/src/helpersfolder.regenerator-runtime's contents, because we need to update our copy of the code wheneverregenerator-runtimehas a new release. Note thatregenerator-runtimeis "finished": it does not have known bugs, there are no new planned features, and so it new releases are rare.regenerator-runtimeis MIT licensed, and its copyright is owned by Facebook. The helper contains a short comment containing the copyright notice and a link to regenerator's original license. That comment is kept in every copy of the helper: both when it's inlined in user code, and in@babel/runtime.Follow ups
There is a@babel/generatorbug and sometimes the comment is duplicated, but that's a low-priority bug.cc @benjamn What do you think about this approach? My main goal is to simplify Babel's user experience, especially for beginners and for quick projects. Since you are the author/maintainer of
regenerator, I'd love to have your 👍!