Journey of publishing a package

Journey of publishing a package

Overview

After we have built the Node.js SDK to support our customers in integrating with our APIs. The next step is publishing it so other developers can use it.

We have some registry choices like the npm registry or GitHub Packages. And we decided to publish our SDK to GitHub Packages because the code repository is on GitHub and we want to leverage the GitHub Action to automatically publish it so we can achieve the single source of truth idea (use only GitHub services). We found many detailed documents which made us believe that we can easily publish it manually or automatically. But some unexpected issues made us change our decision and we will tell you about our journey.

Publish to GitHub Packages

In this section, I will talk about how we can publish a package to GitHub Packages.

1. Name the package in the package.json file

Because GitHub Packages only support scope packages so we have to name our package following this rule.

The field name must contain the scope (the organization name) and the name of the package. For example, if your package is called "zalopay-nodejs", and you are publishing to the zalopay-oss GitHub organization, the field name in your package.json should be @zalopay-oss/zalopay-nodejs.

The package is not linked to a repository by default. If you connect a package to a repository, the package's landing page will show information and links from the repository, such as README.

So in package.json, add these properties

"repository": {
  "type": "git",
  "url": "https://github.com/zalopay-oss/zalopay-nodejs"
},

3. Add GitHub Action script

GitHub Actions is a powerful automation tool built into the GitHub platform that allows developers to automate their CI/CD workflows. And here is an example script that will run when a tag is created.

name: Publish package
on:
  push:
    tags:
      - "v*.*.*"
jobs:
  publish-github-packages:
    runs-on: ubuntu-latest
    permissions:
      packages: write
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Set up node
        uses: actions/setup-node@v3
        with:
          node-version: 16
          registry-url: https://npm.pkg.github.com/
          scope: "@zalopay-oss"
      - name: Install dependencies
        run: npm i
      - name: Build the project
        run: npm run build
      - name: Publish package to GitHub Packages
        # Change the visibility to public when publishing the package
        run: npm publish --access public
        env:
          # An automatic token that will be created when the workflow is running.
          NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
./github/workflows/publish.yml

Usually, the default registry of the user's project is the npm registry, so users need to authenticate and install the package from the GitHub registry.

$ npm login --scope=@zalopay-oss --auth-type=legacy --registry=https://npm.pkg.github.com
 
> Username: USERNAME
> Password: TOKEN
 
$ npm install @zalopay-oss/zalopay-nodejs

Rather than using a single command npm install, now developers have to do an extra step to login first to install the package. With a requirement for Github credentials, it also complicates build processes. We want developers to have good experience while using the SDK, esp. in the begining phase of installation.

So we decided to publish to the npm registry also.

Publish to the npm registry

First, create an access token of your npm account with appropriate permissions.

Second, set the npm token to the repository secret variable on your GitHub repository.

Finally, add another job to your workflow.

jobs:
  publish-github-packages:
    ...
  publish-npm-registry:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Set up node
        uses: actions/setup-node@v3
        with:
          node-version: 16
          registry-url: "https://registry.npmjs.org"
      - name: Install dependencies
        run: npm i
      - name: Build the project
        run: npm run build
      - name: Publish package to NPM registry
        run: npm publish --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
./github/workflows/publish.yml

Note: the name of the repository secret variable must match the env.NODE_AUTH_TOKEN in the workflow.

And now the workflow is completed and ready to run.

Comparison

Here is a quick comparison between GitHub Packages and the npm registry

GitHub Packages NPM registry
Popularity A new service so maybe not be widely used Widely used and well-established
Pricing Free for public packages
Limited free storage for private packages
Free for public packages
Need a subscription for private packages
Support Languages Node.js, Ruby, Java, and other languages Only Node.js
Install the package Require a personal access token with the appropriate scope No

Make a release

Usually, a tag is created when developers want to release a stable version of code which helps them view and manage the change in their codebase. So here is how we do it.

jobs:
  ...
  release:
    permissions:
      contents: write
    needs: [github-packages, npm-registry]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: GH Release
        uses: softprops/action-gh-release@v0.1.15
        with:
          token: ${{secrets.GITHUB_TOKEN}}
          generate_release_notes: true
.github/workflows/publish.yml

In the above script, we use a pre-built action to handle the complicated task of releasing a version on GitHub.

And here is the result:

Conclusion

Publishing a package seems to be an easy task at first point. But at the end of the journey (maybe not yet) we have learned many things:

  • The first choice can be wrong and we have to be decisive when the change is needed.
  • Put yourself in the user's shoes. The moment that you use your product as your customer, you can see many new things.

And that is all we want to share with you. We hope that our journey of this simple task can help you not only with how to publish a package but also with how to do your "tasks".

"The little things amount to big things." - Robin S. Sharma