Angular ❤️ Bazel 离开 Angular 实验室
我们学到了什么
通用 Bazel
这对我来说意味着什么?
随着 Angular 9.0 的发布,包括全新的 Ivy 编译器和运行时,现在正是时候思考“Angular 的下一步是什么?”。你甚至可能会问“接下来会是 Bazel 吗?”。简而言之:我们正在剥离 Bazel 的工作,使其独立于 Angular,并支持所有前端框架或 Node.js 后端。然而,Bazel 永远不会成为 Angular CLI 的默认构建工具,我们预计大多数应用程序也不会切换。
我们学到了什么
我们用 Bazel 开发 Angular 已经有几年了。简单回顾一下,Bazel 是 Google 的增量构建工具——一个小的改动只需要少量的重新构建/测试。它还允许你的构建步骤使用共享缓存,并在多台机器上远程并行执行。这是 Google 能够与数千名工程师在一个庞大的单一代码库中编写大型应用程序的关键。为了使 Angular 在 Google 内部可用,团队必须为 Google 工程师维护 Angular+Bazel。
Bazel 在 Angular Labs 中作为可选预览版已上线一年多,这给了我们一些时间进行深入研究,并向用户学习。目前有几家公司正在使用这个工具链,我听说其中几家公司计划撰写一份案例研究,介绍他们从中获得的益处。
我们了解到,大多数 Angular 应用并没有 Bazel 所解决的问题。对于这些应用,我们不想再引入一个复杂的构建系统机制——无论我们在 Angular CLI 中如何封装,它都是一种有漏洞的抽象,最终用户很可能会遇到 Bazel。因此,我们永远不会打算将其作为 Angular CLI 用户的默认构建系统。
我们学到的另一件事是,Bazel 的迁移应该循序渐进。任何重大变更对于企业应用来说都是一个重大障碍。Bazel 可以运行任何工具链:虽然 Bazel 负责计算哪些构建步骤需要重新运行,但它并不关心这些步骤的具体功能。这意味着我们可以选择在迁移到 Bazel 的同时保持工具链不变。对于 Angular 开发者来说,这意味着所有使用 CLI 的应用程序都应该支持 Bazel。
我们尝试了几种迁移方法。首先,在 Angular 4 中,我们引入了对 Google Closure Compiler 的支持。它可以生成最小的打包文件,但它是一个需要大量工作才能适应的专业工具。然后,我们引入了一个混合工具链,使用 Google 的方法来编译 TypeScript、Angular、Sass 等,但使用 Rollup 作为打包工具。这种方法更加实用,但仍然不是总能立即使用的替代方案;迁移到 Google 的工具仍然需要一些成本。
通用 Bazel
因此,本质上,我们原本希望导出 Google 内部的工具链,但它存在一些不兼容性,即使是最小的不兼容性也是不可接受的。因此,去年年底,我们发布了 Bazel JavaScript 支持 (rules_nodejs) 的 1.0 稳定版本,其中包含一项新功能:无需任何自定义插件代码(Bazel 称之为“规则”)即可在 Bazel 下运行任何JS 生态系统工具。
我在《Bazel Web 分层》一文中写过这个。那篇文章的 TL;DR 是这样的:如果你安装了一些你选择的 JS 工具,比如
$ npm install mocha domino @babel/core @babel/cli @babel/preset-env http-server
您现在可以配置 Bazel 来使用该工具链:
load("@npm//@babel/cli:index.bzl", "babel")
load("@npm//mocha:index.bzl", "mocha_test")
load("@npm//http-server:index.bzl", "http_server")
babel(
name = "compile",
outs = ["app.es5.js"],
...
)
http_server(
name = "server",
data = [
"index.html",
"app.es5.js",
],
...
)
mocha_test(
name = "unit_tests",
args = ["*.spec.js"],
...
)
这对 Angular 开发者来说意味着什么?嗯,既然 Bazel 现在可以运行任何 JS 生态系统工具,它应该能够完全运行你现在正在使用的工具。为了解释我们是如何做到这一点的,我们需要稍微剖析一下 Angular CLI。
Angular CLI 的一个简单模型是:
ng
命令 -> 构建器 -> webpack
该ng
命令会读取你的angular.json
文件,以查找应使用的构建器。构建器层在内部称为“Architect”,因此在你的angular.json
文件中查找键“architect”,你就会看到要使用的构建器的映射。例如,假设你运行ng build
;默认构建器是@angular-devkit/build-angular:browser
。
在文档中了解有关 Angular CLI 构建器的更多信息
这实际上是一个独立的程序,可以在 Angular CLI 之外运行。该@angular-devkit/architect-cli
包提供了一个名为 Architect 的命令行工具。因此ng build
,它完全相当于剥离一层抽象并运行npx architect frontend:build
。
现在我们可以把各个部分组合起来了。如果 Bazel 可以运行任意的 JS 工具,并且我们知道如何使用 Architect 运行当前 Angular 构建的各个步骤,那么我们就可以让 Bazel 运行architect
CLI 来精确地重现你今天正在进行的构建。我们有一个示例应用演示了这一点——如果你查看BUILD.bazel
示例中的文件,你会发现,当 Bazel 想要构建或测试 Angular 应用时,我们只需调用 Architect 命令即可。
这对我来说意味着什么?
首先,如果你的团队对 Angular CLI(或 Nx)感到满意,那么你无需做任何事情。Bazel 不会对你造成影响,将来也不会。
如果当前的工具确实存在扩展问题怎么办?这是软件工程,所以需要权衡利弊。为了让这个构建系统 100% 兼容所有现有的 Angular 应用,我们失去了 Bazel 的一些增量保证。如果我们只运行架构师,那么我们构建的最精细粒度就是拥有一堆 Angular 库和一个使用它们的应用。这样,在发生更改后,只需要重新构建受影响的库。这与 Nx 的做法非常相似。
我们认为现在可以获得最佳的入口:首先使用 Bazel 来协调您现有的构建步骤,然后自定义构建图以提高增量性,从最慢、执行最频繁的步骤开始。
这种方法还有另一个有趣的结果。Angular 并不特殊,任何前端或 Node.js 后端代码都可以由 Bazel 构建,无需团队任何额外工作。因此,我们计划将 Bazel 特有的 API(即@angular/bazel
包)从 Angular 本身中迁移出来,让 Bazel 的工作与 Angular 团队的目标完全脱钩。这赋予了 Bazel 更大的自主权,意味着它可以立即应用于 React、Vue、Next.js 或任何其他提供 CLI 的框架/技术。
至于谁支持什么:我现在在 rules_nodejs 上工作,但不再属于 Angular 团队,所以我们的层级结构非常清晰。Angular 团队支持 CLI 构建器,因此您在使用过程中发现的任何 bug 都可以报告给 Angular。这些构建器的编排由 rules_nodejs 负责,我们将尽力为您提供支持。需要注意的是,后者是一个完全由志愿者组成的开源项目。
以下是当前发生的变化的简要概述:
- Angular 正在弃用
@angular/bazel
v10 的软件包,请参阅Pull 请求 - Angular CLI 构建器现在位于从 rules_nodejs 发布的
@bazel/angular
包中 - 目前没有自动 Bazel 配置。我们预计用户会选择使用 Bazel,因此您必须使用 WORKSPACE/BUILD 文件进行配置。社区提供了许多用于维护配置的工具,例如Evertz/bzlgen。
- 您不再需要
ng_module
中的 Bazel 规则@angular/bazel
。迁移路径是使用ts_library
Angular 插件。请参阅规范的 Angular 示例
我们将继续更新文档,您可以在https://slack.bazel.build上的 #angular 频道中关注这项工作。
我非常高兴能够继续向前端开发者社区推广 Bazel 的独特功能!非常感谢所有为此解决方案做出贡献的贡献者和用户。
文章来源:https://dev.to/bazel/angular-bazel-leaving-angular-labs-51ja