We‘re Nearing the Babel 7.0 Release: Here‘s All the Cool Stuff We‘ve Been Doing

Babel

It‘s hard to believe, but we‘re finally approaching the release of Babel 7.0. For the past year, the Babel team and contributors have been hard at work adding new features, fixing bugs, improving performance, and laying the foundation for the future of the project. As a maintainer, I wanted to take a step back and reflect on what we‘ve accomplished and share some of the highlights with you.

By the Numbers

Before diving into the technical details, let‘s take a quick look at some stats that illustrate just how much Babel has grown and how many people are relying on it:

  • 1.3 million weekly npm downloads (up from 1 million a year ago)
  • 17.5 million monthly npm downloads (up from 11 million a year ago)
  • 1,675 public GitHub repos depend on @babel/core (and many more on other packages)
  • 500+ contributors have helped out in the last year (double from the previous year)

It‘s incredible to see the continued growth and adoption of Babel. But with that increased usage also comes a greater responsibility for the maintainers to keep things running smoothly.

Putting the User First

One of our key priorities for the 7.0 release has been improving the developer experience, especially when it comes to configuring Babel. While Babel is an incredibly powerful tool, it can sometimes be daunting to set up, with its myriad plugins, presets, and options.

Our goal is for Babel to "just work" for most users while still allowing power users to customize every detail. Here are some of the ways we‘re making that happen:

A New Config Hierarchy

We‘ve introduced a new config hierarchy that allows you to specify your Babel config in a variety of ways:

  • Project-wide configuration: A babel.config.json file in your project root will apply to all files in the project.
  • File-relative configuration: A .babelrc.json file in a specific directory will apply only to files in that directory and its subdirectories.
  • package.json fields: You can also specify Babel options directly in your package.json file under a "babel" key.

This allows for a more intuitive and flexible configuration setup. For example, you can have a base config for your whole project, but then override certain settings for a specific folder.

Here‘s what a babel.config.json might look like:

{
  "presets": ["@babel/preset-env"],
  "plugins": ["@babel/plugin-transform-runtime"],
  "sourceType": "unambiguous",
  "overrides": [{
    "test": "./special-dir",
    "sourceType": "module"
  }] 
}

The env Preset

Keeping up with which JavaScript syntax is supported in which browsers can be a full-time job. Babel has long offered individual presets for each yearly update to the language (ES2015, ES2016, etc.), but it was up to users to know which ones they needed.

With the new @babel/preset-env, you can simply specify which browsers you need to support and let Babel handle the rest:

{
  "presets": [
    ["@babel/preset-env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ]
}

Under the hood, preset-env determines which language features are supported by your target browsers and only transpiles the ones that are needed. This results in smaller bundle sizes and faster compilation compared to including all the yearly presets.

Since its introduction a few years ago, preset-env has become one of our most popular packages. In Babel 7.0, we‘re making it the new default and deprecating the individual year-based presets.

Empowering Experimentation

One of Babel‘s core roles in the JavaScript ecosystem is enabling developers to use new language features before they are supported natively in browsers. We work closely with TC39, the committee that develops the JavaScript standard, to provide implementations of new proposals.

In Babel 7.0, we‘re expanding that role even further with some key changes.

Opting In to Experimental Features

Previously, experimental language proposals were grouped into stages (0-4) and you could opt in to all features at a given stage with a preset like @babel/preset-stage-3. In practice, this led to unexpected behavior as proposals at the same stage were often quite different in their stability and required effort to implement.

Now, we recommend explicitly opting in to individual proposals, which makes the configuration more verbose but also much clearer. We‘ve introduced a new naming scheme for proposal plugins that includes both the proposal name and its TC39 stage:

// Before
{
  "presets": ["@babel/preset-stage-3"]
}

// After
{
  "plugins": [
    "@babel/plugin-proposal-class-properties", 
    "@babel/plugin-proposal-optional-chaining"
  ]
}

This gives you full control over which experimental features you are using. Over time, as proposals move through the TC39 process and become more stable, we will recommend enabling them by default. But you‘ll always be able to opt out if needed.

Enabling Proposals Outside Official Releases

In addition to being more explicit about proposals, we‘re also making them more decoupled from Babel‘s release cycle. Previously, a new proposal implementation could only be released as part of a new Babel version. This meant that users either had to wait for the next release or use a beta/alpha version just to try out a new language feature.

Starting with 7.0, we now allow proposal plugins to be published and updated independently of the main Babel packages. This means you‘ll be able to use the latest version of a proposal plugin as soon as it‘s implemented, without having to wait for the next major Babel release.

We‘ve already seen the benefits of this approach with the release of a few new Stage 3 proposals like private class fields, private class methods and numeric separators. Because these proposals were implemented and released within days of being advanced to Stage 3, Babel users were able to quickly provide feedback to the committee.

We hope this more agile process will enable more experimentation and iteration, ultimately leading to better language design decisions.

Investing in the Future

Beyond the user-facing changes, we‘ve also made significant investments in Babel‘s underlying architecture and infrastructure with an eye towards the future.

A New Parser

Perhaps the biggest change is the new parser, @babel/parser (formerly Babylon). The parser is responsible for taking raw source code and turning it into an abstract syntax tree (AST) that Babel can manipulate.

We‘ve completely rewritten the parser from the ground up with a focus on modularity, performance, and extensibility. The old parser had grown quite large and complex after years of development. For 7.0, we‘ve split it up into multiple packages:

  • @babel/parser: The core parser infrastructure (formerly Babylon)
  • @babel/parser-ts: Support for parsing TypeScript syntax
  • @babel/parser-flow: Support for parsing Flow syntax
  • @babel/parser-jsx: Support for parsing JSX syntax

This modular structure will make it much easier to maintain and optimize each part of the parser separately. It also opens up possibilities like allowing users to create their own custom parsers by swapping out parts they don‘t need.

From a performance perspective, @babel/parser is up to 2x faster than Babylon in our benchmarks. This is thanks to a number of low-level optimizations, but also to the new plugin-based architecture which allows us to avoid unnecessary work.

A Faster, More Efficient Traversal

Once Babel has an AST, it needs to traverse that structure in order to make modifications. This traversal process is the heart of how Babel works, so it‘s critical that it be as fast and efficient as possible.

For 7.0, we‘ve made some significant changes to the traversal process:

  • Rewritten the traversal to be fully iterative instead of recursive, avoiding stack overflow errors and generally being more efficient.
  • Introduced a new NodePath abstraction that encapsulates information about an AST node‘s context and provides a cleaner API for modification.
  • Made the traversal more selective by avoiding processing entire subtrees if possible and optimizing processing of leaf nodes.

These changes, along with the parser improvements, have resulted in up to 60% faster JavaScript compilation in our benchmarks. We‘ll continue to look for more optimization opportunities in the future, but this is already a huge win for our users.

Investing in TypeScript

One of the biggest challenges we‘ve faced in maintaining Babel is keeping up with the constant evolution of the JavaScript language. Every year there are new syntax proposals to implement on top of the yearly language releases.

Babel has historically been written in plain ES2015 JavaScript, which has made it challenging to scale the codebase and ensure high-quality, type-safe code. To address these issues, we‘ve been gradually migrating the codebase to TypeScript.

The parser and core transformation logic are now written entirely in TypeScript. We‘ve found the type checking and improved autocompletion to be invaluable for working with complex AST structures. The code is more readable and maintainable, and we‘ve even caught a few bugs via type checking.

We still have a lot of conversion work to do, but eventually our goal is for the entire Babel codebase to be TypeScript. This is a significant undertaking, but we believe the long-term benefits to maintainability and stability are worth it.

Continued Mission

As the core team and I have worked on this release, I‘ve been reflecting a lot on Babel‘s role in the JavaScript ecosystem. What started as a simple tool for compiling ES6 has become a key part of the language development process itself.

By enabling more people to use new and proposed JavaScript features in real-world codebases, Babel has helped validate and shape the future of the language. It has given developers a voice in the process and helped TC39 gather valuable feedback.

But Babel isn‘t just a utility – it‘s also a community. We‘ve been fortunate to have hundreds of contributors and millions of users. Their energy and enthusiasm are what keep the project alive.

As a maintainer, I feel a deep responsibility to both the code and the community. It‘s a balancing act between moving the project forward and minimizing disruption, between empowering contributors and maintaining a cohesive vision.

It‘s a challenge, but also a joy. There‘s something special about working on a project that so many people rely on. Knowing that your code runs on millions of websites is both terrifying and exciting.

Looking ahead, I‘m optimistic about Babel‘s future. We have a clear vision and roadmap, a solid foundation to build on, and a vibrant community. There‘s still a lot of work to do, but I believe we‘re well-positioned to continue driving JavaScript forward.

I‘m personally grateful to be a part of this journey and I‘m looking forward to seeing what the community builds with Babel 7.0 and beyond. If you‘re interested in contributing or providing feedback, please join us on GitHub or our Slack community. We‘d love to have you!

Similar Posts