Why Babel 7.18 broke async/await: regeneratorRuntime issues and fixes

This article analyzes the Babel 7.18 upgrade that caused regeneratorRuntime to disappear, leading to async/await failures and larger bundle sizes, explains the underlying plugin interactions, and provides practical solutions for frontend projects using Babel.

Alibaba Terminal Technology
Alibaba Terminal Technology
Alibaba Terminal Technology
Why Babel 7.18 broke async/await: regeneratorRuntime issues and fixes

Background

Babel 7.18.0 was released as a supposedly compatible upgrade from 7.17.x, but it introduced several problems in the Ant Group ecosystem, such as missing regeneratorRuntime and increased bundle size.

Prerequisite Knowledge

Understanding the following is essential:

@babel/preset-env bundles many plugins and configurations.

@babel/plugin-transform-regenerator handles generator conversion for async/await.

@babel/plugin-transform-runtime provides various runtime helpers.

regeneratorRuntime is a global variable that many projects assumed existed.

regenerator-runtime is Facebook’s (Meta’s) open‑source library that defines regeneratorRuntime.

Syntax and API Polyfill

ECMAScript upgrades include syntax (e.g., arrow functions, async/await) and API (e.g., String.prototype.replaceAll). Babel plugins like @babel/plugin-transform-arrow-functions convert syntax, while core‑js and regenerator-runtime polyfill the APIs, all integrated by @babel/preset-env.

async/await conversion

Conversion occurs in two steps: async → generator, then generator → ES5. The second step relies on @babel/plugin-transform-regenerator, which expects a global regeneratorRuntime variable.

There are three ways to provide this variable:

Manually import the runtime: import 'regenerator-runtime/runtime' Configure @babel/preset-env with useBuiltIns: 'usage' so Babel adds the import automatically.

Use @babel/plugin-transform-runtime (explained below).

@babel/plugin-transform-runtime

This plugin has three main functions:

Enhances async/await conversion so code works even without a global regeneratorRuntime (enabled by default).

Provides non‑global polyfills for new APIs (disabled by default).

Extracts inline helper code (e.g., objectSpread, classCallCheck) into imports like import xxx from '@babel/runtime/helpers/xxx', reducing duplicate code and bundle size (enabled by default).

Typical use cases:

Component library builds benefit from all three functions.

Application builds mainly use function 1; function 2 is less useful; function 3 helps shrink bundles.

Frameworks such as Umi enable this plugin by default, while tools like father require manual activation.

regenerator-runtime

regenerator-runtime is an open‑source library that attaches regeneratorRuntime to the global object. Although the plugin claims not to pollute the global scope, the library itself still creates the global variable.

What Babel changed

The new release addressed three issues:

Async/await output no longer depends on a global regeneratorRuntime; the helper is inlined.

regeneratorRuntime becomes a Babel runtime helper that can be extracted via @babel/plugin-transform-runtime.

The code of regenerator-runtime is copied into the Babel repository, removing the external dependency.

These changes caused incompatibilities because some frameworks still expected the global variable.

Problem Analysis

1. regeneratorRuntime is undefined

Older projects that relied on the global variable started failing after upgrading to Babel 7.18.0. The new inline helper does not automatically attach regeneratorRuntime to the global scope, breaking code that still expects it.

Example scenario with Ant’s Smallfish mobile framework:

Smallfish does not lock the version of @babel/plugin-transform-regenerator, so the inline helper is used.

Mobile builds often disable polyfills to save size, so the external regenerator-runtime is not loaded.

When a library built with an older Babel version (but re‑compiled with 7.18.0) is included, it may still require a global regeneratorRuntime, leading to runtime errors.

2. Bundle size increase

When @babel/plugin-transform-regenerator inlines the helper but @babel/plugin-transform-runtime is locked to an older version, the inline 10 KB helper cannot be extracted, causing each async/await usage to embed the helper and inflate the bundle.

Typical fix: align the versions of both plugins or lock @babel/plugin-transform-regenerator to a lower version (e.g., ~7.12.0) via resolutions in package.json.

3. npm package issues

Enabling @babel/plugin-transform-runtime is recommended to both eliminate the global regeneratorRuntime dependency and extract helpers to reduce size. For tools like father, ensure the runtimeHelpers option is enabled and update @babel/runtime to the matching version.

Solutions and Conclusions

The author quickly reverted the missing global assignment by adding the try‑catch block back in a new Babel PR (https://github.com/babel/babel/pull/14581). The current state is:

Babel 7.18.x is functionally equivalent to 7.17.x for existing projects.

The regeneratorRuntime undefined issue has been resolved.

Bundle size problems can be mitigated by aligning plugin versions or using the runtime plugin to extract helpers.

Overall, the frontend build ecosystem is complex and carries historical baggage; choosing well‑maintained internal frameworks and keeping Babel dependencies consistent helps avoid these pitfalls.

Other

Stay tuned to the Alibaba F2E WeChat public account for the latest frontend developments.

Babelasync/awaitFrontend Buildplugin-transform-runtimeregeneratorRuntime
Alibaba Terminal Technology
Written by

Alibaba Terminal Technology

Official public account of Alibaba Terminal

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.