What Angular is doing with Bazel and Closure

In his ng-conf 2017 keynote, Brad Green announced an effort called ABC — Angular with Bazel and Closure. The goal is to converge how we develop Angular applications internally at Google with how the external community does it. This is still in the design phase, so detail and documentation will not be ready for some time. But we also care deeply about the Angular community, and believe it’s important to give some sketch of what we aim to do, and why.

Gmail was a revolutionary application when it was first introduced. It was a complex, ambitious competitor to desktop mail clients, and ran entirely in a web browser. Later, products like Google Docs repeated this success, and the longevity of these tools proves that their codebases were still maintainable even with lots of JavaScript.

This was possible because some very talented engineers developed the tooling needed to turn JavaScript into an enterprise development platform. We created a typed variant of JavaScript, called Closure, with a standard library, the Closure Library, and the Closure Compiler, which is a type checker, ES2015-transpiler, optimizer, bundler, minifier, all in a single command.

In the 10 years since, the team has continued to make incremental improvements to the optimizer in Closure Compiler. Even single-digit-percentage optimizations provided enough benefit across Google’s webapps that we could dedicate the engineering effort needed. Features like code-splitting to support lazy-loading, and A/B experiments and code hiding at the level of individual JS files have been added to our build toolchain.

Fast forward to Angular in 2016. We released the “Ahead-of-Time Compiler” for Angular, which relocates most of the Angular framework from runtime in the browser to a build step. Importantly, this compiler also changes the templates from HTML to JavaScript, so the entire deployed application is in the same language. This allows Closure Compiler to do the most important optimization: property renaming. Properties in the component class can now be renamed to single-letter identifiers, because the references in the template can be renamed as well. We took full advantage of this within Google, and our Angular applications have typically used the Advanced Optimization flags for Closure Compiler to produce much smaller JavaScript payloads.

At the same time, we needed to integrate both TypeScript and Angular into our build tool, Bazel (http://bazel.build). We provide 1–2 second roundtrip development time, with Ahead-of-time compilation as the *only* allowed method for running Angular. (Aside from in tests, where Just-in-Time is currently required to allow overriding the component tree. There are now plans to do AOT for tests as well.) This means that we do TypeScript and Angular type-checking, TypeScript-to-JavaScript compilation, and Angular template compilation quickly enough to keep developers productive, even on the largest applications.

The necessary property to make this work is that development turnaround time must be proportional to the size of a “library”, not to the size of an application. By dividing compilation into individual compilation units, we only need to run `ngc` on the handful of files including those you’ve just changed, but not on the rest of the application. In other build systems, it would be very cumbersome to orchestrate all the needed re-compilations, and especially hard to reliably re-build the right ones. After all, the only thing worse than a non-incremental build tool is a build tool where you don’t trust that the change you just made is actually reflected in the running application. Bazel users trust the incrementality so much that they never run “bazel clean” (I speculate that many Googlers aren’t even aware of that command).

We think this is pretty cool, and really important to developing large, enterprise-scale frontends. But unlike most of Angular, we’ve developed this integration in our closed-source internal repository. Now we are working to make this available to everyone. This benefits both the open-source community (especially enterprise users), who could build Angular applications like Google does, and also benefits the Angular team, by reducing the amount of parallel effort we undertake behind the scenes.

At the same time, this is also pretty intimidating. Building Angular applications can already be challenging at large-scale. We want to make this better, not worse. So our plan is to first roll this out in our own GitHub repository (which has been suffering a shell-script based build for a year) and prove to ourselves that we can love this developer experience.

After that, we’ll evaluate some options to assemble a build toolchain that provides the best of what we’ve built for ourselves and also the best of what has been built by the community. For example, even though Bazel will run all the compiler tools, we can still use Webpack as the development server. We will also consider how this toolchain can be available in the next generation of the Angular CLI.

There is a lot of work ahead of us, but we are also tremendously excited to tear down some of the walled garden that has separated the developer experience of our two crucial groups of users: our Google co-workers and our Angular community.