Host and Publish NPM package on GitHub

In this post, we are going to explore the options to

  • host npm source code in GitHub
  • host npm package (both publicly and privately) in Github Packages
  • build, version and publish a npm package via GitHub Actions
  • Install GitHub hosted npm package in your project

We will use yarn as the package management tool (in most of the cases). You can replace it with npm and get the same result.

There is not too much to say, please refer to my example repo https://github.com/windix/npm-tiny for an NPM example (derived from How to make a beautify, tiny npm package and publish it).

The NPM package hosted by GitHub is scoped with your GitHub account name: @scope-name/package-name. The package-name can be set via the name attribute in package.json.

It supports both public and private package (based on your GitHub repo is public or private).

The NPM publishing destination (rather than the default npmjs.com) is controlled by publishConfig setting in package.json:

"publishConfig": {
"registry": "https://npm.pkg.github.com/"
}

If you want to publish from your local machine, please follow the steps:

  1. You need a Personal access token from GitHub to be used as password on command line. It can be generated from Settings > Developer settings > Personal access tokens with correct permissions (at least read:packages, write:packages and repo, delete:packages optional).
  2. Run npm login --registry=https://npm.pkg.github.com and follow the prompt. (Note that yarn login doesn’t support specifying registry :( )
  3. Run yarn publish

(You only need to do steps 1 and 2 once and the authentication details will be stored in your ~/.npmrc).

Notes:

  1. You cannot delete a public package yourself (similarly, npmjs only supports to delete a public package within 72 hours).
  2. The private repo is not available for free organization. Need at least GitHub Team level account.

Place this publish.yml under .github/workflows/publish.yml:

name: publish Node.js Package

on:
push:
branches:
- master

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- run: yarn install
- run: yarn test

publish-gpr:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
registry-url: https://npm.pkg.github.com/
scope: '@windix'
- run: yarn install
- run: git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" && git config --global user.name "$GITHUB_ACTOR"
- run: yarn version --minor
- run: git push --tags && git push
- run: yarn publish
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

Notes:

  1. Remember to replace scope with your own GitHub account name
  2. It triggers on new commits pushed onto master branch (the automatic push in the publish-gpr job won’t trigger!)
  3. Two jobs: build will run tests, if that passes, publish-gpr job will be triggered
  4. publish-gpr job will firstly bump the minor version number (e.g. 1.8.0 -> 1.9.0), tag git repo with the new version v1.9.0 and push back the new commit to GitHub (this has been done by yarn version). Then finally build and publish the new npm package to Github Packages (via yarn publish).
  5. Note that the authentication is done via the default GITHUB_TOKEN from the GitHub Actions environment.

A project level .npmrc is required, so package manager knows where to download the package:

@windix:registry=https://npm.pkg.github.com

If your NPM package is hosted privately, you also need to login first via npm login --registry=https://npm.pkg.github.com. See previous section for details.

Now yarn add @windix/npm-tiny will install my latest version of npm-tiny to your project.

Troubleshooting:

In case if you see a similar error:

error https://npm.pkg.github.com/download/@windix/npm-tiny/1.3.0/950b0ad707d12690c72d91db11c45dde44bbd8909845845033ab1ebabd3d1c3d: Integrity checked failed for "@windix/npm-tiny" (none of the specified algorithms are supported)

Use yarn add @windix/npm-tiny --upgrade-checksums instead to solve the issue.