Use GitHub Actions to Automatically Publish a Repo Subfolder as an npm Library
Tags: javascript, github, devops, npm
Published: 2023-04-13 13:53:49

---
title: Use GitHub Actions to Automatically Publish a Repo Subfolder as an npm Library
published: true
date: 2023-04-12 00:00:00 UTC
tags: javascript,github,devops,npm
canonical_url: https://www.paigeniedringhaus.com/blog/use-git-hub-actions-to-automatically-publish-a-repo-subfolder-as-an-npm-library
---

[![Person diagramming out a website workflow](https://www.paigeniedringhaus.com/static/213d0cc6af1f5b11dd550cd7d9e30faa/15ec7/workflow-hero.jpg "Person diagramming out a website workflow")](/static/213d0cc6af1f5b11dd550cd7d9e30faa/a2510/workflow-hero.jpg)

## Introduction

I've said it before, and I'll say it again, working as a software engineer for a startup is fun and challenging because of the sheer number of different things I get to do on a regular basis.

I work for an Internet of Things startup called [Blues](https://blues.io/?&utm_source=dev.to&utm_medium=web&utm_campaign=nf&utm_content=notehub-js) which specializes in getting IoT data from devices in the real world into the cloud via cellular. To help show our customers all the possibilities of what they can do with our hardware (Notecards) and our cloud (Notehub), a group of my coworkers and I have been building [lots of JavaScript-based web apps](https://dev.blues.io/accelerators/?&utm_source=dev.to&utm_medium=web&utm_campaign=nf&utm_content=notehub-js) to monitor and display IoT data for a variety of different use cases.

> **A little more about Notecards and Notehub.io**
> 
> [**Notecards**](https://blues.io/products/notecard/?&utm_source=dev.to&utm_medium=web&utm_campaign=nf&utm_content=notehub-js) are low-power, 30mm x 35mm, prepaid cellular-connected devices designed to integrate with any IoT device, and Notecards know, out of the box, how to connect with the Notehub cloud to send as well as receive data from it.
> 
> [**Notehub.io**](https://notehub.io/?&utm_source=dev.to&utm_medium=web&utm_campaign=nf&utm_content=notehub-js) is a cloud-based service for securely connecting to Notecard devices and storing data from them before sending it on to your cloud application of choice.

It quickly became apparent that rewriting the same HTTP calls in multiple projects to fetch data from the native Notehub API endpoints wasn’t easy to reuse or keep up to date as the API continues to grow and evolve.

So we created our own open source, [JavaScript-based library](https://github.com/blues/notehub-js) for the Notehub API and published it on [npm](https://www.npmjs.com/package/@blues-inc/notehub-js) for anyone to use for free. Notehub JS is designed to get you connected to the Notehub API quickly, and allow you to access all of the API routes relevant to interacting with Notehub in a JavaScript-friendly way.

Figuring out how to build an open source library like this and publish it to npm was a first for me, and I learned a lot of interesting things along the way that I'd like to share with you all over the course of a few blog posts in the hope that it might help you if you decide to undertake a similar effort.

**In this blog, I'll show you how to set up a GitHub Actions workflow to automatically publish a new release of a GitHub repo to npm - no muss, no fuss, no manual input required.**

---

## Notehub JS

Ok, before we get to the GitHub Actions workflow, I want to give you a little background on the Notehub JS project because it's a bit unusual.

As I mentioned above, Notehub JS is a JavaScript-based library for interacting with the native [Notehub API](https://dev.blues.io/reference/notehub-api/api-introduction/?&utm_source=dev.to&utm_medium=web&utm_campaign=nf&utm_content=notehub-js), and it's actually generated from the Notehub project's own `openapi.yaml` file, which follows the [OpenAPI specification](https://swagger.io/specification/) standards.

> **OpenAPI Specification**
> 
> The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to HTTP APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.
> 
> An OpenAPI definition can then be used by documentation generation tools to display the API, code generation tools to generate servers and clients in various programming languages, testing tools, and many other use cases.

### OpenAPI Generator CLI

Because the Notehub API has an `openapi.yaml` file that is updated regularly, I was able to use the [**OpenAPI Generator CLI**](https://openapi-generator.tech/docs/installation) to automatically generate a JavaScript-based library to interact with the Notehub API in just a few commands from a terminal.

The catch is, when the new folder is generated which has all the API endpoints and models, the documents, and the `dist/` folder that packages everything up for consumption as an npm module, it's stored as a _subfolder_ inside of the main Notehub JS repo.

The `openapi.yaml` file lives at the root level of the project along with its `config.json` file, a `package.json` file, and a few other other bits and bobs (license, contribution guidelines, code of conduct, etc.), but the real meat of the library lives inside of the `src/` subfolder.

Here's a simplified view of the [Notehub JS repo](https://github.com/blues/notehub-js)'s folder structure:

```
root/
├── .github/ 
| ├── workflows/
| | ├── publish-npm.yml 
├── src/ <- this is the folder generated by the OpenAPI Generator CLI
| ├── dist/
| ├── docs/
| ├── src/ 
| | ├── api/ 
| | ├── model/
| | ├── index.js 
| openapi.yaml
| config.json
| package.json
```

From the diagram above you can see the `openapi.yaml` file that this library is generated from lives at the root of the repo, and the `src/` folder is what actually holds all the Notehub API JavaScript code that powers the Notehub JS library.

This `src/` folder is what needs to be published to npm - not the root of the repo as is the case with most projects in GitHub. But not to worry, publishing just this subfolder can be done, and better yet, it can be automated.

### Configure the root `package.json` to point to the subfolder where the Notehub JS library code lives

So now that I've covered _why_ I only need to publish the subfolder of the Notehub JS repo to npm, let's get on to the _how_.

First thing: add a few extra configuration details to the [`package.json` at the root of the project](https://github.com/blues/notehub-js/blob/main/package.json).

**Update the `main` field to point to the subfolder's `index.js` file**

According to the npm docs, the [`main`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#main) field points to the primary entry point of an app, and when it's not specifically defined it defaults to `index.js` at the root of the project.

Since the `src/dist/` folder is where the `index.js` file lives for Notehub JS library code that should be uploaded to npm, `main` needs to be updated to point to it instead.

Now the `package.json`'s `main` field should read:

```json
"main": "./src/dist/index.js"
```

**Update `repository` to include a `directory` field**

Next, the [`repository`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#repository) field in a `package.json` specifies where the code lives, and it's generally helpful for people who want to contribute to the project.

It has another benefit though: if the `package.json` for the npm package is not in the root directory (like for us, where the auto-generated `src/` folder has its own `package.json`), you can specify the directory in which that file lives.

Here's what the `repository` field should look like:

```json
"repository": {
  "type": "git",
  "url": "https://github.com/blues/notehub-js.git",
  "directory": "src"
}
```

What this translates to on the npm package page is a handy link that points back to root of the GitHub folder (see image below).

[![Notehub JS npm page highlighting repository link on the page](https://www.paigeniedringhaus.com/static/00e3a061fba537fd942151fd22bb311a/1e043/npm-repo-link.png "Notehub JS npm page highlighting repository link on the page")](/static/00e3a061fba537fd942151fd22bb311a/a7396/npm-repo-link.png)

**Add the `publishConfig` field to specify `directory`**

Typically, the [`publishConfig`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#publishconfig) field is used to set config values that will be used at publish time like tags, registries, or access.

Another field that can be added here is `directory`, which customizes the published subdirectory relative to the current `package.json`. This ensures npm knows the `package.json` it needs to read from (and display) in the npm package page is inside of the auto-generated `src/` folder, not at the root of the project.

Add the following `publishConfig` code to the `package.json` like so:

```json
"publishConfig": {
  "registry": "https://registry.npmjs.org",
  "directory": "./src"
}
```

In the end, the whole `package.json` at the root of the Notehub JS repo looks like the code snippet below.

> **Note:** I've omitted parts of the `package.json` for clarity, but if you'd like to see the whole file, you can click the file name below. It's linked to the actual file in the repo in GitHub.

[**`package.json`**](https://github.com/blues/notehub-js/blob/main/package.json)

```json
{
  "name": "notehub-js",
  "description": "JavaScript library for accessing the Blues Wireless Notehub API endpoints",
  "main": "./src/dist/index.js",
  "repository": {
    "type": "git",
    "url": "https://github.com/blues/notehub-js.git",
    "directory": "src"
  },
  "publishConfig": {
    "registry": "https://registry.npmjs.org",
    "directory": "./src"
  }
}
```

Great, the changes to the `package.json` to publish just the `src/` folder to npm are complete, let's move on to the GitHub Actions workflow to make publishing a new version of the Notehub JS library to npm as automated as possible.

### Create a GitHub Actions workflow to publish to npm

> **Need a refresher on GitHub Actions?**
> 
> If you want a quick primer on what GitHub Actions are, I recommend you check out a previous article I wrote about them [here](https://www.paigeniedringhaus.com/blog/use-secret-environment-variables-in-git-hub-actions#what-is-github-actions).

I decided that for my use case, creating a new [**release**](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases) made the most sense to trigger a GitHub Actions workflow to publish the Notehub JS `src/` subfolder to npm.

> GitHub specifically defines a **release** as a deployable software iteration that you can package and make available for a wider audience to download and use, which is exactly what I want.

Once I had settled on this as the trigger for my GitHub Actions workflow, it was a pretty straightforward set of steps to publish to npm.

Here's what the finished `publish-npm.yml` file will look like inside of the `./github/workflows/` folder - I'll break it all down afterwards.

[**`publish-npm.yml`**](https://github.com/blues/notehub-js/blob/main/.github/workflows/publish-npm.yml)

```yml
name: Publish notehub-js to npm

on:
  release:
    types: [created]

jobs:
  npm:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./src
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Setup .npmrc file to publish to npm
        uses: actions/setup-node@v3
        with:
          node-version: "16.x"
          registry-url: "https://registry.npmjs.org"

      - name: Install dependencies
        run: npm ci

      - name: Publish to npm
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
```

Each workflow file needs a **`name`**, so I chose a descriptive one: `Publish notehub-js to npm`.

Next, as I already explained above, this workflow is triggered whenever a new release is created in GitHub, which is where

```yml
on:
  release: 
    types: [created]
```

comes into play.

- [**`on`**](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on) is how a workflow is triggered.
- [**`release`**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release) is the event that triggers the workflow.
- **`types: [created]`** is the activity type for a `release` event that triggers the workflow. This gives us more fine-grained control of when the workflow should run.

Then the **`jobs`** section runs inside of the workflow. This particular script only has one job, `npm`, but if there's multiple jobs, they'll run sequentially unless otherwise specified.

The `npm` job defines that it runs on the latest version of Ubuntu in **`runs-on`**.

[**`defaults.run`**](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#defaultsrun) is an important part of the script because it's where I specify that the working directory for all the following steps is the `src/` folder (because I don't need any of the files from the root of the repo, just what's inside the `src/` folder, I can define this at the job level).

Finally, I get to the **`steps`**.

The steps are as follows:

1. Checkout the code so the workflow can access it using the GitHub Action [`actions/checkout@v3`](https://github.com/actions/checkout).
2. Download a Node.js version to build the package before publishing it to npm using the GitHub Action [`actions/setup-node@v3`](https://github.com/actions/setup-node) (specify the `node-version` and `registry-url` for npm here).
3. Install the project's dependencies stored in the `src/` folder's `package.json` file using [`npm ci`](https://github.com/actions/setup-node).
4. Publish to npm by running the command [`npm publish`](https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages#publishing-packages-to-the-npm-registry) and supplying it with an [`NPM_TOKEN`](https://docs.npmjs.com/creating-and-viewing-access-tokens) (generated in npm) to verify this workflow has permissions to publish to the specified npm package registry.

And there you have it: each time a new release is created in the Notehub JS repo, this GitHub Actions workflow will run and deploy the updated code to npm.

---

## Conclusion

Working as an engineer for a startup company is cool because no two days are alike for me. One day I'm building web apps and updating documentation on our developer experience site, the next I'm reading up on best practices for npm packages and how to automate tasks with GitHub Actions.

Venturing into the realm of open source software and publishing my first JavaScript package to npm was quite a learning experience for me, but I'm so grateful I had the chance to push myself into this space and create something useful for my team (and hopefully our users as well!).

One thing I knew I wanted, right from the start, was to automate the tasks I knew I'd be repeating fairly regularly over time: namely, regenerating the JavaScript library as the Notehub API continued to evolve, and redeploying a new version of the library to npm with the latest updates.

With some extra configurations in the Notehub JS repo's `package.json`, I was able to focus in on the auto-generated subfolder that contains the useful JavaScript-based code for easily interacting with the Notehub API, and with a few GitHub Actions inside of a workflow, I was able to build the code for the package and publish it to npm with the click of a button. Not too bad for an end result.

Check back in a few weeks — I’ll be writing more about the useful things I learned while building this project in addition to other topics on JavaScript, React, IoT, or something else related to web development.

If you’d like to make sure you never miss an article I write, sign up for my newsletter here: https://paigeniedringhaus.substack.com

Thanks for reading. I hope learning how to target a specific folder inside of a project and automating deployments to npm through GitHub Actions workflows come in handy for you in the future. Enjoy!

---

## References & Further Resources

- [Notehub JS](https://github.com/blues/notehub-js) GitHub repo
- [notehub-js](https://www.npmjs.com/package/@blues-inc/notehub-js) npm library
- [OpenAPI Generator CLI](https://openapi-generator.tech/docs/installation)