Automate publish of Angular library as npm package with Azure DevOps

Reading time: 10 minutes

Description

In this post I will explain how to set up continuous deployment of Angular library as npm package with Azure DevOps.

This post will also contain instructions of how to configure the build pipeline, how to configure your Angular application as developer and as a consumer of this package.

I will build two Angular applications for this purpose, so it will be clear to distinguish between the library and consumer applications.

What is required

What’s good about it?

If you are using npm packages you need to host them somewhere. There are several options available. Normally if it’s for public use then it’s free if private or corporate then it obviously costs money. That is their business model.

If you already have an Azure subscription then you have an option to store and host them there. This might be more cost effective but it depends on your needs and availability.

For me it was handy to have an Azure DevOps repo that would have continuous integration trigger enabled, so when I commit a change it would build it and publish it for me.

Once I set up the build pipeline it would do the main stuff related to publishing for me. So the only thing that I would have left to do is set the correct version from my local machine.

Let’s start with initiating a repository for an Angular library on Azure DevOps

Prerequisite: you need a project on Azure DevOps. Go to your Azure DevOps main page.

Once the project is created select Repos from the left side menu. Clone this repo to your computer by copying the url link and using it with your choice of Git GUI.

If you haven’t configured your environment with Angular yet then please do so.

Install Visual Studio Code on your machine. Please use the link below.

https://code.visualstudio.com/download

Then you need to install an appropriate Node.js version that is compatible with your version of Angular.

https://nodejs.org/en/download/

Let’s create an Angular library

Open VS code and navigate to the root folder of the destination where you cloned your repo.

In VS code new terminal type ‘cd destination-of-your-repo’ for example ‘cd C:\Users\dmitr\source\frontend\AzureArtifactsNpmPublish’

Then type

ng new AzureArtifactsNpmPublish --directory=./ --skip-install --create-application=false

The name of this app should match the folder name. This way it will use the root folder and won’t nest it within an extra folder.

As a result you get minimum files created plus it is created straight away in the repo root folder. Pretty neat.

Open the project code files in new the window by typing ‘code .

Then type ‘ng g library your-library-name’ for example ng g library azure-npm-ng-lib

Once you have done this and you are happy with the output please commit-push to Azure DevOps repo.

Before we head on to create a pipeline we need to create the feed that we will be using to store and manage our packages

Select Artifacts from the left side menu of the project on Azure DevOps. Click on Create feed and type in the name for your feed. For Visibility it should be Members of name-of-your-organisation. Make sure Upstream sources Include packages from common publish sources is ticked. As for the Scope select Organization.

All of these settings are applicable to our current needs. If you want to limit who can use the feed then you need to select the appropriate Visibility and Scope.

We are ready to create a build pipeline

Go to the Pipelines section and click Create Pipeline. Then select Classic Editor.

Since we created our repo with Azure DevOps we need to select Azure Repos Git. As for the template, Empty Job will fit our needs.

Because we will use Angular Cli we need Node.js. So the first task will be Node.js Installer.

We also need angular cli install, npm install, npm build and npm publish tasks.

For angular cli install task we need to set Command as custom, in Command and arguments enter ‘install @angular/cli -g’

For the npm install task we will leave it as it is.

For the npm build task we need to set for ‘Working folder that contains package.json’ the location of the root of the library folder within the angular project e.g. ‘projects/azure-npm-ng-lib’
Also in here for ‘Command and arguments’ we need to type ‘run build your-library-name –prod’ e.g. run build azure-npm-ng-lib –prod

For npm publish task we need set ‘Working folder that contains package.json’ with the destination after the application was built. We know that build files are placed by default into the ‘dist/project-name’ folder (you can change this outputPath in angular.json). Hence the location of this library would be at ‘dist/azure-npm-ng-lib’ and the full path ‘$(System.DefaultWorkingDirectory)/dist/azure-npm-ng-lib’
As for ‘Registry Location’ we want to set ‘Registry’ and for ‘Target registry’ we need to pick a registry that is preferably organization scoped.

Additionally we need to set CI trigger and Agent Specification for this pipeline.

Different agent specifications would have different build processes and different paths. For our purpose we will use ubuntu-18.04 agent specification.

Click on the Pipeline section and set the appropriate agent specification for your needs.

Select dropdown of Save & Queue and select Save.

Before we can run it we need to allow this pipeline to make changes to Artifacts feed-registry that we selected in the npm publish task as Target registry.

Once this is done you need to go back to Pipelines and click Run Pipeline. Check the images for more info.

Click on the dropdown of Save & Queue.

If the build is successfull we can find our package under Artifacts side menu option.

*make sure tsconfig.lib.json library level enableIvy is set to false i.e. “angularCompilerOptions”: { “enableIvy”: false }
*and package.json contains scripts part with ng build i.e. “scripts”: { “ng”: “ng”, “build”: “ng build” }

Next we need to configure our machine to use artifacts feed-registry for our npm package

Since we will be storing our npm packages in Azure DevOps feed we need to configure our client machine to use this feed.

There is a helpful section of how to do this under Artifacts. Click on Connect feed and then select npm. On the newly opened section click ‘Get the tools’. This should open a slide menu with description of how to do it.

Since we already configured Node.js and npm at the beginning we can skip to Step 2. Copy the command ‘npm install -g vsts-npm-auth –registry https://registry.npmjs.com –always-auth false’

Open a new terminal in VS code and run it. As an extra check if it was installed you can run this command ‘npm list -g –depth 0’ and see if it’s in the list.

There are more details as to how to set up authentication.

Let’s create another Angular app that would consume our npm package

Before that we need to initiate a repository at Azure DevOps. Select Repos in left side menu. Click a dropdown next to the name of your current repository. Select New Repository.

Clone it to your machine and keep in mind the location.

Open VS code and navigate to that location. Run this command

ng new AzureArtifactsNpmConsumer --directory=./ --skip-install

Make sure the name matches the name of the root folder. This way your app won’t be nested within an extra folder.

Next we need to set up our Angular project according to the provided instructions at Azure DevOps Connect to feed section

Add npmrc file to your root project. In my case this would be ‘C:\Users\dmitr\source\frontend\AzureArtifactsNpmConsumer\.npmrc’

Paste in the first command from Connect to feed description into project level npmrc file.

If you open a user level npmrc file which is located at ‘C:\Users\yourName\.npmrc’ and either take a screenshot or copy it somewhere as a backup before it is be modified.

Then run this command in the same project ‘vsts-npm-auth -config .npmrc’.
You will be prompted with a login window. Follow the onscreen instructions to complete the authentication process.

Now if you close and open again the user level npmrc file you would be able to see the difference.

There’s another thing you can do to assist the process of the authentication. Open package.json of the project you are working on and add this bit “refreshVSToken” : “vsts-npm-auth -config .npmrc” into the scripts section. So it would look like so “scripts”: {“refreshVSToken” : “vsts-npm-auth -config .npmrc”}

So in case you are required to refresh the token you can write in terminal ‘npm run refreshVSToken’ and it should reauthenticate you/refresh the token at user level npmrc file.

Basically what is happening behind the scene is every time we run npm install the authentication process kicks in. The token that is in the npmrc file at user lever location is exchanged with registry-feed, so that user machine gets authenticated.

Let’s test if we can install our library package to our Angular consumer app

Please go to the Artifacts at Azure DevOps from there into the package details page and copy the full command to install the package. For example ‘npm install azure-npm-ng-lib@0.0.1’

Use this command in the Angular app where you want to access this npm package.

Next let’s add some code to Angular app and test if we can use npm package code

Open app.component.ts and add this code.

constructor(private _azureNpmNgLibService: AzureNpmNgLibService) {
  }

  ngOnInit(): void {
    this.mainFunc();
  }

  mainFunc(){
    let message = this._azureNpmNgLibService.getMessage();
    console.log(message);
    console.log(123)
  }

So it would look like the image below. Then run ‘ng serve -o’ and open the developer tools. Check if the console/debugger tab contains our ng library npm package message.

Next let’s apply a change and increase the version of lib package

In terminal navigate into folder where library files live and type in ‘npm version 0.0.2’ e.g. C:\Users\dmitr\source\frontend\AzureArtifactsNpmPublish\projects\azure-npm-ng-lib> npm version 0.0.2
This way the package.json version of the library would be updated.

Optionally change the message.

export class AzureNpmNgLibService {

  constructor() { }
  
  getMessage(){
    return "wow what an update! is it the font or a colour :-D"
  }
}

Then commit-push these changes. This should trigger a new build.

This should update our existing package to 0.0.2. You can check this at the Artifacts section.

Next let’s update our Angular consumer app to the latest version of our npm package

In the terminal type in ‘npm outdated’. This would list all the packages that have updated versions.

To update the package to the latest version we need to use ‘npm i azure-npm-ng-lib@latest’ You can also target a particular the version then you need to write what version number like so ‘npm i azure-npm-ng-lib@2.0.0’

Once it is updated to the latest version it is removed from the outdated list. If it’s not the latest it will still be there. For instance if you have 3 versions and your app uses version number two.

Npm follows semantic versioning, more details here.

Conclusion

As you have noticed there are a lot of tips available on Azure DevOps that can guide you through the whole process. As long as you are aware of the process of how npm packages are published to the npm registry all of this should make sense.

If you want an original guide from Microsoft you can find it here.

In my opinion this combination of npm packages and build pipeline with Azure DevOps can be extremely helpful.

It’s one of those things you set up once and you can enjoy the effectiveness of it from then on. In essence you have moved the main heavy lifting(building and publishing) to a cloud based server, so it’s doing it for you.

Moreover you can see the history and related description of changes in a more familiar format.

You can find code for ng library package here and consumer app here.