使用 Bazel 1.0 构建您的无服务器 Azure 函数应用🌿
搭建 Azure 函数应用程序框架
设置 Bazel 工作区
构建 Azure 函数应用程序
部署到 Azure
Bazel 刚刚迎来了一个新的里程碑:Bazel 1.0 于今日正式发布。现在正是投资这款分布式构建和测试编排工具的最佳时机。
在本快速指南中,我们将使用 Bazel 构建一个用 TypeScript 编写的Azure 函数应用程序。
Bazel 是多语言的,这意味着你可以用它同时构建和测试不同的技术,即使是在同一个 monorepo 中!今天我们将重点关注 TypeScript。
如果您想了解更多关于 Bazel 在构建 Web 应用程序方面的功能,我强烈建议您阅读我的朋友 Alex Eagle(来自 Google 的 JavaScript 构建/服务团队)撰写的以下文章。
以下是我们将要遵循的步骤:
如果需要,我附上了Azure 免费试用版的链接,您可以自行试用。
让我们开始吧……
10 月 20 日更新:Hexa现在内置了对 Bazel 的支持!
搭建 Azure 函数应用程序框架
为了方便地创建和部署我们的Azure 函数应用程序,我们将使用Hexa CLI:
$ mkdir azurefunctionbazel && cd $_
$ hexa init --just functions
$ cd functions/azurefunctionbazel-5816
Hexa 是一个开源 CLI 工具,可以增强 Azure CLI(了解更多关于 Hexa 以及如何安装它的信息)。
我们使用Hexa在./functions/azurefunctionbazel-5816一个新的 TypeScript Azure 函数应用程序中搭建了脚手架,该应用程序tsc(默认情况下)使用构建。
我们将设置 Bazel 并使用它来通过ts_library规则(即 Bazel 插件)来编排构建过程。
设置 Bazel 工作区
为了在 Azure 函数项目中设置和使用 Bazel ./functions/azurefunctionbazel-5816,我们需要:
- 从 NPM 安装 Bazel 及其依赖项
WORKSPACE在项目根目录下添加一个文件BUILD.bazel在项目根目录下添加一个文件BUILD.bazel在每个函数内部添加一个
通常情况下,您无需手动设置 Bazel,而是可以使用诸如 Bazel 之类的工具
@bazel/create来自动完成设置和配置。
安装 Bazel 及其依赖项
在文件夹内./functions/azurefunctionbazel-5816,使用以下命令从 NPM 安装所需的 Bazel 及其依赖项(它还会更新现有依赖项package.json):
$ npm install -D \
@bazel/bazel@latest \
@bazel/typescript@latest \
typescript@^3.3.3
确保
typescript已将其列为依赖项并已安装。package.json
添加WORKSPACE文件
WORKSPACE在根目录下创建一个文件,./functions/azurefunctionbazel-5816内容如下(详见下方说明):
workspace(
name = "azurefunctionbazel",
managed_directories = {"@npm": ["node_modules"]},
)
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "1447312c8570e8916da0f5f415186e7098cdd4ce48e04b8e864f793c766959c3",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.38.2/rules_nodejs-0.38.2.tar.gz"],
)
load("@build_bazel_rules_nodejs//:index.bzl", "npm_install")
npm_install(
name = "npm",
package_json = "//:package.json",
package_lock_json = "//:package-lock.json",
)
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
install_bazel_dependencies()
load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
ts_setup_workspace()
让我们逐一解释每个部分……
workspace(
name = "azurefunctionbazel",
managed_directories = {"@npm": ["node_modules"]},
)
- 该
workspace规则声明此文件夹是 Bazel工作区的根目录。 - 该
name属性声明了如何从另一个工作区使用绝对标签引用此工作区,例如:@azurefunctionbazel// - 该
managed_directories属性将@npmBazel 工作区映射到node_modules目录。这使得 Bazel 可以使用与其他本地工具相同的目录node_modules。
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "1447312c8570e8916da0f5f415186e7098cdd4ce48e04b8e864f793c766959c3",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/0.38.2/rules_nodejs-0.38.2.tar.gz"],
)
这将安装 Node.js“bootstrap”包,该包提供在 Bazel 中运行和打包 Node.js 应用程序的基本工具。
load("@build_bazel_rules_nodejs//:index.bzl", "npm_install")
npm_install(
name = "npm",
package_json = "//:package.json",
package_lock_json = "//:package-lock.json",
)
- 该
npm_install规则会在配置文件更改时运行(npm或yarn根据您的配置运行)。它还会提取软件包中分发的任何 Bazel 规则。package.jsonpackage-lock.jsonnpm - 该
name属性就是 Bazel Label 引用的样子。@npm//@azure/functions
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
install_bazel_dependencies()
此调用将安装之前由该规则提取的所有 Bazel 规则npm_install。
load("@npm_bazel_typescript//:index.bzl", "ts_setup_workspace")
ts_setup_workspace()
这将为您的工作区设置 TypeScript 工具链。
根BUILD.bazel
BUILD.bazel在根目录下创建一个文件,./functions/azurefunctionbazel-5816内容如下:
exports_files(["tsconfig.json"], visibility = ["//:__subpackages__"])
这段简单的代码BUILD.bazel会将文件导出tsconfig.json,以便其他包可以引用它。
包裹BUILD.bazel
Bazel 建议创建细粒度的包,以提高构建效率。在 Bazel 术语中,包是指包含BUILD.bazel文件的文件夹,例如 .bazel.js ./functions/azurefunctionbazel-5816/httpTrigger/BUILD.bazel。
在我们的示例中,Azure 函数应用程序包含一个文件夹,每个函数对应一个文件夹。这些文件夹将用于存放我们的 Bazel 包。
在每个部分中,BUILD.bazel我们将描述该包(即 Azure 函数)应该如何构建,并让 Bazel 来处理编排。
为了构建我们的应用程序,我们将尽量简化流程,仅使用tsc编译器。但是,对于更复杂的场景,我们也可以使用工具对应用程序进行打包rollup和压缩terser。一个假设的构建过程可能如下所示:
# Note: this build hasn't been tested!
load("@npm_bazel_typescript//:index.bzl", "ts_library")
load("@npm_bazel_rollup//:index.bzl", "rollup_bundle")
load("@npm_bazel_terser//:index.bzl", "terser_minified")
package(default_visibility = ["//visibility:public"])
ts_library(
name = "httpTrigger",
srcs = ["index.ts"],
deps = ["@npm//@azure/functions"]
)
rollup_bundle(
name = "bundle",
entry_point = ":index.ts",
deps = [":httpTrigger"],
)
terser_minified(
name = "bundle.min",
src = ":bundle",
)
但就我们而言,我们将化繁为简:
load("@npm_bazel_typescript//:index.bzl", "ts_library")
package(default_visibility = ["//visibility:public"])
ts_library(
name = "httpTrigger",
srcs = ["index.ts"],
deps = ["@npm//@azure/functions"]
)
- 该属性是目标(本次调用)
name的名称。ts_library - 该
srcs属性列出了所有要转译的 TypeScript 文件。 - 该
deps属性列出了此包中使用的所有外部依赖项(例如@azure/functions)。@npm//是 NPM 工作区的名称(见WORKSPACE上文)。
细粒度的包管理让我们能够从 Bazel 获得增量式、可远程并行化的构建和自动缓存,这将大大缩短构建时间,尤其对于规模庞大、更为复杂的项目而言。
构建 Azure 函数应用程序
现在,我们可以运行 Bazel 来构建这个特定的软件包:
$ bazel build @azurefunctionbazel//httpTrigger:httpTrigger
到达目标的标准路径解释如下:
事实上,这条路径可以缩短为:
$ bazel build //httpTrigger
这是因为我们是在同一个工作空间中构建指定的目标。所以我们可以省略工作空间标识符,并且由于包名和目标名相同,我们也可以省略目标名称。
我们还可以指示 Bazel 构建当前工作区内所有软件包的所有目标:
$ bazel build //...
你可能不会觉得使用 Bazel 构建一个简单的函数有什么好处,但是一旦你开始处理数百个无服务器应用程序,Bazel 就能帮助你提高构建和测试性能。
Bazel 也非常擅长理解我们应用程序的依赖关系图。我们可以让 Bazel 向我们展示这个依赖关系图:
$ bazel query --noimplicit_deps 'deps(//...)' --output graph | dot -Tpng > azurefunctionbazel.png
输出结果:
我们可以利用这种可视化方式更好地了解应用程序的内部结构。想象一下,一个应用程序包含数百个函数应用!
部署到 Azure
ts_library()默认情况下, (*.js和)规则的输出*.d.ts将存储在./functions/azurefunctionbazel-5816/bazel-bin/httpTrigger。
在部署到 Azure 之前,我们需要更新function.json每个函数的配置,并将其scriptFile指向bazel-bin/:
{
...
"scriptFile": "../bazel-bin/httpTrigger/index.js"
}
我们还需要通过更新文件来确保不要将 Bazel 工作区部署到 Azure .funcignore:
## Bazel ignored files
node_modules/@bazel/*
BUILD.bazel
# ignore all bazel output folder except the bazel-bin folder
# where the transpiled code lives
bazel-*
!bazel-bin
现在我们准备使用Hexa CLI 将应用程序部署到 Azure:
$ # cd to the root of azurefunctionbazel where hexa.json is located
$ hexa deploy
部署命令的输出结果为:
✔ Building Function app azurefunctionbazel-5816...
✔ Deploying Function app azurefunctionbazel-5816...
✔ Application azurefunctionbazel deployed successfully!
➜ Functions:
- httptrigger: https://azurefunctionbazel-5816.azurewebsites.net/api/httptrigger?code=POfqT9xFCtYKOaryFW8LkzFsUtD3ioWi8Y2e4M8BpBeLhTOH8aqUIg==
✔ Done in 68 seconds.
恭喜🎉!您的 Azure 函数应用程序现已使用 Bazel 构建,并使用Hexa部署。
在 GitHub 上找到示例项目
文章来源:https://dev.to/azure/build-azure-function-apps-with-bazel-1-0-mci

