不同构建环境如何正确设置环境变量及故障排查
推荐超级课程:
@TOC
概述
有时在单页应用程序(SPAs)中,可能会对如何在不同的环境中获取和填充环境变量感到困惑。这还可能因框架而异,并且也可能发生在并非严格意义上的SPA的框架/库中。
在部署时——严格来说是指SPA——这类应用程序通过将环境变量注入构建过程中来处理它们。这意味着环境变量必须在生成生产构建的环境中可用,该环境生成您的静态包。我们不是在谈论使用开发服务器的情况(比如在本地开发中通常使用的那样)。理想情况下,在开发服务器上运行时,会使用Web Pack来处理这个问题。但在生产环境中,我们不会使用这种方式。
我应该在哪里添加它们?
由于环境变量必须存在于生成生产包的“构建”环境中,我们将查看以下一些场景以更好地解释:
本地Git(和使用Oryx的其他方法)
如果使用本地Git进行部署,您将使用Oryx进行构建 ,针对Kudu站点,该站点作为与应用程序分离的容器运行。这将是我们进行构建的环境。
因此,您需要将希望注入构建的应用程序中的环境变量添加为应用设置。这种方法适用于所有依赖客户端代码构建的SPA和框架。
我们之所以将环境变量添加为应用设置,而不是下面提到的其他方法,是因为添加应用设置后,这些变量也将存在于Kudu环境中,这是我们的构建环境,正是正确注入它们所需的环境。以React为例,它期望任何在客户端代码中可访问的环境变量带有REACT_APP_
前缀
,让我们添加一个应用设置:
我们可以看到它在Kudu环境中是可用的:
现在,如果我们部署如下代码,我们应该看到它被正确注入:
<span>
API URI: `{process.env.REACT_APP_API_URI ?? "No environment variables found"}`
</span>
为什么环境变量会显示为缺失或未定义?
在上面的例子中,我们在部署之前添加了应用设置,所以在执行 npm run build
或 yarn run build
时,环境已经可以访问它。但是,如果我们先部署,然后在部署完成后添加相同的应用设置会发生什么?
假设我们没有添加任何应用设置(比如 REACT_APP_API_URI
),现在进行部署,我们会看到以下情况:
这意味着空值合并回退到了我们的默认值,因为 REACT_APP_API_URI
在环境中不可用,无法注入到我们的构建中。
总结:
如果使用 Oryx 作为构建器,应在部署之前添加应用设置,否则环境变量将不可用于构建。
如果这些应用设置是在部署之后添加的,那么需要重新部署应用程序。
GitHub Actions
当使用 GitHub Actions 进行部署(以 GitHub 作为构建器)时,通常整个构建过程会在这个管道中执行。
因此,这将是一个构建环境,并且需要在这里提供环境变量。这基本上对所有需要为客户侧代码进行构建过程的 SPA 或基于 Node 的应用程序都是相同的前提。
以下是使用 Next.js 作为示例。我们在 GitHub Actions 中使用 env
属性指定环境变量。更多相关信息可以在这里找到:环境变量
:
name: Build and deploy Node.js app to Azure Web App - myapp
env:
NEXT_PUBLIC_API_URI: ${{ secrets.NEXT_PUBLIC_API_URI }}
on:
push:
branches:
- main
workflow_dispatch:
我们将环境变量添加到管道中,因为以 NEXT_PUBLIC_
为前缀的变量是浏览器可以访问的变量,并且需要在构建时可用。
在我们的 Next.js 应用程序中使用如下代码,我们可以看到它现在是可访问的:
<p className={styles.description}>
NEXT_PUBLIC_API_URI: {process.env.NEXT_PUBLIC_API_URI ?? "No environment variables exposed to the browser"}
</p>
重要提示:
由于构建发生在 GitHub Actions 中,我们不需要在应用服务的应用设置中添加这些变量。这将没有任何影响,而且也是多余的,因为构建是在管道中发生的,而不是使用 Oryx(应用服务)。这仅适用于嵌入到构建中的环境变量,例如浏览器访问的变量****注意:请小心审查您所使用框架/库的文档。以 Next.js 为例,有一些环境变量仅对浏览器可用(以 NEXT_PUBLIC_
为前缀的变量),还有一些环境变量仅在 Node 环境中可用。如果您的框架中有仅在 Node 运行时可用且不在浏览器中可用的环境变量,那么它们必须作为应用设置添加。
有关 Next.js 环境变量的更多信息,请参阅这里 的文档。
DevOps 管道
Azure DevOps 管道将遵循我们讨论 GitHub Actions 时提到的相同方法。
我们将使用一个 Vue 应用程序来举例说明。
与 React 和 Next 一样,Vue 期望环境变量具有特定的前缀
,以便在浏览器中访问这些变量——这个前缀是 VUE_APP_
(此方法使用的是维护模式的 Vue CLI)。对于使用 Vite
的 Vue 应用程序,前缀是 VITE_
。
我们将使用如下代码在浏览器中访问我们的环境变量:
在管道侧,要添加环境变量:
点击 管道 -> 省略号图标 -> 编辑管道
然后,点击 变量 -> 添加新变量
这样,环境变量就会被暴露出来,当我们在管道中运行 npm run build
时,环境变量将被嵌入到构建中。我们现在会在运行时看到这个变量可用:
如果我们忘记这样做,我们的环境变量可能会是未定义的。
重要提示:
由于构建发生在 DevOps 管道上,我们不需要在应用服务的应用设置中添加这些变量。这将没有任何影响,而且也是多余的,因为构建是在管道中发生的,而不是使用 Oryx(应用服务)。这仅适用于嵌入到构建中的环境变量,例如浏览器访问的变量
Zip 部署(不使用 Oryx 构建),FTP
如果使用不通过 Oryx 构建的 Zip 部署(应用设置 SCM_DO_BUILD_DURING_DEPLOYMENT
未设置或设置为 false
)或使用 FTP 部署您的基于 SPA 的应用程序——您需要确保生产构建是本地生成的。
框架特定示例
以下是某些框架需要特定的变量前缀以便将这些变量暴露给浏览器。如果不添加这些前缀,即使您正确地将它们暴露给构建环境,您的变量也将是未定义的:
- React
- 使用
REACT_APP_
前缀 - Vue (with Vue CLI)
- 使用
VUE_APP_
前缀 - Vue (with Vite)
- 使用
VITE_
前缀 - Nextjs (client-code)
- 使用
NEXT_PUBLIC_
前缀 - Angular
- Angular 通过
environment.<someEnv>.ts
文件以不同的方式处理这个问题。仍然可以使用process.env.<SOME_ENV>
,就像这些其他库和框架一样,但需要一些额外的工作。有关如何使用process.env.
方法的示例可以在 这里 查看。
故障排除
如果您的变量在运行时显示为未定义,请审查以下要点:
- 这些环境变量应该暴露给浏览器吗?(例如,
REACT_APP_
,VUE_APP_
,VITE_
,NEXT_PUBLIC_
等)- 如果是,请确保这些环境变量的值在您的 GitHub Actions 管道或 DevOps 管道的构建时可用。审查有关使用 DevOps 添加变量 和使用 GitHub Actions 添加变量 的文档。如果使用 Oryx 在 Kudu 上构建(例如,本地 Git)- 将这些值作为应用设置添加。
- 这些环境变量应该暴露给 Node 运行时吗?(例如,服务器端,非浏览器/客户端代码)
- 如果是,请确保这些环境变量的值作为应用设置添加到应用服务上。
- 如果您的库/框架期望特定前缀以使它们对客户端代码可用,请检查您的语法。
- 如果将这些作为秘密添加到 GitHub Actions 的
env
块中引用,请确保您引用了适当的秘密名称。