Skip to content

Jonathan Wilkinson

Create NPM Packages with GitHub Packages and GitHub Actions

TypeScript, GitHub Packages, GitHub Actions3 min read

Packages are a great way to share common code between repositories, and GitHub packages is a convenient way to do this. There's unlimited usage for public repos and generous allowances for private repos, even with a free account. Better yet, you get the benefit of keeping all your code in one place.

In this tutorial, we'll go over how to:

  • create a publishable package
  • publish the package locally and in GitHub Actions
  • install the package locally and in GitHub Actions

You can preview the completed deployed package here.

Create an NPM package

First, we'll need something to deploy. For that we're going to create our very own nodash package: lodash's less useful younger brother.

The library will be simple: a single file, index.ts, exporting a single function, mean.

src/index.ts
1/**
2 * Rewrite of lodash's `mean` function with correct output
3 */
4export const mean = (): string => "I don't like your face";

tsconfig.json

We'll build our package using tsc and a minimal tsconfig. Our code will be built into the ./dist folder and will ship with type declarations for anyone using our module in a TypeScript app.

tsconfig.json
1{
2 "compilerOptions": {
3 "target": "es2015",
4 "module": "commonjs",
5 "strict": true,
6 "outDir": "./dist", // build into ./dist
7 "declaration": true // create type declarations
8 },
9 "include": [
10 "src/**/*"
11 ]
12}

package.json

Before our package is publishable we'll need to make a few important changes to our package.json.

package.json
1{
2 "name": "@jonathan-wilkinson/nodash",
3 "version": "1.0.0",
4 "main": "./dist/index.js",
5 "scripts": {
6 "build": "tsc"
7 },
8 "dependencies": {
9 "typescript": "^3.9.6"
10 },
11 "repository": {
12 "type": "git",
13 "url": "git+https://github.com/jonathan-wilkinson/nodash.git"
14 },
15 "publishConfig": {
16 "registry":"https://npm.pkg.github.com/",
17 "access": "public" // Makes the package public!!!
18 }
19}
name

GitHub only allows scoped packages. Scopes are a way to group packages by indvidual or organisation and are named @<scope>/<package>. When using GitHub Packages your scope will be the name of the GitHub account that owns the repository you're publishing to.

My account is jonathan-wilkinson and I'm publishing my nodash package, so my package name will be @jonathan-wilkinson/nodash.

main

The main property tells NPM which file is the entrypoint to our package. This is the file that will be loaded when someone imports/requires our module.

We'll be building our code (index.ts) into the dist, so our main will be dist/index.js.

repository

GitHub needs the repository field to know which repo to publish a package to. Depending on how you first set up your package, this is probably filled in. If it's not, you'll have to add this information before you'll be able to publish.

publishConfig.registry

This field tells NPM which registry to publish our package to. As we're using GitHub's registry, this will be set to "https://npm.pkg.github.com/"

publishConfig.access

Scoped packages are private by default. If we want to make our package public, we need to set publishConfig.access to "public". To keep your package private, you can either remove this or set it to "restricted".


Publish to GitHub Packages

Now we've got our package ready, we'll go over how to publish it manually or with GitHub Actions.

Publishing Manually

Before we can publish we need to set-up NPM to authenticate with GitHub. To do this we need to generate a Personal Access Token in GitHub with permissions:

  • repo
  • write:packages
  • read:packages

We can then run npm config set //npm.pkg.github.com/:_authToken <token> to register this token for use with the GitHub package registry.

Finally, we need to build our package (npm run build) and then we're ready to publish using npm publish.

Publishing in GitHub Actions

Publishing in GitHub Actions is similar to publishing manually. Before we publish, we need to authenticate with GitHub. However, in GitHub Actions we can use the built-in GITHUB_TOKEN.

Our action will run on every push to master. It will:

  • checkout the latest commit
  • set up authentication with GitHub
  • build the package
  • publish the package

You'll notice that we aren't running unit tests, cacheing our resources or handling package versioning here. This is to keep the focus on publishing the package. You'll need to consider all of these when implementing this in a real project.

.github/workflows/publish.yml
1name: Publish
2
3on:
4 push:
5 branches:
6 - master
7
8jobs:
9 build:
10 runs-on: ubuntu-latest
11 steps:
12 - uses: actions/checkout@v2
13
14 - run: |
15 npm config set //npm.pkg.github.com/:_authToken $TOKEN
16 npm install
17 npm run build
18 npm publish
19 env:
20 TOKEN: ${{secrets.GITHUB_TOKEN}}

Install from GitHub Packages

Installing a package from GitHub Packges is relatively simple. We'll use the same npm install command as always. But there are a few additional steps we'll need to take beforehand.

To help NPM find our package, we're going to associate our package scope with the GitHub Package registry. To do this we need to add the following line to a .npmrc file in the root of our repo: @<scope>:registry=https://npm.pkg.github.com/.

In my case, my package scope (the GitHub user associated with my package) is jonathan-wilkinson, so I'd add the following to my .npmrc file.

.npmrc
1@jonathan-wilkinson:registry=https://npm.pkg.github.com/

If we're trying to install a public package, we're ready to npm install, both locally and in GitHub Actions. But if we're going to be installing a private package we'll need to set up authentication with GitHub. The steps will be different for installing the package locally and in GitHub Actions.

Installing a Private Package Locally

If you've been following this tutorial step-by-step you'll have already set up local authentication with GitHub Packages in the publishing step above. If so, you should now be able to npm install the package.

Otherwise, you should follow the steps above to set-up authentication.

GitHub Actions

To install a private package inside a GitHub Action we need to set-up authentication with GitHub before we attempt to npm install our package.

To do this we need to create a new GitHub Personal Access Token with the following permissions:

  • read:packages

Once we've got this token we're going to store it as a "secret" in our repo called READ_PACKAGES. Our secret will be available to use in a GitHub action via the secrets object.

Inside our action, we can run the following command to set up authentication: npm config set //npm.pkg.github.com/:_authToken $TOKEN, where $TOKEN is an environment variable set to the value of secrets.READ_PACKAGES.

.github/workflows/test.yml
1name: Test-Install-GH-Package
2
3on:
4 push
5
6jobs:
7 build:
8 runs-on: ubuntu-latest
9 steps:
10 - uses: actions/checkout@v2
11
12 - run: |
13 npm config set //npm.pkg.github.com/:_authToken $TOKEN
14 npm install
15 npm run speak # Runs a script that calls our "mean" fn
16 env:
17 TOKEN: ${{secrets.READ_PACKAGES}}

All Done! 🎉

If you've got to this point, you should be equipped with everything you need to know to go out into the world and make your own nodash library, or maybe even something useful.

© 2020 by Jonathan Wilkinson. All rights reserved.
Theme by LekoArts