Navigate back to the homepage

Build and publish your node module to private NPM registry on Azure Artifacts

Patrick Zhao
January 12th, 2020 · 3 min read

Background

NPM is a package manager for the JavaScript programming language. It is the default package manager for the JavaScript runtime environment Node.js. Similar to some other languages, via NPM, Node.js developers can upload and manage their node modules flexibly. NPM offers public registries where developers can freely upload their packages and allows others to consume. NPM also offers private registries so that packages upload there is for private usage.

Azure Artifacts – part of Azure DevOps – introduces the concept of multiple feeds that you can use to organize and control access to your packages. If you’re familiar with using packages from NuGet.org or npmjs, you can think of those places each as a single feed.

Recently, when I was helping one of my clients to set up the development environment for the development team, dev team raised a question of using NPM to modularise their node components so different node projects can consume the same set of functionalities. Since their DevOps is entirely set up on Azure DevOps, I had decided to use Azure Artifacts to manage the NPM feed.

In this post, I will show you how to publish an NPM package to Azure Artifacts - NPM private feed. We will use Typescript to build our package.

All the work we do today can be found on my GitHub repo: https://github.com/PatrickZhao1989/npm-package.git

Prerequisite

  • Node.js and Typescript installed on your operation system (OS)
  • Basic understanding of Node.js and Typescript
  • I use PowerShell commands on Windows OS. Please figure out the equivalence in other OS and command prompt.

Project Initialization

First of all, we will initialize a project. Create a new folder in your file system, then launch Windows PowerShell and cd to that directory.

Run npm init and follow through the template giving your project a name, version number..etc. Once completed, a package.json file will be generated under your directory.

Next, we are going to add Typescript to our project. Under the same directory where your package.json file resides, run tsc --init and it will generate a tsconfig.json file in the directory.

Configuration

Since we are going to build the module in Typescript and we want our package consumers to leverage TypeScript’s strong typing and other benefits, we need to configure Typescript Transpiler to do it for us. In tsconfig.json, Add "declaration": true so that it will generate corresponding .d.ts file for us during the build. We also need to define a outDir and enable esModuleInterop. Your tsconfig.json file should look like below.

1{
2 "compilerOptions": {
3 "target": "es5",
4 "module": "commonjs",
5 "declaration": true,
6 "outDir": "./dist",
7 "strict": true,
8 "esModuleInterop": true
9 }
10}

In our package.json, we need to specify main and types values. We also want to include a tsc command so that Typescript will transpile the project for us. See below:

1{
2 "name": "sample",
3 "version": "1.0.9",
4 "description": "This is the sample npm module",
5 "main": "dist/index.js",
6 "types": "dist/index.d.ts",
7 "scripts": {
8 "start": "node dist/index.js",
9 "build": "tsc",
10 "test": "echo \"Error: no test specified\" && exit 1"
11 },
12 "author": "Patrick Zhao",
13 "license": "MIT",
14 "dependencies": {
15 "@types/node": "^13.1.6"
16 }
17}

Build our package

Now is the exciting part – building our package. You can build your modules and organize in your own preferred way. As instruction, we are going to build something super simple. Add an index.ts file in the directory and add the following functions to it.

1export function helloWorld1(input:string): void{
2 console.log(`HelloWorld1 from ${input}`)
3}
4
5export function helloWorld2(input:string): void{
6 console.log(`HelloWorld2 from ${input}`)
7}
8
9export function helloWorld3(input:string): void{
10 console.log(`HelloWorld3 from ${input}`)
11}

Build the code

Now we can run npm run build to build our module. It will generate 2 files under the dist folder. (NPM-PACKAGE is the root directory name – don’t be confused 🙂)

build result in dist folder

The index.js is the transpiled vanilla JavaScript code and the index.d.ts file has the typescript header information. This way, the user of our module can leverage TypeScript benefits such as static type checking.

Setting up Azure Artifacts feed

Now we have built our node module. The next step is to publish it. As mentioned earlier, we are going to publish to Azure Artifact private feed. I assume you have created a project on Azure DevOps. Go to your Azure DevOps project then navigate to the Artifacts menu and create a new feed as shown below:

create new feed on Azure DevOps

Then we can connect to the feed. Select npm and refer to the instructions.

connect to NPM feed

The first thing we need to do is to authenticate with Azure private feed by running the command below.

1npm install -g vsts-npm-auth --registry https://registry.npmjs.com --always-auth false

Then all we need to do is following the instructions to set up a .npmrc file in our project directory (besides package.json) which stores the link to the registry and then authenticates with the link.

Publish our package

We have set up our feed on Azure Artifact. Next, we are going to publish our package. If we have put our working directory into any source control tool such as Git, we need to commit our changes first. Then we can run npm publish to publish our package on to Azure Artifact. Once the publish command completes, we can then see the package together with its dependencies on the Azure Artifact feed.

published feed

Update published package version

After we have made any changes to our package, we need to update our package version before we publish it. Run the command below to update our package.

1npm version <update_type>

update_type can be a patch, major, or minor. See here for further reference.

Consume the package

Consuming the package is easy 🙂 We can initialize a project using npm init and connect to the feed in the same way as we did before using .npmrc file.

Next, we can add our package name to the dependencies. Our package is named sample so after adding it to dependencies, our consumer program’s package.json file looks like this:

1{
2 "name": "test-module",
3 "version": "1.0.0",
4 "description": "",
5 "main": "index.js",
6 "scripts": {
7 "test": "echo \"Error: no test specified\" && exit 1"
8 },
9 "author": "",
10 "license": "ISC",
11 "dependencies": {
12 "sample": "^1.0.9"
13 }
14}

If there is any update in the sample package, we can run npm update to update our dependency.

In our consumer app index.ts, we can reference the module in this way:

1import {helloWorld1, helloWorld2, helloWorld3} from 'sample'
2
3
4helloWorld1('Patrick');
5helloWorld2('Patrick');
6helloWorld3('Patrick');

Running the program will give us the output:

Output of comsumer app

Summary

Building and publishing your own Node.js modules is not a hard thing at all. NPM package management is also the foundation of node applications. In my next few posts, I will discuss more Node.js applications.

More articles from Copyright Patrick Zhao 2021

How I set up my blog

I used to be a WordPress blogger until I find it too expensive and then I decided to set up my own blog

March 31st, 2019 · 4 min read

Building a modern WebRTC streaming solution using Agora

The global pandemic has changed the way people communicate. Online streaming has become a new fashion and norm . I will show you how easy it is to build a reliable and scalable streaming solution using Agora

December 3rd, 2020 · 1 min read
© 2019–2020 Copyright Patrick Zhao 2021
Link to $https://twitter.com/paladinapayLink to $https://github.com/PatrickZhao1989Link to $https://www.linkedin.com/in/patrickzhao1989/