Force PushedFP
  • Home
  • Blog
  • Workbooks

Automating publishing a React component library to npm with GitHub actions

What am I publishing to npm?

Along with a ton of other application UIs, I also manage an internally developed component library which outputs several UMD bundles.

Right now this component library is manually built and published to npm by a developer before the next package version can be used in any application.

A typical workflow is for a developer to make the necessary code changes, edit the package.json file to change the npm version number, and finally build and publish the package before merging the PR.

npm run build
npm run pack
npm publish

Sometimes the publish step is skipped and there's inevitably a QA bug filed indicating a feature doesn't work. Since this is an internal package it's not really super important, however I've also seen this occur in popular npm packages, which is super frustrating given some authors do not respond super quickly to outages or bugs.

What's involved in using a GitHub action?

At first glance, developing a Github Action is a little confusing. Since there isn't an easy way to test locally, it needs to be deployed to GitHub meaning certain restraints are needed.

Before I get too far down the road, there are two options I have:

  1. Publishing via npm
  2. Publishing via GitHub

Both options require that I add a new Github Actions folder, but other than that this feels like just a lot of GitHub UI administration.

Since I still want to support the process to manually publish the package to NPM, I'll go with the first option.

Obtain an npm access token

The first thing I need to do is generate an access token for the npm registry in order for GitHub Actions to publish packages. This step is simple given you have access to npm. Once an access token is created at npmjs.com, copy and paste it somewhere for use in the next step.

Give GitHub your npm access token so it can authenticate to npm

The access token we just generated will be stored as a repository secret. In the GitHub repository settings, I visited "Secrets" → "Actions", click "New repository secret", and added the npm access token. I named mine NPM_TOKEN but it doesn't matter as long as you use the same name a few steps later.

Add a GitHub Workflow to your repository to support your new Action

In my component library repository, I then created a new directoy .github/workflows and places a GitHub workflow YAML file called release_package.yml inside.

The code below is the final form of what I ended up with, however it took me a while to figure out some details. Like I said above, since there's no way to test this locally, each change must be committed and pushed to GitHub.

One suggestion I have is to disable any GitHub Action push or merge triggers, and allow your Action to run in a feature branch. This will keep your master branch clean, letting you do all of your work in a feature branch to later squash all of the changes down to one sane-looking commit .

A couple things to note here

  1. Any commits being done in the action are done as a GitHub user which I discovered how from this GitHub community discussion
  2. I am automatically updating the package version with a couple of steps.
  3. The release-type entry under the workflow_dispatch trigger will show a text input prompting how to update the package version.
name: React Component Library
on:
  workflow_dispatch:
    inputs:
      release-type:
        description: 'Release type (one of): patch, minor, major, prepatch, preminor, premajor, prerelease'
        required: true

jobs:
  setup:
    runs-on: ubuntu-latest
    steps:

      # Action setup
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '16.x'
          registry-url: 'https://registry.npmjs.org'

      # Configure Git Actions author
      # @link https://github.com/orgs/community/discussions/26560
      - name: Git configuration
        run: |
          git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git config --global user.name "GitHub Actions"

      # Bump package version
      - name: Bump release version
        if: startsWith(github.event.inputs.release-type, 'pre') != true
        run: |
          echo "NEW_VERSION=$(npm --no-git-tag-version version $RELEASE_TYPE)" >> $GITHUB_ENV
        env:
          RELEASE_TYPE: ${{ github.event.inputs.release-type }}

      # Commit new package version
      - name: Commit package.json version change
        run: |
          git add "package.json"
          git commit -m "mark release ${{ env.NEW_VERSION }}"

      # Run packages install
      - run: npm i

      # Tests
      - run: npm run test-jsx
      - run: npm run test-utilities

      # Publish to npm
      - run: npm run build
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      # Push repository changes
      - name: Push changes to repository
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          git push origin

Make sure your permissions are in order

This part took me the longest and resulted in a fair amount of commits and browsing through the GitHub management UIs.

I had to make some tweaks in the repository and at the organization level some of these permissions affected repository level settings, preventing the GitHub Action from running.

If you're not an admin of your GitHub organization, this part might be time consuming so allow yourself some additional time.

Create a new release using GitHub Actions

Once the permissions and workflow were created and the repository was updated, I could finally trigger a run. I specified "patch" for the release version since this was was a change to the project but nothing that would affect usability.

Wrapping up

Now that this GitHub Action is up and running, I'll probably look to configure some build triggers and remove the manual aspect of me still having to go into the GitHub UI and clicking a button.

With this knowledge and experience, I'm really looking forward to using more GitHub workflows. I'd like to use GitHub Pages to build a documentation portal from an existing Storybook setup for this component library. Also, since I plan on creating other reusable libraries, this repository will serve as a great baseline for future GitHub automation.