Private npm registry with Azure Artifacts and Azure DevOps
While developing line of business products, organizations, usually prefer an ecosystem approach where multiple products or projects can share and reuse code — services, UI components etc. to achieve maximum efficiency. This greatly increases the organization’s savings in terms of time and money.
In this article we will learn to create a private npm registry for hosting npm packages. The example package we are using here is built using Angular. However, the process mentioned here is framework agnostic and can be used for hosting packages built using any modern technology.
Setting up Azure Artifacts feed
First things first, we need to create an artifacts feed to host our npm packages. We will make use of Azure Artifacts feed for this.
Head over to dev.azure.com and follow these steps.
- Create an organization, pick an appropriate and logical name for the organization
2. Create a project within the organization. Let’s call it SharedServices. We are keeping it private. Later members can be provided access using user access management.
3. From the Artifacts link, click on Create Feed. Depending on the purpose of the feed choose an appropriate name. For this example scenario, let’s call it angularcomponents.
Don’t forget to select “Include packages from common public sources” option. As this feed will act as source for both public and private packages. Later, when we connect to this feed from consuming applications, this option will allow us to install external dependencies from common public sources such as npmjs.com or nuget.org.
With that, our private feed is ready which can host packages — npm, nugets etc. However, it is a good practice to maintain separate feeds for different package categories.
Creating an angular library project with a sand box application and live in documentation site
We now shift our attention towards creating the library project that will hold our reusable components and services.
We will not sweat it out on creating a super smart component, as that’s not our real objective here.
Let’s create an angular project using ng create command.
ng new angularcomponents
Add a new library project using ng generate library command inside the angularcomponents project. Each reusable component should be created as library projects.
ng generate library super-header
In this case, we are creating a super-header component which can be reused across applications;
Note that, the above command has created a projects folder and placed the reusable component super-header under this projects folder.
If you wish to enforce a standard for having an unique identifier for your components, you can do so by modifying the tslint.json file to make the linter aware about it. Let’s make our components to have abcenterprise as the unique identifier name.
"component-selector": [
true,
"element",
"abcenterprise",
"kebab-case"
]
While publishing the package, if the component element selector name doesn’t have abcenterprise, we will get an error during linting stage.
Now it’s time to describe our package, its dependencies and version etc. We do all of that in the library project’s package.json file.
{
"name": "@abcenterprise/super-header",
"version": "0.0.1",
"description": "This is a super header component",
"peerDependencies": {
"@angular/common": "^8.2.14",
"@angular/core": "^8.2.14"
}
}
It is a good practice to use semantic versioning for specifying major/minor/patch releases.
Peer dependencies are not installed with the package but signifies that the package needs such dependencies to be installed for functioning. Consumer needs to install such peer dependencies.
Finally, update the README.md file with information about the package that you want Azure artifacts feed to use for generating documentation about the package.
Now it is time to lint, build, run unit tests and publish the library project. But before that, we need to connect to the Azure artifacts feed for hosting our package.
Connecting to Azure Artifacts feed
From the Azure Artifacts feed page that we created previously, click on Connect to feed button and then select npm from the options available.
We need to add a .npmrc file to the angularcomponents project in the same directory that contains the package.json. This will hold the registry address of the feed. You can find the required information that needs to go into the .npmrc file in the Project setup section of the feed.
We would also need to generate a PAT — Personal Access Token, which will be used for authentication. After successful authentication a connection to this feed can be established. This token can be generated using the below command.
vsts-npm-auth -config .npmrc
If vsts-npm-auth tool is not already installed on the machine, we need to install the same using the instructions under Get the tools section of the page.
The above command does the following.
- Creates a PAT token under the DevOps organization npmplayground we created earlier
2. Updates the user-level .npmrc file with generated token details.
With that, we are now ready to publish our package to the feed.
Publishing to the feed
Let’s now do a linting of the library project to ensure that the rules that we have setup are not violated.
ng lint super-header
We should see an error in the console complaining that the selector should be prefixed by “abcenterprise”. This is because we have set up a rule to enforce that every component should have a name prefixed with “abcenterprise”.
@Component({
selector: "abcenterprise-super-header",
template: ` <p>super-header works!</p> `,
styles: [],
})
Changing the selector name to “abcenterprise-super-header” should fix the error and linting should pass.
We can now build the library project. We also need to copy the .npmrc file to the dist folder as this file will be needed for publishing to the private feed.
ng build super-header && copy .npmrc dist
Make sure to run the above command in CMD and not in PowerShell as PowerShell will complain about ‘&&’ not being a valid statement separator.
This will create all necessary bundles, type definition files etc. for publishing.
It’s always a good practice to write enough unit tests for the library project.
ng test super-header --watch=false --browser=ChromeHeadless
The above command executes the unit tests once in the console.
We are now ready to push the package to the feed.
From inside the dist folder we need to copy the .npmrc file to the super-header folder. Then execute npm publish command from within the super-header folder to publish the package to the feed.
The Sequence of commands are shown below.
D:\JYOTI PRAKASH\angularcomponents>cd distD:\JYOTI PRAKASH\angularcomponents\dist>copy .npmrc super-header
1 file(s) copied.D:\JYOTI PRAKASH\angularcomponents\dist>cd super-headerD:\JYOTI PRAKASH\angularcomponents\dist\super-header>npm publish
If everything goes fine, then we should see a success message in the console along with the package details.
We can also see the package in the angularcomponents feed.
That’s it! We have successfully published a npm package to a private npm repository.
Connecting to the feed from a consuming project
Let’s now try to connect to this feed from a consuming project and use the npm package from the feed.
The first step is to add a .npmrc file containing the feed address like we did in the previous section.
The next step is to run npm install command with our package name and optionally the version. If version is not supplied the latest available version of the package is installed from the feed.
npm install @abcenterprise/super-header@0.0.1
And then add an import to the SuperHeaderModule in the imports array of the app.module.ts file.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';import { AppComponent } from './app.component';
import { SuperHeaderModule } from '@abcenterprise/super-header';@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
SuperHeaderModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Now let’s run the application and see if the component which we created and published to the private repository works.
Sure it does!
I hope this article will help you when you need to create an in house private npm repository for your own organization.