使用 Azure DevOps CI/CD 管道将 Visual Studio React 应用程序部署到 Azure 静态 Web 应用
有关使用 Azure DevOps 将 Visual Studio 2022 React 项目部署到 Azure 静态 Web 应用的说明,包括有关项目结构以及它如何与 YAML 管道设置相关的信息。
引言
注意:本文仅介绍 Windows 上的 Visual Studio。不包括安装 Visual Studio、Node.js 或任何其他软件的说明。
如果像我一样,您倾向于在功能齐全的 Visual Studio 版本中进行所有开发,您可能会发现互联网上关于将 React Web 应用程序部署到 Azure 静态 Web 应用的信息对您不起作用。我找到的所有教程和问答条目都针对 Visual Studio Code 项目,并且大多数都使用 GitHub Actions 进行部署。
我在其他教程中遇到的主要问题是正确获取代码路径。Visual Studio (VS) 项目模板倾向于将项目代码包装在包含 Visual Studio 解决方案的附加文件夹层中。这也是您创建 CI/CD YAML 管道文件的文件夹。
进一步的复杂情况是,最新的 VS React 项目(2024 年 9 月 9 日)在 VS 中按 F5 调试时使用 Vite 来托管应用程序。我不清楚在部署到 Azure 静态 Web 应用之前是否需要生成项目。我现在就可以解决这个问题,您确实需要先生成项目,但有几种方法可以做到这一点,包括一个可以同时完成生成和部署的管道步骤。
而且,另一个复杂之处在于,当您使用“独立 TypeScript React 项目”模板创建新项目时,VS 允许您更改解决方案 (.sln) 文件在文件夹结构中的位置。
快速答案
如果您尝试按照其他关于如何创建 Azure 静态 Web 应用并将其部署的帖子进行操作,但 DevOps 部署管道未能生成,并且您没有时间阅读完整的文章,那么您可能只需要 Azure 门户中“创建静态 Web 应用”表单的“生成详细信息”部分的正确设置。
所需设置取决于您是使用解决方案和项目在同一目录中创建的 VS 项目
- 应用位置/
- API 位置
- 输出位置: dist
或者以传统方式将解决方案放在单独的目录中
- 应用位置: /<项目名称>
- API 位置
- 输出位置: dist
将 <项目名称> 替换为您的 VS 项目名称,例如 /reactproject1
如果您想了解更多信息,请继续阅读。
长答案
要在 Visual Studio 中创建 React 应用并使用 Azure DevOps 管道将其部署到 Azure 静态 Web 应用,您需要执行以下操作:
- 创建您的 Visual Studio 项目。
- 将您的项目添加到 Azure DevOps 存储库。
- 创建 Azure 静态 Web 应用。
- 创建 CI/CD 管道以将您的应用程序部署到 Azure 静态 Web 应用。
使用 Azure 门户中的向导创建 Azure 静态 Web 应用时,步骤 3 和 4 会同时完成。
本文的其余部分详细介绍了一种完成这些任务的方法,并提供了一些额外信息以帮助您理解正在发生的事情。
在 Visual Studio 中创建 React 项目
在 Visual Studio 中,您可以使用众多可用的项目模板之一来创建新项目。对于 React,您有四种模板可供选择:
- 独立 JavaScript React 项目
- 独立 TypeScript React 项目
- React 和 ASP.Net Core (标签:JavaScript)
- React 和 ASP.Net Core (标签:TypeScript)
我将使用独立 TypeScript React 项目模板,但如果您愿意,也可以使用 JavaScript 模板。
创建项目
- 在 Windows 中打开 Visual Studio。
- 从 VS 启动屏幕中选择“创建新项目”选项。
- 在“创建新项目”页面的顶部搜索框中键入React。
- 选择独立 TypeScript React 项目模板。
- 选择“下一步”按钮。
- 在“项目名称:”文本框中输入您的项目名称。例如:reactproject1
- 接受默认的“位置”,或者如果您将项目文件保存在与操作系统 (OS) 不同的硬盘驱动器上,请选择其他路径。
- 现在您需要做出选择。您可以选择在单独的目录中创建解决方案文件,也可以将文件添加到项目目录中。您的选择将影响创建 CI/CD 部署管道时所需的属性。
- 选择“创建”按钮以创建您的项目。
如果您选择“将解决方案和项目放在同一目录中”选项
您的文件和目录将如下所示:
reactproject1/
├─ .vs/
├─ .vscode/
├─ public/
│ └─ vite.svg
├─ src/
│ ├─ assets/
│ │ └─ react.svg
│ ├─ app.css
│ ├─ App.tsx
│ ├─ index.css
│ ├─ main.tsx
│ └─ vite-env.d.ts
├─.gitignore
├─ CHANGELOG.md
├─ eslint.config.js
├─ Index.html
├─ nuget.config
├─ package.json
├─ reactproject1.esproj
├─ reactproject1.sln
├─ README.md
├─ tsconfig.app.json
├─ tsconfig.json
├─ tsconfig.node.json
└─ vite.config.js
如果您不选择“将解决方案和项目放在同一目录中”选项,这是传统的项目组织方式
您的文件和目录将如下所示:
reactproject1/
├─ .vs/
├─ reactproject1/
│ ├─ .vscode/
│ ├─ public/
│ │ └─ vite.svg
│ ├─ src/
│ │ ├─ assets/
│ │ │ └─ react.svg
│ │ ├─ app.css
│ │ ├─ App.tsx
│ │ ├─ index.css
│ │ ├─ main.tsx
│ │ └─ vite-env.d.ts
│ ├─.gitignore
│ ├─ CHANGELOG.md
│ ├─ eslint.config.js
│ ├─ Index.html
│ ├─ nuget.config
│ ├─ package.json
│ ├─ reactproject1.esproj
│ ├─ vite.config.js
│ ├─ README.md
│ ├─ tsconfig.app.json
│ ├─ tsconfig.json
│ ├─ tsconfig.node.json
│ └─ vite.config.js
└─ reactproject1.sln
我的解决方案应该放在哪里?
在 VS 中,一个解决方案可以包含多个项目。一个典型的例子是 n 层或 3 层应用程序,有时称为全栈应用程序。此应用程序通常至少包含一个数据库项目、API 项目和 Web 前端项目(例如 React 项目)。当 VS 解决方案包含多个项目时,您可能希望将解决方案保留在文件夹结构的最顶层,并将每个项目放在其自己的子文件夹中,因此我更喜欢将解决方案放在项目之外的单独文件夹中。
MySolution/
├─ MySolution.Database/
│ ├─ mysolution.database.sqlproj
│ └─ …
├─ MySolution.API/
│ ├─ mysolution.api.csproj
│ └─ …
├─ MySoution.WFE/
│ ├─ mysolution.wfe.esproj
│ └─ …
└─ mysolution.sln
注意:VS 中的一个项目可以包含在多个解决方案中。这取决于您的开发需求。例如,在一个包含 30、40 个甚至更多 VS 项目的大型项目中,每个项目可能不会引用所有其他项目,因此您不希望所有代码同时加载到 VS 中。您可以将项目分组到仅包含相互引用的项目的解决方案中。在这种情况下,我会在上一个示例文件夹结构中的根文件夹:MySolution/ 中存储多个 .sln 解决方案文件。
什么是 Vite?
现在您已经创建了一个新的 VS 项目,您需要了解您创建的内容。VS 本身无法托管 React Web 应用程序。最新的 React 模板使用 Vite 在 Node.js 之上托管 Web 应用程序。
那么,什么是 Vite 呢?
没有必要重复造轮子,所以这是 Vite 网站上概述的第一部分:
引用Vite(法语“快速”的意思,发音为 /vit/,听起来像“veet”)是一个构建工具,旨在为现代 Web 项目提供更快、更精简的开发体验。它包含两个主要部分:
- 一个开发服务器,它比原生 ES 模块提供丰富的特色增强,例如极快的热模块替换 (HMR)。
- 一个构建命令,它使用Rollup捆绑您的代码,预先配置为输出高度优化的生产用静态资源。
Visual Studio 为什么/如何使用 Vite?
VS 将 Vite 用作托管平台。当您按 F5 调试应用程序时,VS 会启动 Vite,Vite 会将您的 .ts、.tsx 或 .jsx 代码、scss 等转换为可在浏览器中运行的标准 HTML、JavaScript 和 CSS。它还有更多功能,但您已了解其大致作用。
开始调试或按 F5
那么,当您在 VS 中按 F5 时会发生什么?
答案是:这取决于。如果您没有修改 VS 项目中的设置,VS 将调用 npm run dev
。
dev
是您 React 项目的 package.json 文件中配置的一个脚本。如果您查看该文件,您会看到类似以下内容:
{
…
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
},
…
}
要查看 VS 按 F5 时调用的内容,您可以:
- 右键单击“解决方案资源管理器”窗格中的项目名称,然后选择“属性”。
- 从导航列表中选择“部署”,然后选择“常规”。
- 从“启动命令”文本框中获取命令。
如果您愿意,可以按以下方法进行测试:
- 右键单击项目名称,然后选择“在终端中打开”。
- 在命令提示符处输入“启动命令”(
npm run dev
),然后按 Enter 键。
您将看到与通常在新控制台窗口中打开的 Vite 启动相同的输出。
复制终端中“本地:”旁边的 URL(例如,上面屏幕截图中的https://:5173/),将其粘贴到新浏览器标签页的地址栏中,然后按 Enter 键。您应该会看到您的 React 应用程序。
停止 Vite
- 选择运行 Vite 的“开发人员 PowerShell”终端。
- 按 Ctrl + c
- 在“终止批处理作业 (Y/N)?”消息处键入 Y,然后按 Enter。
注意:如果您在浏览器的开发人员工具中检查源文件,您会注意到浏览器似乎直接与 VS 中的文件相同,但实际上并非如此。这是 Vite 的强大功能,可帮助您实时调试源代码,同时将代码转换为 HTML 和 JavaScript 以在浏览器中显示。
注意:您的网站运行的端口号在项目 .vscode 目录中的 launch.json 文件中配置。
生成项目
那么,当您在项目级别运行生成时会发生什么?
即,当您右键单击项目名称并选择“生成”时会发生什么?
答案再次是:这取决于。与调试一样,您可以更改 VS 在生成项目时所做的操作。但是,React 类型项目的默认操作在项目属性中不可见。默认情况下,VS 将运行类似 npm install
的命令,该命令将确保您的所有项目节点模块已下载并根据项目 package.json 文件中的“依赖项”和“开发依赖项”设置保持最新。
要查看 VS 在开始生成项目时调用的内容,您可以:
- 右键单击“解决方案资源管理器”窗格中的项目名称,然后选择“属性”。
- 从导航列表中选择“生成”,然后选择“常规”。
- 从“生成命令”文本框中获取命令,但默认情况下它是空的。
在 .esproj 项目文件中还有一个隐藏设置,可以更改生成命令的行为。该设置名为 ShouldRunBuildScript,它是一个布尔值,值为 true
或 false
。默认值为 false。
默认值
<ShouldRunBuildScript>false</ShouldRunBuildScript>
要在 VS 中查看 .esproj 文件:
- 右键单击“解决方案资源管理器”窗格中的项目名称,然后选择“编辑项目文件”。
如果将 ShouldRunBuildScript
设置为 true,VS 将在 npm install
命令之后运行 npm run build
命令。与调试一样,build
是您 React 项目的 package.json 文件中配置的一个脚本。默认情况下,VS package.json 配置为运行 tsc -b && vite build
。
默认的生成脚本包含两个按顺序运行的命令:
- tsc -b
- vite build
tsc -b
将编译/生成项目中的 TypeScript。
请参阅:TypeScript:文档 - tsc CLI Options (typescript.org)
当 vite build
运行时,Vite 会将您的项目文件转换为一个静态 Web 应用程序,该应用程序由 HTML、JavaScript、CSS 和支持的工件(如图像)组成。
这些生成的文件的保存位置由项目的“生成输出文件夹”属性指示。
要查看项目的生成输出目录,您可以:
- 右键单击“解决方案资源管理器”窗格中的项目名称,然后选择“属性”。
- 从导航列表中选择“生成”,然后选择“常规”。
- 从“生成输出文件夹”文本框中获取命令。
默认情况下,“生成输出文件夹”属性设置为 $(MSBuildProjectDirectory)\dist
。这意味着生成的文件的位置是项目目录根目录下的“dist”文件夹。如果该文件夹不存在,则会自动创建。
在标准的解决方案文件夹结构中,解决方案文件未包含在项目文件夹内,如下所示:
reactproject1/
├─ .vs/
├─ reactproject1/
│ ├─.vscode/
│ ├─ dist/
│ │ ├─ assets/
│ │ │ ├─ index-<hash>.css
│ │ │ ├─ index-<hash>.js
│ │ │ └─ react-<hash>.svg
│ │ ├─ index.html
│ │ └─ vite.svg
│ ├─ public/
│ ├─ src/
│ ├─.gitignore
│ └─ …
└─ reactproject1.sln
文件的确切数量和名称将取决于您开发网站的方式。例如,如果您为网站添加了本地化并将翻译存储在其他 .json 文件中,只要这些文件被添加到 public 或 src 文件夹内或下方,它们及其文件夹结构就会被添加到“dist”目录中。
注意:如果您的项目已连接到 Azure DevOps 或 Git 存储库,默认情况下,“dist”文件夹不会(也不应该)上传到存储库。每个开发人员都应该在需要时生成自己的 dist 文件,并且尽可能频繁地生成。此设置在项目根目录的 .gitignore 文件中。如果您的项目没有 .gitignore 文件,您可以自己添加一个。文件名就是 .gitignore,没有前缀或其他文件类型后缀。
VS React 项目的 .gitignore 文件的默认条目是:
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
预览
您可能已经注意到 package.json 文件中有一个名为“preview”的脚本。VS 中没有调用此脚本的命令,但您可以使用 npm run preview
自己运行它。您必须先运行 npm run build
才能运行 preview 命令。
preview 命令将使用 Vite 通过“dist”文件夹中的文件来托管您的应用程序。因此,它会重现您的应用程序在生产环境中运行时在外观看似和行为。
默认情况下,预览站点托管在端口 4173 上。VS 模板文件中没有此端口号的设置。
与上面详细介绍的运行 npm run dev
命令一样,复制终端中“本地:”旁边的 URL(例如,上面屏幕截图中的https://:4173/),将其粘贴到新浏览器标签页中,然后按 Enter 键。您应该会看到您的 React 应用程序。
可以通过修改 preview 脚本在 package.json 文件中设置 preview 端口号,但似乎存在防火墙或其他网络设置阻止您访问该站点。我还没有深入研究以找出问题所在。我怀疑这可能是 Windows 防火墙设置。如果是这种情况,您的行为可能会有所不同,具体取决于您设置的防火墙规则。设置端口 80 或 443 可以工作。
"preview": "vite preview –port 80",
虽然我没有尝试过,但据说您可以在 vite.config.ts 文件中使用类似以下内容设置 preview 端口:
export default defineConfig({
preview: {
port: 8080
}
})
请参阅:reactjs - 如何设置 Vite (preview) 生产端口?- Stack Overflow
Lint
最后一个脚本是“lint”。这不会影响您的应用程序部署到 Azure 静态 Web 应用,但我在此提及以求完整性。ESLint 是一个用于标识和报告 ECMAScript/JavaScript 代码中发现的模式的工具。运行命令 npm run lint
会导致 VS 检查您的代码是否存在潜在错误和代码风格问题。您不需要运行此命令,因为 VS 在您进行更改时会持续为您进行 linting。这就是在 React 项目中给您的代码打上波浪线的原因。linting 检查的内容高度可配置,并且本身就是一个庞大的主题。
将 React 项目添加到 Azure DevOps 存储库
我不会详细介绍如何设置 Azure DevOps 项目或存储库,因为它们超出了本博客的范围。但是,我认为值得注意的是,您可以使用 VS 用户界面轻松地将 VS 解决方案添加到现有存储库。
您需要做的第一件事是登录到 VS,使用一个对您想要添加解决方案的 Azure DevOps 项目和存储库具有权限的帐户。
- 从 VS 右上角选择“登录”按钮。
- 在“登录”对话框中,选择合适的帐户,然后选择“继续”按钮。
- (可选)如果您像我一样,您的帐户可以访问多个 Azure 租户(客户、开发、B2C 等),您可能需要取消选择您不进行开发的租户。这有助于限制 VS 在处理 Azure 相关资源(例如部署到 Azure 或选择 Azure DevOps 组织)时向您显示的数量。
您通过以下方式执行此操作:- 选择替换步骤 1 中“登录”按钮的图标。
- 选择您帐户图片下方的“帐户设置”链接。
- 在“帐户设置”对话框中,选择您刚刚登录的帐户旁边的“应用筛选器…”链接。
- 在“筛选帐户”对话框中,从可用租户列表中取消选择您不想开发的租户,然后选择“应用”按钮。
- 选择“帐户设置”对话框中的“关闭”按钮。
- 选择 VS 右下角的“添加到源控件”按钮,然后选择“Git”。
- 在“创建 Git 存储库”对话框中:
- 选择“Azure DevOps”选项。
- 确保将“默认 (VisualStudio)”选为“.gitignore 模板”。
- (可选)选择“许可证模板”。
- (可选)选择“添加 README.md”选项。这将在新存储库的根目录中添加一个 read-me markdown 文件。如果您已将解决方案添加到项目目录的同一目录中,请不要选择此选项。该位置已存在 README.md 文件。
- 确保选择了正确的“帐户”。这应默认为您登录的帐户。
- 从下拉列表中选择 Azure DevOps “组织”。如果您的组织未列出,请检查:
- 您已使用正确的帐户登录。
- 已选择正确的帐户。
- 您的帐户对 Azure DevOps 组织具有必需的权限。
- 从下拉列表中选择 Azure DevOps “项目”。
- 输入“存储库名称”或接受默认名称。
- 选择“创建并推送”按钮。
- 让 Visual Studio 花点时间处理您的更改并将您的代码推送到新存储库。
注意:此方法会导致第一个分支命名为 **master**。如果您希望主分支名为 main,则需要关闭 VS,在浏览器中导航到您的 Azure DevOps 实例,创建一个新分支,删除旧分支,重新打开 VS,然后从左下角(上方图片中显示 master 的位置)选择新分支。总之,这有点麻烦。
生产环境托管
在生产环境中,您不会在 Vite 之上运行应用程序。这就是 npm run build
创建的“dist”文件夹及其内容的作用。您不能简单地导航到“dist”文件夹并双击 index.html 来运行您的应用程序。您需要从一个合适的 Web 服务器托管这些文件。
测试生产代码(无 Vite)
为了进行此测试,我将使用一些老式的方法,但这是我所熟悉的。如果您安装了 IIS(Internet Information Services),您可以在没有 Vite 的情况下测试运行应用程序的生产文件。
- 右键单击“解决方案资源管理器”窗格中项目下方的“dist”文件夹名称,然后选择“在文件资源管理器中打开文件夹”。
- 从 Windows 资源管理器的地址栏复制到该文件夹的完整路径。
它应该类似于:
C:\Users\<username>\source\repos\ReactProject1\ReactProject1\dist
- 打开 IIS 管理器
- 按 Windows 键 + R
- 在“打开:”文本框中键入 inetmgr.exe。
- 选择“确定”按钮。
- 在左侧的“连接”窗格中,展开服务器(计算机名称)节点和“网站”节点。
- 右键单击“网站”节点,然后选择“添加网站”。
- 在“添加网站”对话框中输入以下详细信息:
- 网站名称:为您应用程序起的任何合适名称。
- 物理路径:步骤 2 中复制的路径。
- 端口:任何未被其他网站或服务使用的端口号。
如果这是您托管的唯一网站,请使用 80;否则,请尝试 8080 或 6173。
- 选择“确定”按钮创建网站。
- 在左侧的“连接”窗格中选择新网站的名称。
- 在右侧窗格的“浏览网站”下方,选择“浏览 *.<端口> (http)”链接。
如果一切顺利,您应该会在默认浏览器中看到您的应用程序弹出。
注意:这些说明是测试 Web 应用程序所需的最基本要求。IIS 网站托管是另一个庞大的主题,与本文无关。
此测试演示了运行 React 应用程序所需的条件。此时,构成 VS 项目的“dist”文件夹之外的其他文件均未使用。Azure 静态 Web 应用将在生产环境中取代 IIS。
创建 Azure 静态 Web 应用
这些说明将向您展示如何使用 Azure 门户用户界面创建 Azure 静态 Web 应用。
- 在浏览器中打开 Azure 门户 (https://portal.azure.com/)
- 请确保使用具有对您的 React 应用存储库所在 Azure DevOps 项目的访问权限的帐户登录。您的帐户还需要在 Azure DevOps 项目中具有添加文件到存储库和创建 Azure DevOps Library 条目的适当权限。
- 从主页顶部选择“+ 创建资源”按钮。
- 在“搜索服务和市场”搜索框中键入azure static web app,然后按 Enter 键。
- 从“静态 Web 应用”服务结果中选择“创建”,然后选择“静态 Web 应用”。
- 在“创建静态 Web 应用”表单的“基础知识”选项卡上:
- 确保选择了正确的“订阅”。
- 在“资源组”下拉列表下方选择“创建新项”。
- 为新的资源组输入一个名称。例如:mc-reactproject1-rg
注意:我倾向于使用 <我的首字母>-<项目名称>-rg 作为资源组名称。 - 选择“确定”按钮关闭新的资源组弹出窗口。
- 为您的静态 Web 应用输入一个“名称”。例如:ReactProject1
- 选择合适的“计划”类型。免费版适合演示或试用。通常,您会选择标准版,除非您对新的专用版有特定需求。
- 从“源”列表中选择“Azure DevOps”。
- 选择 Azure DevOps “组织”。
- 选择 Azure DevOps “项目”。
- 选择 Azure DevOps “存储库”。
- 选择 Azure DevOps “分支”。
- 从“生成预设”列表中选择“React”。
- 如果您的解决方案文件和项目文件位于不同的文件夹中,请在“应用位置”文本框中输入/<项目名称>。
如果您的解决方案文件和项目在同一个文件夹中,请在“应用位置”文本框中输入 /。 - 由于我们不消耗任何外部 API,请将“API 位置”留空。
- 在“输出位置”文本框中输入dist。
- 选择“下一步:高级 >”按钮。
- 在“创建静态 Web 应用”表单的“高级”选项卡上:
- 选择离您最近的区域。
- 选择“下一步:标记 >”按钮。
- 在“创建静态 Web 应用”表单的“标记”选项卡上:
- 输入您通常创建的任何标记的名称。例如:Environment
- 输入标记的值。例如:Development
- 对所有必需的标记重复步骤 a 和 b。
- 选择“下一步:审查 + 创建 >”按钮。
- 在“创建静态 Web 应用”表单的“审查 + 创建”选项卡上:
- 检查页面上显示的信息。
- 选择“创建”按钮开始创建资源的进程。
- 您将被重定向到新资源的部署页面。如果一切顺利,“转到资源”按钮将会出现。选择“转到资源”按钮。
- 您应该会看到新静态 Web 应用的“概览”页面。
- 选择“URL”链接以查看新网站的默认内容。
您应该会在浏览器中看到您的 React 应用,如果您点击中间的计数按钮,您应该会看到计数器递增。
如果您没有立即看到您的 React 应用,可能是因为 Azure DevOps 中的新 CI/CD 管道尚未完成运行。稍等几分钟(通常不到 2 分钟),然后刷新浏览器标签页。
调查 CI/CD 管道
Azure 门户中的“创建静态 Web 应用”向导已为您创建了一个 YAML 管道文件,并将其添加到您指定的 Azure DevOps 项目的根目录中。
管道文件可能会被命名为类似:
azure-static-web-apps-<random>-<random>-<random>.yml
它将包含类似以下的脚本:
name: Azure Static Web Apps CI/CD
pr:
branches:
include:
- master
trigger:
branches:
include:
- master
jobs:
- job: build_and_deploy_job
displayName: Build and Deploy Job
condition: or(eq(variables['Build.Reason'], 'Manual'),or(eq(variables['Build.Reason'], 'PullRequest'),eq(variables['Build.Reason'], 'IndividualCI')))
pool:
vmImage: ubuntu-latest
variables:
- group: Azure-Static-Web-Apps-ambitious-bush-02470c603-variable-group
steps:
- checkout: self
submodules: true
- task: AzureStaticWebApp@0
inputs:
azure_static_web_apps_api_token: $(AZURE_STATIC_WEB_APPS_API_TOKEN_AMBITIOUS_BUSH_02470C603)
###### Repository/Build Configurations These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: "/reactproject1" # App source code path
api_location: "" # Api source code path - optional
output_location: "dist" # Built app content directory - optional
###### End of Repository/Build Configurations ######
简而言之:
- 管道的显示名称是**Azure 静态 Web 应用 CI/CD**。
- 它有一个针对存储库 master 分支的拉取请求触发器。
- 它有一个针对 master 分支的推送触发器。
- 它有一个阶段(隐含)和一个作业,其显示名称为生成和部署作业。
- 该管道在 Microsoft 提供的最新 Ubuntu Linux 生成代理虚拟机上运行。
- 它使用一个名为 azure-static-web-apps-<random>-<random>-<random>-variable-group 的变量组中的变量,该变量组存储在**管道** > **库** > **变量组**中。
- 该组有一个变量,即您的 Azure 静态 Web 应用的部署令牌。
- 该作业按顺序执行两个操作:**checkout**,然后是一个 **AzureStaticWebApp@0** 任务,前提是 Build.Reason 变量是以下值之一:
- 手动
- PullRequest
- IndividualCI
- checkout 操作将从您的主分支获取最新文件,并将其添加到生成代理的工作目录中。
- AzureStaticWebApp@0 任务将:
- 从 **app_location** 指示的目录开始。这相对于工作目录。
- 它将使用 Oryx 处理工作目录中的文件:
“Oryx 是一个构建系统,可以自动将源代码存储库编译成可运行的工件。它用于为Azure 应用服务和其他平台构建 Web 应用。”
(microsoft/Oryx:自动构建您的存储库。(github.com))。
它将运行npm install
,然后运行npm run build
。 - Oryx 将验证生成文件是否在 **output_location** 文件夹中。
- 由于 **api_location** 设置为“”,Oryx 不会尝试处理 API。
- 它将创建一个包含 **output_location** 文件夹中文件的 zip 文件,并使用变量组中的部署令牌将其部署到您的 Azure 静态 Web 应用。
注意:Build.Reason 是一个预定义管道变量(预定义变量 - Azure Pipelines | Microsoft Learn)。它包含一个值,该值指示导致生成管道运行的事件。
有关 **AzureStaticWebApp@0** 任务的更多信息,请参阅Azure 静态 Web 应用的生成配置 | Microsoft Learn。
由“创建静态 Web 应用”向导创建的变量组包含一个名为 AZURE_STATIC_WEB_APPS_API_TOKEN_<random>_<random>_<random> 的单个变量。
该变量受保护,因此您无法在库中查看其值。
- 在浏览器中打开 Azure DevOps。
- 从左侧菜单中选择“管道”,然后选择“库”。
- 从变量组列表中选择所需的变量组。
如果由于身份验证原因,Azure DevOps 管道与您的 Azure 静态 Web 应用之间的访问开始失败,您可能需要替换此值。
尽管变量将其称为 Azure 静态 Web 应用 API 令牌,但 Microsoft 的文档和 Azure UI 将其称为部署令牌。要获取当前部署令牌或生成新令牌:
- 打开Azure 门户。
- 在主页顶部中央的搜索框中输入 Static Web App,然后在“服务”标题下方选择“静态 Web 应用”。
- 从可用 Web 应用列表中选择您的 Web 应用。
- 在“概览”页面的顶部菜单栏中选择“管理部署令牌”。
- 在右侧出现的“管理部署令牌”面板中:
- (可选)选择“重置令牌”按钮以生成新令牌。
- 选择复制图标以复制现有令牌。
Microsoft 在此处详细介绍了该过程:重置 Azure 静态 Web 应用中的部署令牌 | Microsoft Learn
创建自己的 CI/CD 管道
有时您可能不希望 Oryx 生成您的项目,例如:
- Oryx 可能无法生成您的项目。
- 您可能希望在生成和部署之间进行其他测试。
- 您可能希望生成一个已部署文件的包,以供管道中的其他地方使用。
在这些情况下,我们可以根据从生成的管道中学到的知识来构建自己的 YAML 管道。
name: Azure Static Web Apps Custom CI/CD
pr:
branches:
include:
- main
trigger:
branches:
include:
- main
stages:
- stage: Build # The first stage runs on an Ubuntu Linux build agent provided by Microsoft
displayName: Build stage
jobs:
- job: Build
displayName: Build
condition: or(eq(variables['Build.Reason'], 'Manual'),or(eq(variables['Build.Reason'],'PullRequest'),eq(variables['Build.Reason'], 'IndividualCI')))
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0 # Ensure Node.js is available on the agent
inputs:
versionSpec: '20.x' # Use Node.js version 20.x (or adjust to your preferred version)
displayName: 'Install Node.js'
# Run commands to restore node.js modules and build
# Copy the dist directory to the staging directory
- script:
echo "##### Current working directory: $PWD"
echo '##### npm install:'
npm install
echo "##### List node_modules dir contents:"
ls node_modules
echo '##### npm run build --if-present:'
npm run build --if-present
echo "##### List working dir contents:"
ls
echo "##### List dist dir contents:"
ls dist
echo '##### npm run test --if-present:'
npm run test --if-present
echo "##### copy the $PWD/dist directory to staging: $(Build.ArtifactStagingDirectory)"
cp -r $PWD/dist $(Build.ArtifactStagingDirectory)
echo "##### List $(Build.ArtifactStagingDirectory)/dist dir contents:"
ls $(Build.ArtifactStagingDirectory)/dist
displayName: 'Build Vite React App'
workingDirectory: '$(System.DefaultWorkingDirectory)/reactproject1'
- task: PublishBuildArtifacts@1 # Package everything in the staging directory into a package called drop
displayName: 'Publish Build Artifacts'
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: 'drop'
- stage: Deploy # The second stage will run on another build agent
displayName: Deploy stage
dependsOn: Build
condition: succeeded()
jobs:
- job: Deploy
displayName: Deploy
condition: succeeded()
pool:
vmImage: ubuntu-latest
variables:
- group: React-i18next-Library
steps:
- task: DownloadPipelineArtifact@2 # Download the drop package created in the previous stage
displayName: 'Download Build Artifacts'
inputs:
artifact: drop
downloadPath: $(System.ArtifactsDirectory)
- task: AzureStaticWebApp@0 # Deploy the dist directory to Azure Static Web App without building
inputs:
workingDirectory: $(System.ArtifactsDirectory)
azure_static_web_apps_api_token: $(StaticWebAppToken)
skip_app_build: true
app_location: "dist"
api_location: ""
output_location: ""
此管道有两个阶段。使用 Microsoft 提供的生成代理(vmImage:'ubuntu-latest')时,这两个阶段将在不同的虚拟机上运行,即每个阶段都会启动一个新虚拟机。因此,我们需要将任何希望在生成代理之间共享的文件添加到已发布的包中。
第一个阶段负责从我们的项目生成分发文件。存储库文件默认添加到生成代理的工作目录中;我没有添加一个步骤来执行此操作。
第一步确保将 Node.js 添加到生成代理(NodeTool@0)。
接下来,我们运行一些 Linux bash 命令 npm install
和 npm run build
来生成我们的项目的生产文件(script)。请注意,workingDirectory 设置为项目名称,因为我没有将解决方案文件存储在项目目录中。如果您的解决方案文件和项目文件在同一个文件夹中,您将使用 workingDirectory: '$(System.DefaultWorkingDirectory)。
在生成命令之后,script 将 dist 文件夹复制到工件暂存目录 ($(System.ArtifactsDirectory))。
我还添加了许多目录列表命令到 script 中,以便在 Azure DevOps 管道日志中显示目录的内容。我认为这是调试 YAML 管道的一种有用技术。
注意:如果您想在 Windows 生成代理上运行管道,这些命令仍然可以正常工作,但请记住,脚本将运行 PowerShell 命令。
脚本完成后,我们运行一个步骤来压缩暂存目录中的所有等待文件,将其打包为名为 drop 的包,然后将其发布到 Azure DevOps (PublishBuildArtifacts@1)。
第二个阶段负责将生产文件部署到 Azure 静态 Web 应用。因为这是一个新阶段,您可能需要等待一段时间才能获得可用的生成作业槽并创建生成代理。等待时间的长短取决于您的 Azure DevOps 环境配置使用的并发作业数量。
此阶段所做的第一件事是下载我们在第一个阶段创建的名为 drop 的包,并将其解压到工件目录 (DownloadPipelineArtifact@2)。
最后一步是运行 AzureStaticWebApp@0 任务,并设置正确的参数以发布文件到 Azure 静态 Web 应用,而不运行生成。请参阅Azure 静态 Web 应用的生成配置 | Microsoft Learn(跳过生成前端应用)。
注意:管道运行完成后,您可以将包下载到您的计算机。在 Azure DevOps 中,选择管道名称,然后选择您想要获取包的实例/运行。您将在标题数据中间的“相关”项下找到该包。选择“n 已发布”链接,您就可以浏览包的内容并下载任何您需要的文件。
结论
如果您一直读到这里,感谢您的坚持。一旦您了解了 Visual Studio 中的 React 是做什么的,以及“创建静态 Web 应用”向导创建了什么,您就能非常轻松地确定应用程序和输出文件位置应该选择什么值。
我知道我在本文中涵盖了很多主题,但我想确保本文可以独立作为您开始将 Visual Studio 的 React 应用程序部署到 Azure 静态 Web 应用(使用 Azure DevOps)之旅的单一起点。我认为,找不到比发现一篇看似能回答您的问题的文章,但又发现其中一半信息已在其他不再可用的文章中更令人沮丧的事情了。