| title | Customize JavaScript for Azure Pipelines |
|---|---|
| description | Customize how you use JavaScript with Azure Pipelines |
| ms.topic | conceptual |
| ms.custom | devx-track-js, freshness-fy22q2 |
| ms.date | 11/02/2023 |
| monikerRange | <= azure-devops |
You can use Azure Pipelines to build your JavaScript apps without having to set up any infrastructure of your own. Tools that you commonly use to build, test, and run JavaScript apps - like npm, Node, Yarn, and Gulp - get pre-installed on Microsoft-hosted agents in Azure Pipelines.
For the version of Node.js and npm that is preinstalled, refer to Microsoft-hosted agents. To install a specific version of these tools on Microsoft-hosted agents, add the Node Tool Installer task to the beginning of your process. You can also use a self-hosted agent.
To create your first pipeline with JavaScript, see the JavaScript quickstart.
::: moniker range=">=azure-devops-2020"
If you need a version of Node.js and npm that isn't already installed on the Microsoft-hosted agent, use the Node tool installer task. Add the following snippet to your azure-pipelines.yml file.
Note
The hosted agents are regularly updated, and setting up this task results in spending significant time updating to a newer minor version every time the pipeline is run. Use this task only when you need a specific Node version in your pipeline.
- task: UseNode@1
inputs:
version: '16.x' # replace this value with the version that you need for your project::: moniker-end
::: moniker range="< azure-devops"
If you need a version of Node.js/npm that isn't already installed on the agent:
-
In the pipeline, select Tasks, choose the phase that runs your build tasks, and then select + to add a new task to that phase.
-
In the task catalog, find and add the Node Tool Installer task.
-
Select the task and specify the version of the Node.js runtime that you want to install.
::: moniker-end
To update just the npm tool, run the npm i -g npm@version-number command in your build process.
You can build and test your app on multiple versions of Node with the Node tool installer task.
::: moniker range=">=azure-devops-2020"
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::: moniker-end
::: moniker range="< azure-devops"
See multi-configuration execution.
::: moniker-end
::: moniker range=">=azure-devops-2020"
If you have tools that are development dependencies in your project package.json or package-lock.json file, install your tools and dependencies through npm. The exact version of the tools gets defined in the project, isolated from other versions that exist on the build agent.
- script: npm install --only=dev- task: Npm@1
inputs:
command: 'install'Run tools installed this way by using the npm npx package runner, which detects tools installed this way in its path resolution. The following example calls the mocha test runner but looks for the version installed as a development dependency before using a globally installed (through npm install -g) version.
- script: npx mochaTo install tools that your project needs but that aren't set as development dependencies in package.json, call npm install -g from a script stage in your pipeline.
The following example installs the latest version of the Angular CLI by using npm. The rest of the pipeline can then use the ng tool from other script stages.
Note
On Microsoft-hosted Linux agents, preface the command with sudo, like sudo npm install -g.
- script: npm install -g @angular/cliTip
These tasks run every time your pipeline runs, so be mindful of the impact that installing tools has on build times. Consider configuring self-hosted agents with the version of the tools you need if overhead becomes a serious impact to your build performance.
::: moniker-end
::: moniker range="< azure-devops"
Use the npm or command-line tasks in your pipeline to install tools on your build agent.
::: moniker-end
In your build, use Yarn or Azure Artifacts to download packages from the public npm registry. This registry is a type of private npm registry that you specify in the .npmrc file.
You can use npm in the following ways to download packages for your build:
- Directly run
npm installin your pipeline, as it's the simplest way to download packages from a registry without authentication. If your build doesn't need development dependencies on the agent to run, you can speed up build times with the--only=prodoption tonpm install. - Use an npm task. This task is useful when you're using an authenticated registry.
- Use an npm Authenticate task. This task is useful when you run
npm installfrom inside your task runners - Gulp, Grunt, or Maven.
If you want to specify an npm registry, put the URLs in an .npmrc file in your repository.
If your feed gets authenticated, create an npm service connection on the Services tab in Project settings to manage its credentials.
::: moniker range=">=azure-devops-2020"
To install npm packages with a script in your pipeline, add the following snippet to azure-pipelines.yml.
- script: npm installTo use a private registry specified in your .npmrc file, add the following snippet to azure-pipelines.yml.
- task: Npm@1
inputs:
customEndpoint: <Name of npm service connection>To pass registry credentials to npm commands via task runners such as Gulp, add the following task to azure-pipelines.yml before you call the task runner.
- task: npmAuthenticate@0
inputs:
customEndpoint: <Name of npm service connection>::: moniker-end
::: moniker range="< azure-devops"
Use the npm or npm authenticate task in your pipeline to download and install packages.
::: moniker-end
::: moniker range="<=azure-devops"
If your builds occasionally fail because of connection issues when you restore packages from the npm registry, you can use Azure Artifacts with upstream sources, and cache the packages. The credentials of the pipeline automatically get used when you connect to Azure Artifacts. These credentials are typically derived from the Project Collection Build Service account.
::: moniker-end
::: moniker range=">=azure-devops-2020"
If you're using Microsoft-hosted agents, you get a new machine every time you run a build - which means restoring the dependencies every time, which can take a significant amount of time. To mitigate, you can use Azure Artifacts or a self-hosted agent - then you get the benefit of using the package cache.
::: moniker-end
::: moniker range=">=azure-devops-2020"
Use a script stage to invoke Yarn to restore dependencies. Yarn gets preinstalled on some Microsoft-hosted agents. You can install and configure it on self-hosted agents like any other tool.
- script: yarn install::: moniker-end
::: moniker range="< azure-devops"
Use the CLI or Bash task in your pipeline to invoke Yarn.
::: moniker-end
::: moniker range=">=azure-devops-2020"
Use compilers such as Babel and the TypeScript tsc compiler to convert your source code into versions usable by the Node.js runtime or in web browsers.
If you have a script object set up in your project package.json file that runs your compiler, invoke it in your pipeline by using a script task.
- script: npm run compileYou can call compilers directly from the pipeline by using the script task. These commands run from the root of the cloned source-code repository.
- script: tsc --target ES6 --strict true --project tsconfigs/production.json::: moniker-end
::: moniker range="< azure-devops"
Use the npm task in your pipeline if you have a compile script defined in your project package.json to build the code. Use the Bash task to compile your code if you don't have a separate script defined in your project configuration.
::: moniker-end
::: moniker range=">=azure-devops-2020"
Configure your pipelines to run your JavaScript tests so that they produce results formatted in the JUnit XML format. You can then publish the results using the built-in publish test results task.
If your test framework doesn't support JUnit output, add support through a partner reporting module, such as mocha-junit-reporter. You can either update your test script to use the JUnit reporter, or if the reporter supports command-line options, pass those options into the task definition.
The following table lists the most commonly used test runners and the reporters that can be used to produce XML results:
| Test runner | Reporters to produce XML reports |
|---|---|
| mocha | mocha-junit-reporter cypress-multi-reporters |
| jasmine | jasmine-reporters |
| jest | jest-junit jest-junit-reporter |
| karma | karma-junit-reporter |
| Ava | tap-xunit |
The following example uses the mocha-junit-reporter and invokes mocha test directly by using a script. This script produces the JUnit XML output at the default location of ./test-results.xml.
- script: mocha test --reporter mocha-junit-reporterIf you defined a test script in your project package.json file, you can invoke it by using npm test.
- script: npm testTo publish the results, use the Publish Test Results task.
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testRunner: JUnit
testResultsFiles: '**/test-results.xml'If your test scripts run a code coverage tool, such as Istanbul, add the Publish Code Coverage Results task. When you do so, you can find coverage metrics in the build summary and download HTML reports for further analysis. The task expects Cobertura or JaCoCo reporting output, so ensure that your code coverage tool runs with the necessary options to generate the right output. For example, --report cobertura.
The following example uses nyc, the Istanbul command-line interface, along with mocha-junit-reporter and invokes npm test command.
- 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'::: moniker-end
::: moniker range="< azure-devops"
Use the Publish Test Results and Publish Code Coverage Results tasks in your pipeline to publish test results along with code coverage results by using Istanbul.
Set the Control Options for the Publish Test Results task to run the task even if a previous task has failed, unless the deployment was canceled.
::: moniker-end
Run tests in headless browsers as part of your pipeline with tools like Protractor or Karma. Then publish the results for the build to Azure DevOps with the following steps:
- Install a headless browser testing driver, such as headless Chrome or Firefox, or a browser-mocking tool such as PhantomJS, on the build agent.
- Configure your test framework to use the headless browser/driver option of your choice according to the tool's documentation.
- Configure your test framework (usually with a reporter plug-in or configuration) to output JUnit-formatted test results.
- Set up a script task to run any CLI commands needed to start the headless browser instances.
- Run the end-to-end tests in the pipeline stages along with your unit tests.
- Publish the results by using the same Publish Test Results task alongside your unit tests.
::: moniker range=">=azure-devops-2020"
Package applications to bundle all your application modules with intermediate outputs and dependencies into static assets ready for deployment. Add a pipeline stage after your compilation and tests to run a tool like webpack or ng build by using the Angular CLI.
The first example calls webpack. To have this work, make sure that webpack is configured as a development dependency in your package.json project file. This runs webpack with the default configuration unless you have a webpack.config.js file in the root folder of your project.
- script: webpackThe next example uses the npm task to call npm run build to call the build script object defined in the project package.json. Using script objects in your project moves the logic for the build into the source code and out of the pipeline.
- script: npm run build::: moniker-end
::: moniker range="< azure-devops"
Use the CLI or Bash task in your pipeline to invoke your packaging tool, such as webpack or Angular's ng build.
::: moniker-end
For Angular apps, you can include Angular-specific commands such as ng test, ng build, and ng e2e. To use Angular CLI commands in your pipeline, install the angular/cli npm package on the build agent.
::: moniker range=">=azure-devops-2020"
Note
On Microsoft-hosted Linux agents, preface the command with sudo, like sudo npm install -g.
- script: |
npm install -g @angular/cli
npm install
ng build --prod::: moniker-end
::: moniker range="< azure-devops"
Add the following tasks to your pipeline:
-
npm
- Command:
custom - Command and arguments:
install -g @angular/cli
- Command:
-
npm
- Command:
install
- Command:
-
bash
- Type:
inline - Script:
ng build --prod
- Type:
::: moniker-end
For tests in your pipeline that require a browser to run, such as the ng test command in the starter app, which runs Karma, use a headless browser instead of a standard browser. In the Angular starter app:
-
Change the
browsersentry in your karma.conf.js project file frombrowsers: ['Chrome']tobrowsers: ['ChromeHeadless']. -
Change the
singleRunentry in your karma.conf.js project file from a value offalsetotrue. This change helps make sure that the Karma process stops after it runs.
All the dependencies for your React and Vue apps are captured in your package.json file. Your azure-pipelines.yml file contains the standard Node.js script:
::: moniker range=">=azure-devops-2020"
- script: |
npm install
displayName: 'npm install'
- script: |
npm run build
displayName: 'npm build'::: moniker-end
The build files are in a new folder, dist (for Vue) or build (for React). This snippet builds an artifact - www - that is ready for release. It uses the Node Installer, Copy Files, and Publish Build Artifacts tasks.
::: moniker range=">=azure-devops-2020"
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::: moniker-end
To release, point your release task to the dist or build artifact and use the Azure Web App Deploy task.
You can use a webpack configuration file to specify a compiler, such as Babel or TypeScript, to transpile JSX or TypeScript to plain JavaScript, and to bundle your app.
::: moniker range=">=azure-devops-2020"
- script: |
npm install webpack webpack-cli --save-dev
npx webpack --config webpack.config.js::: moniker-end
::: moniker range="< azure-devops"
Add the following tasks to your pipeline:
-
npm
- Command:
custom - Command and arguments:
install -g webpack webpack-cli --save-dev
- Command:
-
bash
- Type:
inline - Script:
npx webpack --config webpack.config.js
- Type:
::: moniker-end
It's common to use Gulp or Grunt as a task runner to build and test a JavaScript app.
::: moniker range=">=azure-devops-2020"
Gulp gets preinstalled on Microsoft-hosted agents. Run the gulp command in the YAML file:
- script: gulp # include any additional options that are neededIf the steps in your gulpfile.js file require authentication with an npm registry:
- task: npmAuthenticate@0
inputs:
customEndpoint: <Name of npm service connection>
- script: gulp # include any additional options that are neededAdd the Publish Test Results task to publish JUnit or xUnit test results to the server.
- task: PublishTestResults@2
inputs:
testResultsFiles: '**/TEST-RESULTS.xml'
testRunTitle: 'Test results for JavaScript using gulp'Add the Publish Code Coverage Results task to publish code coverage results to the server. You can find coverage metrics in the build summary, and you can download HTML reports for further analysis.
- task: PublishCodeCoverageResults@1
inputs:
codeCoverageTool: Cobertura
summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/*coverage.xml'
reportDirectory: '$(System.DefaultWorkingDirectory)/**/coverage'::: moniker-end
::: moniker range="< azure-devops"
The simplest way to create a pipeline if your app uses Gulp is to use the Node.js with gulp build template when you create the pipeline. This template automatically adds various tasks to invoke Gulp commands and to publish artifacts. In the task, select Enable Code Coverage to enable code coverage by using Istanbul.
::: moniker-end
::: moniker range=">=azure-devops-2020"
Grunt gets preinstalled on Microsoft-hosted agents. To run the grunt command in the YAML file:
- script: grunt # include any additional options that are neededIf the steps in your Gruntfile.js file require authentication with an npm registry:
- task: npmAuthenticate@0
inputs:
customEndpoint: <Name of npm service connection>
- script: grunt # include any additional options that are needed::: moniker-end
::: moniker range="< azure-devops"
The simplest way to create a pipeline if your app uses Grunt is to use the Node.js with Grunt build template when you create the pipeline. This automatically adds various tasks to invoke Gulp commands and to publish artifacts. In the task, select the Publish to TFS/Team Services option to publish test results, and select Enable Code Coverage to enable code coverage by using Istanbul.
::: moniker-end
After you've built and tested your app, you can upload the build output to Azure Pipelines, create and publish an npm or Maven package, or package the build output into a .zip file for deployment to a web application.
::: moniker range=">=azure-devops-2020"
To upload the entire working directory of files, use the Publish Build Artifacts task and add the following to your azure-pipelines.yml file.
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(System.DefaultWorkingDirectory)'To upload a subset of files, first copy the necessary files from the working directory to a staging directory with the Copy Files task, and then use the Publish Build Artifacts task.
- task: CopyFiles@2
inputs:
SourceFolder: '$(System.DefaultWorkingDirectory)'
Contents: |
**\*.js
package.json
TargetFolder: '$(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1If your project's output is an npm module for use by other projects and not a web application, use the npm task to publish the module to a local registry or to the public npm registry. Provide a unique name/version combination each time you publish.
The first example assumes that you manage version information (such as through an npm version) through changes to your package.json file in version control. The following example uses the script task to publish to the public registry.
- script: npm publishThe next example publishes to a custom registry defined in your repo's .npmrc file. Set up an npm service connection to inject authentication credentials into the connection as the build runs.
- task: Npm@1
inputs:
command: publish
publishRegistry: useExternalRegistry
publishEndpoint: https://my.npmregistry.comThe final example publishes the module to an Azure DevOps Services package management feed.
- task: Npm@1
inputs:
command: publish
publishRegistry: useFeed
publishFeed: https://my.npmregistry.comFor more information about versioning and publishing npm packages, see Publish npm packages and How can I version my npm packages as part of the build process?.
To create a .zip file archive that is ready for publishing to a web app, use the Archive Files task:
- task: ArchiveFiles@2
inputs:
rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
includeRootFolder: falseTo publish this archive to a web app, see Azure web app deployment.
::: moniker-end
::: moniker range="< azure-devops"
Use the Publish Build Artifacts task to publish files from your build to Azure Pipelines.
To create and publish an npm package, use the npm task. For more information about versioning and publishing npm packages, see Publish npm packages.
To create a .zip file archive that is ready for publishing to a web app, use the Archive Files task. To publish this archive to a web app, see Azure Web App deployment.
::: moniker-end
::: moniker range=">=azure-devops-2020"
Once your source code builds successfully and your unit tests are in place and successful, you can also build an image and push it to a container registry.
::: moniker-end
If you can build your project on your development machine but are having trouble building it on Azure Pipelines, explore the following potential causes and corrective actions:
-
Check that the versions of Node.js and the task runner on your development machine match those on the agent. You can include command-line scripts such as
node --versionin your pipeline to check what is installed on the agent. Either use the Node Tool Installer (as explained in this guidance) to deploy the same version on the agent, or runnpm installcommands to update the tools to wanted versions. -
If your builds fail intermittently while you restore packages, either the npm registry has issues or there are networking problems between the Azure data center and the registry. We can't control these factors. Explore whether using Azure Artifacts with an npm registry as an upstream source improves the reliability of your builds.
-
If you're using
nvmto manage different versions of Node.js, consider switching to the Node Tool Installer task instead. (nvmis installed for historical reasons on the macOS image.)nvmmanages multiple Node.js versions by adding shell aliases and alteringPATH, which interacts poorly with the way Azure Pipelines runs each task in a new process.The Node Tool Installer task handles this model correctly. However, if your work requires the use of
nvm, you can add the following script to the beginning of each pipeline: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"
Then,
nodeand other command-line tools work for the rest of the pipeline job. In each step where you use thenvmcommand, start the script with the following code:- bash: | . ${NVM_DIR}/nvm.sh nvm <command>
A: Package Management in Azure Artifacts
A: Build, release, and test tasks
Q: How do I fix a pipeline failure with the message 'FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory'?
A: This failure type happens when the Node.js package exceeds the memory usage limit. To resolve the issue, add a variable like NODE_OPTIONS and assign it a value of --max_old_space_size=16384.
A: One option is to use a combination of version control and npm version. At the end of a pipeline run, you can update your repo with the new version. In this YAML, there's a GitHub repo and the package gets deployed to npmjs. Your build fails if there's a mismatch between your package version on npmjs and your package.json file.
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