andrew Flower

Async/Await with React, Webpack and Babel

ReferenceError: regeneratorRuntime is not defined

If you tried using async/await in React, you might encounter this error in the browser:

ReferenceError: regeneratorRuntime is not defined

Your application has been compiled, expecting regeratorRuntime to be available to interpret the async and await. But you haven't provided the regenerator.

Below are two simple ways to configure Babel to transpile these commands successfully so that they work in your environment. The examples will show how to do it using Webpack.

At the time of writing/editing, these are the versions I'm using

Babel 7.5
Webpack 3.3.5

The good and bad ways

There are two prominent ways to do this. The first is better as it does not pollute the global namespace.

Using plugin-transform-runtime

The plugin-transform-runtime plugin sandboxes your code and ensures that helper code is not imported more than once, rather re-using the same injected helper code. It also automatically injects Regenerator where generators or async/await are used.

It is better than the second option because, according to the Babel docs:

"If you directly import core-js or @babel/polyfill and the built-ins it provides such as Promise, Set and Map, those will pollute the global scope. While this might be ok for an app or a command line tool, it becomes a problem if your code is a library which you intend to publish for others to use or if you can't exactly control the environment in which your code will run."

All you need to do is install these two packages:

  • @babel/plugin-transform-runtime
  • @babel/runtime

And modify your Webpack configuration to use the plugin with the babel-loader.

module.exports = {
    ...
    module: {
        rules: [{
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            loader: "babel-loader",
            options: {
                presets: [
                    '@babel/preset-env',
                    '@babel/preset-react'
                ],
                plugins: [
                    '@babel/transform-runtime'
                ]
            }
        ...

Using @babel/polyfill

This option requires slightly less change, but as the Babel Polyfill Docs suggest, should be avoided.

"As of Babel 7.4.0, this package has been deprecated in favor of directly including core-js/stable (to polyfill ECMAScript features) and regenerator-runtime/runtime (needed to use transpiled generator functions)"

It goes on to say that this polyfill is targetting apps and not libraries, as it adds to the global scope and can cause namespace collisions. If you are aware and accept this, then all you need to do is install:

  • @babel/polyfill

And add it to the entrypoint in your Webpack configuration:

module.exports = {
    entry: [
        'babel-polyfill',
        'app.jsx'
    ],
        ...

Summary

So in summary there are two easy ways to add support for async/await using Babel, as was demonstrated in the Webpack configurations. Only one of these should be used these days.

Bye bye, have fun

References