为 Azure Pipelines 自定义 JavaScript
可以使用 Azure Pipelines 生成 JavaScript 应用,而无需设置自己的任何基础结构。 通常用于生成、测试和运行 JavaScript 应用(如 npm、Node、Yarn 和 Gulp)的工具将预安装在 Azure Pipelines 中的 Microsoft 托管代理上。
有关预安装的 Node.js 和 npm 版本,请参阅 Microsoft 托管代理。 要在 Microsoft 托管的代理上安装这些工具的特定版本,请将“Node 工具安装程序”任务添加到进程的开头。 你还可以使用自托管代理。
若要使用 JavaScript 创建第一个管道,请参阅 JavaScript 快速入门。
使用特定版本的 Node.js
如果 Microsoft 托管代理上没有安装需要的 Node.js 和 npm 版本,请使用 Node 工具安装程序任务。 要将以下代码片段添加到 azure-pipelines.yml
文件。
注意
托管代理会定期更新,设置此任务会导致在每次运行管道时花费大量时间更新到较新的次要版本。 仅在管道中需要特定 Node 版本时使用此任务。
- task: UseNode@1
inputs:
version: '16.x' # replace this value with the version that you need for your project
如果代理上没有安装需要的 Node.js/npm 版本:
在管道中,选择“任务”,选择运行生成任务的阶段,然后选择 + 将新任务添加到该阶段。
在任务目录中,查找并添加“Node 工具安装程序”任务。
选择任务并指定要安装的 Node.js 运行时版本。
要仅更新 npm 工具,请在生成过程中运行 npm i -g npm@version-number
命令。
使用多个节点版本
可以使用“Node 工具安装程序”任务在多个版本的 Node 上生成和测试应用。
pool:
vmImage: 'ubuntu-latest'
strategy:
matrix:
node_16_x:
node_version: 16.x
node_13_x:
node_version: 18.x
steps:
- task: UseNode@1
inputs:
version: $(node_version)
- script: npm install
请参阅多配置执行。
在生成代理上安装工具
如果项目 package.json
或 package-lock.json
文件中具有开发依赖项的工具,请通过 npm 安装工具和依赖项。 工具的确切版本在项目中定义,独立于生成代理上存在的其他版本。
使用脚本与 package.json 一起安装
- script: npm install --only=dev
使用 npm 任务与 package.json 一起安装
- task: Npm@1
inputs:
command: 'install'
使用 npm npx
包运行器以这种方式运行安装的工具,该运行器在其路径解析中检测以这种方式安装的工具。 以下示例调用 mocha
测试运行程序,但在使用全局安装的(通过 npm install -g
)版本之前,会查找作为开发依赖项安装的版本。
- script: npx mocha
若要安装项目需要但未在 package.json
中设置为开发依赖项的工具,请从管道中的脚本阶段调用 npm install -g
。
以下示例使用 npm
安装最新版本的 Angular CLI。 然后,管道的其余部分可以从其他 script
阶段使用 ng
工具。
注意
在 Microsoft 托管的 Linux 代理上,在命令前面加上 sudo
,例如 sudo npm install -g
。
- script: npm install -g @angular/cli
提示
这些任务在管道每次运行时都会运行,因此请注意安装工具对生成时间的影响。 如果开销严重影响生成性能,请考虑使用所需工具版本配置自托管代理。
管理依赖项
在生成中,使用 Yarn 或 Azure Artifacts 从公共 npm 注册表下载包。 此注册表是在 .npmrc
文件中指定的一种专用 npm 注册表。
使用 npm
可以通过以下方式使用 npm 下载生成的包:
- 直接在管道中运行
npm install
,因为这是从注册表下载包而无需身份验证的最简单方法。 如果生成不需要代理上的开发依赖项就能运行,则可以使用--only=prod
选项进行npm install
来加快生成时间。 - 使用 npm 任务。 使用经过身份验证的注册表时,此任务非常有用。
- 使用 npm 身份验证任务。 从任务运行程序(Gulp、Grunt 或 Maven)内部运行
npm install
时,此任务非常有用。
如果要指定 npm 注册表,请将 URL 放入存储库的 .npmrc
文件中。
如果源经过身份验证,请在“项目设置”中的“服务”选项卡上创建 npm 服务连接,以管理其凭据。
要在管道中使用脚本安装 npm 包,请将以下代码片段添加到 azure-pipelines.yml
。
- script: npm install
要使用 .npmrc
文件中指定的专用注册表,请将以下代码片段添加到 azure-pipelines.yml
。
- task: Npm@1
inputs:
customEndpoint: <Name of npm service connection>
要通过任务运行程序(如 Gulp)将注册表凭据传递给 npm 命令,请在调用任务运行程序之前将以下任务添加到 azure-pipelines.yml
。
- task: npmAuthenticate@0
inputs:
customEndpoint: <Name of npm service connection>
如果从 npm 注册表还原包时,生成偶尔因连接问题而失败,则可以将 Azure Artifacts 与上游源配合使用,并缓存包。 连接到 Azure Artifacts 时,会自动使用管道的凭据。 这些凭据通常派生自“项目集合生成服务”帐户。
如果使用 Microsoft 托管代理,则每次运行生成时都会获得一台新计算机,这意味着每次都还原依赖项,这可能需要很长时间。 若要缓解问题,可以使用 Azure Artifacts 或自托管代理 - 然后,便可体会到使用包缓存的好处。
使用 Yarn
使用脚本阶段调用 Yarn 以还原依赖项。 Yarn 将预安装在某些 Microsoft 托管代理上。 可以像任何其他工具一样在自托管代理上安装和配置它。
- script: yarn install
运行 JavaScript 编译器
使用编译器(如 Babel 和 TypeScript tsc
编译器)将源代码转换为Node.js运行时或 Web 浏览器中可使用的版本。
如果在运行编译器的项目 package.json
文件中设置了脚本对象,请使用脚本任务在管道中调用它。
- script: npm run compile
可以使用脚本任务直接从管道调用编译器。 这些命令从克隆的源代码存储库的根目录运行。
- script: tsc --target ES6 --strict true --project tsconfigs/production.json
运行单元测试
配置管道以运行 JavaScript 测试,以便生成采用 JUnit XML 格式的结果。 然后,可以使用内置的发布测试结果任务发布结果。
如果测试框架不支持 JUnit 输出,请通过合作伙伴报告模块(如 mocha-junit-reporter)添加支持。 可以更新测试脚本以使用 JUnit 报告器,或者如果报告器支持命令行选项,请将这些选项传递到任务定义中。
下表列出了可用于生成 XML 结果的最常用的测试运行程序和报告器:
测试运行程序 | 生成 XML 报表的报告器 |
---|---|
mocha | mocha-junit-reporter cypress-multi-reporters |
jasmine | jasmine-reporters |
jest | jest-junit jest-junit-reporter |
karma | karma-junit-reporter |
Ava | tap-xunit |
以下示例使用 mocha-junit-reporter,并使用脚本直接调用 mocha test
。 此脚本在 ./test-results.xml
的默认位置生成 JUnit XML 输出。
- script: mocha test --reporter mocha-junit-reporter
如果在项目 package.json 文件中定义了 test
脚本,则可以使用 npm test
调用它。
- script: npm test
发布测试结果
要发布结果,请使用发布测试结果任务。
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testRunner: JUnit
testResultsFiles: '**/test-results.xml'
发布代码覆盖率结果
如果测试脚本运行代码覆盖率工具(如 Istanbul),请添加发布代码覆盖率结果任务。 执行此操作时,可以在生成摘要中找到覆盖率指标,并下载 HTML 报告以供进一步分析。 该任务需要 Cobertura 或 JaCoCo 报告输出,因此请确保代码覆盖率工具使用必要的选项运行以生成正确的输出。 例如,--report cobertura
。
以下示例使用 nyc(Istanbul 命令行接口)以及 mocha-junit-reporter 并调用 npm test
命令。
- script: |
nyc --reporter=cobertura --reporter=html \
npm test -- --reporter mocha-junit-reporter --reporter-options mochaFile=./test-results.xml
displayName: 'Build code coverage report'
- task: PublishCodeCoverageResults@2
inputs:
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/*coverage.xml'
端到端测试浏览器
使用 Protractor 或 Karma 等工具在无界面浏览器中作为管道的一部分运行测试。 然后,使用以下步骤将生成的结果发布到 Azure DevOps:
- 在生成代理上安装无界面浏览器测试驱动程序(如无界面 Chrome 或 Firefox)或浏览器模拟工具(如 PhantomJS)。
- 根据工具的文档,将测试框架配置为使用所选的无界面浏览器/驱动程序选项。
- 配置测试框架(通常使用报告器插件或配置)来输出 JUnit 格式的测试结果。
- 设置脚本任务以运行启动无界面浏览器实例所需的任何 CLI 命令。
- 在管道阶段以及单元测试中运行端到端测试。
- 将发布测试结果任务与单元测试一起使用以发布结果。
打包 Web 应用
打包应用,以将所有具有中间输出和依赖项的应用模块捆绑到可供部署的静态资产中。 在编译和测试后添加管道阶段,以使用 Angular CLI 运行 webpack 或 ng 生成等工具。
第一个示例调用 webpack
。 为此,请确保 webpack
在 package.json 项目文件中配置为开发依赖项。 这样将使用默认配置运行 webpack
,除非项目根文件夹中有文件 webpack.config.js
。
- script: webpack
下一个示例使用 npm 任务调用 npm run build
来调用项目 package.json 中定义的 build
脚本对象。 在项目中使用脚本对象会将生成的逻辑移入源代码并移出管道。
- script: npm run build
实施 JavaScript 框架
Angular
对于 Angular 应用,可以包含 Angular 特定的命令,例如 ng test、ng build 和 ng e2e。 要在管道中使用 Angular CLI 命令,请在生成代理上安装 angular/cli npm 包。
注意
在 Microsoft 托管的 Linux 代理上,在命令前面加上 sudo
,例如 sudo npm install -g
。
- script: |
npm install -g @angular/cli
npm install
ng build --prod
将以下任务添加到管道:
npm
- 命令:
custom
- 命令和参数:
install -g @angular/cli
- 命令:
npm
- 命令:
install
- 命令:
bash
- 类型:
inline
- 脚本:
ng build --prod
- 类型:
对于管道中需要浏览器运行的测试(例如运行 Karma 的启动器应用中的 ng test 命令),请使用无界面浏览器而不是标准浏览器。 在 Angular 启动器应用中:
将 karma.conf.js 项目文件中的
browsers
条目从browsers: ['Chrome']
更改为browsers: ['ChromeHeadless']
。将 karma.conf.js 项目文件中的
singleRun
条目从值false
更改为true
。 此更改有助于确保 Karma 进程在运行后停止。
React 和 Vue
React 和 Vue 应用的所有依赖项都捕获到 package.json 文件中。 azure-pipelines.yml 文件包含标准 Node.js脚本:
- script: |
npm install
displayName: 'npm install'
- script: |
npm run build
displayName: 'npm build'
生成文件位于新文件夹 dist
(适用于 Vue)或 build
(用于 React)中。 此代码片段生成一个可供发布的工件 www
。 它使用节点安装程序、复制文件和发布生成工件任务。
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseNode@1
inputs:
version: '16.x'
displayName: 'Install Node.js'
- script: |
npm install
displayName: 'npm install'
- script: |
npm run build
displayName: 'npm build'
- task: CopyFiles@2
inputs:
Contents: 'build/**' # Pull the build directory (React)
TargetFolder: '$(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory) # dist or build files
ArtifactName: 'www' # output artifact named www
要进行发布,请将发布任务指向 dist
或 build
工件,并使用 Azure Web 应用部署任务。
Webpack
可以使用 Webpack 配置文件指定编译器(如 Babel 或 TypeScript),将 JSX 或 TypeScript 转译为纯 JavaScript,以及捆绑应用。
- script: |
npm install webpack webpack-cli --save-dev
npx webpack --config webpack.config.js
将以下任务添加到管道:
npm
- 命令:
custom
- 命令和参数:
install -g webpack webpack-cli --save-dev
- 命令:
bash
- 类型:
inline
- 脚本:
npx webpack --config webpack.config.js
- 类型:
生成任务运行程序
通常使用 Gulp 或 Grunt 作为任务运行程序来生成和测试 JavaScript 应用。
Gulp
Gulp 将预安装在某些 Microsoft 托管的代理上。 在 YAML 文件中运行 gulp
命令:
- script: gulp # include any additional options that are needed
如果 gulpfile.js 文件中的步骤需要使用 npm 注册表进行身份验证:
- task: npmAuthenticate@0
inputs:
customEndpoint: <Name of npm service connection>
- script: gulp # include any additional options that are needed
添加发布测试结果任务,以将 JUnit 或 xUnit 测试结果发布到服务器。
- task: PublishTestResults@2
inputs:
testResultsFiles: '**/TEST-RESULTS.xml'
testRunTitle: 'Test results for JavaScript using gulp'
添加发布代码覆盖率结果任务以将代码覆盖率结果发布到服务器。 可以在生成摘要中找到覆盖率指标,并下载 HTML 报告以供进一步分析。
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/*coverage.xml'
reportDirectory: '$(System.DefaultWorkingDirectory)/**/coverage'
如果应用使用 Gulp,则创建管道的最简单方法是在创建管道时将 Node.js 与 gulp 生成模板配合使用。 此模板会自动添加各种任务来调用 Gulp 命令和发布工件。 在该任务中,选择“启用代码覆盖率”以使用 Istanbul 启用代码覆盖率。
Grunt
Grunt 将预安装在某些 Microsoft 托管的代理上。 在 YAML 文件中运行 grunt 命令:
- script: grunt # include any additional options that are needed
如果 Gruntfile.js
文件中的步骤需要使用 npm 注册表进行身份验证:
- task: npmAuthenticate@0
inputs:
customEndpoint: <Name of npm service connection>
- script: grunt # include any additional options that are needed
如果应用使用 Grunt,则创建管道的最简单方法是在创建管道时将 Node.js 与 Grunt 生成模板配合使用。 此模板会自动添加各种任务来调用 Gulp 命令和发布工件。 在此任务中,选择“发布到 TFS/Team Services”选项以发布测试结果,然后选择“启用代码覆盖率”以使用 Istanbul 启用代码覆盖率。
打包和交付代码
生成并测试应用后,可以将生成输出上传到 Azure Pipelines,创建并发布 npm 或 Maven 包,或者将生成输出打包成 .zip 文件,以便部署到 Web 应用程序。
将文件发布到 Azure Pipelines
若要上传文件的整个工作目录,请使用发布生成工件任务,并将以下内容添加到 azure-pipelines.yml
文件中。
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(System.DefaultWorkingDirectory)'
若要上传文件的子集,请先使用复制文件任务将所需文件从工作目录复制到暂存目录,然后使用发布生成工件任务。
- task: CopyFiles@2
inputs:
SourceFolder: '$(System.DefaultWorkingDirectory)'
Contents: |
**\*.js
package.json
TargetFolder: '$(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1
将模块发布到 npm 注册表
如果项目的输出是供其他项目而不是 Web 应用程序使用的 npm
模块,请使用 npm 任务将模块发布到本地注册表或公共 npm 注册表。 每次发布时提供唯一的名称/版本组合。
示例
第一个示例假定你通过对版本控制中的 package.json
文件的更改(例如通过 npm 版本)管理版本信息。 以下示例使用脚本任务发布到公共注册表。
- script: npm publish
下一个示例将发布到存储库 .npmrc
文件中定义的自定义注册表。 设置 npm 服务连接,以在生成运行时将身份验证凭据注入连接。
- task: Npm@1
inputs:
command: publish
publishRegistry: useExternalRegistry
publishEndpoint: https://my.npmregistry.com
最后一个示例将模块发布到 Azure DevOps Services 包管理源。
- task: Npm@1
inputs:
command: publish
publishRegistry: useFeed
publishFeed: https://my.npmregistry.com
有关版本控制以及发布 npm 包的详细信息,请参阅发布 npm 包和如何在生成过程中对 npm 包进行版本控制?。
部署 Web 应用
要创建准备发布到 Web 应用的 .zip 文件存档,请使用存档文件任务:
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
includeRootFolder: false
要将此存档发布到 Web 应用,请参阅 Azure Web 应用部署。
将工件发布到 Azure Pipelines
使用发布生成工件任务将文件从生成发布到 Azure Pipelines。
发布到 npm 注册表
要创建和发布 npm 包,请使用 npm 任务。 有关版本控制以及发布 npm 包的详细信息,请参阅发布 npm 包。
部署 Web 应用
要创建准备发布到 Web 应用的 .zip 文件存档,请使用存档文件任务。 要将此存档发布到 Web 应用,请参阅 Azure Web 应用部署。
疑难解答
如果可以在开发计算机上生成项目,但在 Azure Pipelines 上生成项目时遇到问题,请了解以下潜在原因和纠正措施:
检查开发计算机上的 Node.js 版本和任务运行器的版本是否与代理上的版本匹配。 可以在管道中包含命令行脚本(例如
node --version
),以检查代理上安装的内容。 使用 Node 工具安装程序(如本指南中所述),在代理上部署相同的版本,或者运行npm install
命令将工具更新为所需版本。如果在还原包时生成间歇性失败,则 npm 注册表出现问题,或者 Azure 数据中心与注册表之间存在网络问题。 我们无法控制这些因素。 了解将 Azure Artifacts 与 npm 注册表一起使用作为上游源是否可以提高生成的可靠性。
如果使用
nvm
来管理不同版本的 Node.js,请考虑切换到 Node 工具安装程序任务。 (nvm
由于历史原因安装在 macOS 映像上。)nvm
通过添加 shell 别名和更改PATH
来管理多个 Node.js 版本,而这与 Azure Pipelines 在新进程中运行每个任务的方式交互效果很差。Node 工具安装程序任务可正确处理此模型。 但是,如果工作需要使用
nvm
,则可以将以下脚本添加到每个管道的开头:steps: - bash: | NODE_VERSION=16 # or whatever your preferred version is npm config delete prefix # avoid a warning . ${NVM_DIR}/nvm.sh nvm use ${NODE_VERSION} nvm alias default ${NODE_VERSION} VERSION_PATH="$(nvm_version_path ${NODE_VERSION})" echo "##vso[task.prependPath]$VERSION_PATH"
然后,
node
和其他命令行工具适用于管道作业的其余部分。 在使用nvm
命令的每个步骤中,使用以下代码作为脚本开头:- bash: | . ${NVM_DIR}/nvm.sh nvm <command>
常见问题解答
问:在哪里可以了解有关 Azure Artifacts 和包管理服务的详细信息?
问:我可在何处了解任务的详细信息?
问:如何修复消息为“严重错误:CALL_AND_RETRY_LAST 分配失败 - JavaScript 堆内存不足”的管道故障?
答:当 Node.js 包超出内存使用限制时,会发生此故障类型。 要解决此问题,请添加变量(如 NODE_OPTIONS
),并为其分配一个值 --max_old_space_size=16384。
问:如何在生成过程中对 npm 包进行版本控制?
答:一种选项是结合使用版本控制和 npm 版本。 在管道运行结束时,可以使用新版本更新存储库。 在此 YAML 中,有一个 GitHub 存储库,该包将部署到 npmjs。 如果 npmjs 上的包版本与 package.json
文件不匹配,生成将失败。
variables:
MAP_NPMTOKEN: $(NPMTOKEN) # Mapping secret var
trigger:
- none
pool:
vmImage: 'ubuntu-latest'
steps: # Checking out connected repo
- checkout: self
persistCredentials: true
clean: true
- task: npmAuthenticate@0
inputs:
workingFile: .npmrc
customEndpoint: 'my-npm-connection'
- task: UseNode@1
inputs:
version: '16.x'
displayName: 'Install Node.js'
- script: |
npm install
displayName: 'npm install'
- script: |
npm pack
displayName: 'Package for release'
- bash: | # Grab the package version
v=`node -p "const p = require('./package.json'); p.version;"`
echo "##vso[task.setvariable variable=packageVersion]$v"
- task: CopyFiles@2
inputs:
contents: '*.tgz'
targetFolder: $(Build.ArtifactStagingDirectory)/npm
displayName: 'Copy archives to artifacts staging directory'
- task: CopyFiles@2
inputs:
sourceFolder: '$(Build.SourcesDirectory)'
contents: 'package.json'
targetFolder: $(Build.ArtifactStagingDirectory)/npm
displayName: 'Copy package.json'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)/npm'
artifactName: npm
displayName: 'Publish npm artifact'
- script: | # Config can be set in .npmrc
npm config set //registry.npmjs.org/:_authToken=$(MAP_NPMTOKEN)
npm config set scope "@myscope"
# npm config list
# npm --version
npm version patch --force
npm publish --access public
- task: CmdLine@2 # Push changes to GitHub (substitute your repo)
inputs:
script: |
git config --global user.email "username@contoso.com"
git config --global user.name "Azure Pipeline"
git add package.json
git commit -a -m "Test Commit from Azure DevOps"
git push -u origin HEAD:main