The Ops Community

Cover image for Publish an npm to GitHub packages
Axel Navarro
Axel Navarro

Posted on • Originally published at dev.to

Publish an npm to GitHub packages

Sometimes in website and backend projects we found common components (React, utils, validations, etc) and, if we follow the DRY concept, we should find a way to create a private package and install it in every project that needs it.

We're going to review how to build and publish JavaScript packages using GitHub and npm.

The GitHub solution

GitHub provides the GitHub Package Registry to publish private npm packages. We can also use it for Docker images and libraries for other languages like Ruby, but we're going to focus on the npm solution.

The publish configuration

You should add the publishConfig section in the package.json file to publish to the GitHub registry.

"publishConfig": {
  "registry": "https://npm.pkg.github.com"
}
Enter fullscreen mode Exit fullscreen mode

The workflow

This workflow will publish a package to the GitHub Registry every time we create a release in the GitHub repository:

name: Publish
on:
  release:
    types: [created]
jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 16
      - run: npm install
      - run: npm run build
      - run: |
          echo @lexacode:https://npm.pkg.github.com/ > build/.npmrc
          echo '//npm.pkg.github.com/:_authToken=${NPM_TOKEN}' >> build/.npmrc
      - run: npm publish
        working-directory: ./build
        env:
          NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

The permissions modifies the default permissions granted to the GITHUB_TOKEN.

This workflow creates a .npmrc file inside the build/ directory before publishing the package to the registry.

echo @lexacode:https://npm.pkg.github.com/ > build/.npmrc
echo '//npm.pkg.github.com/:_authToken=${NPM_TOKEN}' >> build/.npmrc
Enter fullscreen mode Exit fullscreen mode

🧠 Remember that your organization name, e.g. lexacode, should be in kebab-case, no uppercase allowed.

Then, you should add the GITHUB_TOKEN as an environment variable for the npm publish command.

- run: npm publish
  working-directory: ./build
  env:
    NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

Installing the GitHub package

To install the GitHub package locally you should create a PAT (Personal Access Token) in the GitHub web. Make sure you selected the read:packages permission. Then, add the token to your environment:

export NPM_TOKEN=<YOUR_GITHUB_TOKEN>
Enter fullscreen mode Exit fullscreen mode

Create the following .npmrc file in the project:

@lexacode:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
Enter fullscreen mode Exit fullscreen mode

Now, you can run the npm install:

npm install @lexacode/package-example
Enter fullscreen mode Exit fullscreen mode

In GitHub Actions

To use your package in GitHub actions you should use a code like the following:

build:
  permissions:
      contents: read
      packages: read
  steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-node@v2
      with:
        node-version: 16
    - run: npm ci
      env:
        NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ You need the explicit packages: read permission.

Packages cross organizations

If you want to use a package from another organization using the GitHub Package Registry, you should set your PAT as a secret in the repository. Edit the YAML file using the new secret instead:

- run: npm ci
  env:
    NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ The custom permissions section is not required for this scenario.

Conclusion

You can publish private packages and use it everywhere you want via the GitHub Package Registry.

I left you a full repository with a TypeScript package, already published using the CI action. πŸ™Œ

Example npm package

This repository is a template for create TypeScript packages compatible with ES modules and CommonJS.

Discussion (0)