A selfie of me hiking on snowy Mt. Rainier. I am smiling while wearing my hat and sunglasses. Behind my head, in the distance, you can see the looming peak of Mt. Adams.
0 min read
Published · Updated

Use GitHub Packages to store font files as a private NPM package

GitHub Packages allow you to store up to 500 MB of NPM packages privately, for free.

I re­mem­ber stum­bling upon Kelly Har­rop’s post, “Cre­at­ing a fonts pack­age,” some time last year. In­trigued, her idea mar­i­nated in my head for a while. Though I do share all of Kelly’s goals with the ex­ter­nal font pack­age, I had an ad­di­tional goal not men­tioned in her post: I wanted to make my font repo and NPM pack­age pri­vate.

My rea­son­ing here was twofold. I wanted to help pro­tect the type foundry’s in­tel­lec­tual prop­erty, and I also wanted to com­ply with the EULAs I agreed to when I li­censed a par­tic­u­lar type­face.

Blanco — the serif type­face I use for body copy on this site — spec­i­fies in their EULA that the li­cen­sor can­not “store or use font files in a way that makes them avail­able for use by any third party.” This, I think, rules out stor­ing the font files as-is in a pub­lic GitHub repos­i­tory.

As I put the fin­ish­ing touches on this site’s lat­est de­sign, I re­mem­bered Kelly’s post and de­cided to tweak her process for my pri­vate font pack­ages.

Rea­sons for pri­vate NPM pack­ages

Li­cens­ing is­sues aside, there are other rea­sons why you’d want to store font files — or any type of files, for that mat­ter — in a sep­a­rate, pri­vate NPM pack­age:

  • Con­fi­den­tial source code: Maybe you have code sep­a­rate from your open-​source project that you want to keep se­cret. In that case, turn­ing a pri­vate repo into a GitHub Pack­age you can npm install is pretty handy.
  • Re­duce boil­er­plate: At work, I need to reach for the same type­faces on every sin­gle web project to ad­here to our brand. Even though all of my work repos are pri­vate, it’s te­dious doing the same setup tasks for every project. Maybe you need the same con­fig files shared across a lot of projects, stor­ing them in one source of truth is handy.

Set­ting up our repo

First, we’ll need to cre­ate the local di­rec­tory that we’ll push to GitHub. I name mine after the type­face I will store in it, but you can name it what­ever you want.

npm init

I then walk through the prompts to cre­ate a package.json file. I don’t bother fill­ing out the prompts, but you can if you want. Then, add the font files, an index.css file, and a README.md, if de­sired. In the end, your di­rec­tory may look some­thing like this:

blanco/
├─ files/
│  ╰─ Blanco/
│     ╰─ woff2/
│        ├─ Blanco-Regular.woff2
│        ├─ Blanco-Italic.woff2
│        ├─ Blanco-Medium.woff2
│        ├─ Blanco-MediumItalic.woff2
│        ├─ Blanco-Bold.woff2
│        ├─ Blanco-BoldItalic.woff2
│        ├─ Blanco-ExtraBold.woff2
│        ╰─ Blanco-ExtraBoldItalic.woff2
├─ index.css
├─ package.json
╰─ README.md

I like to group my font files by file type, but you’re wel­come to do what works best for you.

The pack­age.json file

Your package.json may look some­thing like this:

package.json
{
	"name": "@johneatmon/blanco", // <-- this must be your GH username and repo/package name
	"version": "0.0.1", // <-- this is the semver of your package
	"description": "The font files for the Blanco typeface",
	"main": "index.css", // <-- this is the entry point for your package
	"publishConfig": {
		"access": "restricted", // <-- this makes your package private
		"registry": "https://npm.pkg.github.com" // <-- this tells NPM to use GH Packages
	},
	"repository": {
		"type": "git",
		"url": "git+https://github.com/johneatmon/blanco.git" // <-- this is the URL to your GH repo
	},
	"author": "John Eatmon <...>",
	"homepage": "https://github.com/johneatmon/blanco#readme"
}

The lines I’ve com­mented are the cru­cial ones you will need to adapt to your en­vi­ron­ment.

The CSS file

Let’s take a look at the index.css file:

index.css
/* Regular */

@font-face {
	font-family: "Blanco";
	src: url("./files/woff2/Blanco-Regular.woff2") format("woff2");
	font-weight: 400;
	font-style: normal;
	font-display: auto;
	font-feature-settings: "kern" on, "liga" on, "ss01" on;
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F,
		U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ... */

Write as many @font-face de­c­la­ra­tions as you need for your font files. Since I know I will be using the font’s kern­ing and lig­a­tures fea­tures, I en­able those in the font-feature-settings prop­erty. I also spec­ify the unicode-range prop­erty to sub­set the font for the Latin al­pha­bet.

Once you’ve set all of this up, go ahead and com­mit these to your GitHub repo. Make sure the name of the repo matches the name in your package.json file.

Cre­ate a GitHub per­sonal ac­cess token (PAT)

Now that we have our GitHub repo set up, we need to con­fig­ure a GitHub Per­sonal Ac­cess Token (PAT) to allow us to push our pack­age to GitHub Pack­ages.

  1. To do this, go to your GitHub Set­tings.
  2. Click on the De­vel­oper set­tings tab.
  3. Then, click on Per­sonal ac­cess to­kens.
  4. In the To­kens (clas­sic) tab, click Gen­er­ate new token and give it a name. I called mine Private GH registry, but name it what­ever.
  5. Se­lect the repo and write:packages scopes.
  6. Once you’ve cre­ated the token, copy it to your clip­board. I rec­om­mend you stash it in a pass­word man­ager or sim­i­lar be­cause you won’t be able to see it again.

Now we need to add our per­sonal ac­cess token as a shell en­vi­ron­ment vari­able.

Con­fig­ur­ing bash/zsh to use GitHub Pack­ages

To con­fig­ure bash or zsh to use GitHub Pack­ages, we need to edit the ~/.bashrc or ~/.zshenv file on our ma­chine. My macOS ma­chine uses zsh, so I will be adding a ~/.zshenv file (didn’t exist be­fore). My Win­dows ma­chine uses bash, so I edited the ~/.bashrc file there in­stead.

Here’s how we’ll do that:

macOS (zsh)

  1. Go to the di­rec­tory where your .zshrc file is stored, typ­i­cally in your home di­rec­tory. If you’re not sure, you can type the fol­low­ing in a new zsh ter­mi­nal:
echo ~

This will print out the di­rec­tory of your .zshrc file.

  1. Once you’ve lo­cated the di­rec­tory, you might not see the file right away. That’s be­cause, by de­fault, macOS hides files that start with a .. To see the file, you can use the fol­low­ing key­board short­cut: ⌘ + Shift + . — this will tog­gle the vis­i­bil­ity of hid­den files. You should see the .zshrc file now.

  2. Cre­ate a new file (if not pre­ex­ist­ing) called .zshenv in the same di­rec­tory.

  3. In that file, add the fol­low­ing line:

export GITHUB_TOKEN=GITHUB_PAT_TOKEN

GITHUB_TOKEN is the en­vi­ron­ment vari­able that will be ref­er­enced later, you can call it what­ever you wish. Re­place GITHUB_PAT_TOKEN with the per­sonal ac­cess token you cre­ated ear­lier. Save the file and close it.

Any pro­grams you have run­ning that use zsh will now have ac­cess to the GITHUB_TOKEN en­vi­ron­ment vari­able (but you may need to restart them first).

  1. You can check that the en­vi­ron­ment vari­able is set by typ­ing the fol­low­ing in a new zsh ter­mi­nal:
echo ${GITHUB_TOKEN}

Win­dows (bash)

  1. Go to the di­rec­tory where your .bashrc file is stored, typ­i­cally in your home di­rec­tory. If you’re not sure, you can type the fol­low­ing in a new bash ter­mi­nal:
echo ~
  1. Once you’ve lo­cated the di­rec­tory, you might not see the file right away. That’s be­cause, by de­fault, Win­dows hides files that start with a .. To see the file, you can click the View but­ton in the File Ex­plorer tool­bar and then se­lect ShowHid­den items. This will tog­gle the vis­i­bil­ity of hid­den files. You should see the .bashrc file now.

  2. Open the .bashrc file and add the fol­low­ing line:

export GITHUB_TOKEN=GITHUB_PAT_TOKEN

GITHUB_TOKEN is our en­vi­ron­ment vari­able that will be ref­er­enced later, you can call it what­ever you wish. Re­place GITHUB_PAT_TOKEN with the token you copied ear­lier. Save the file and close it.

  1. You can check that the en­vi­ron­ment vari­able is set by typ­ing the fol­low­ing in a new bash ter­mi­nal:
echo ${GITHUB_TOKEN}

Pub­lish­ing the pack­age

Now that we have our en­vi­ron­ment vari­able set up, we can pub­lish our pack­age to GitHub Pack­ages. 🥳

Go back to your font project di­rec­tory and run the fol­low­ing com­mand:

npm publish

If every­thing was done cor­rectly, it should pub­lish your pack­age to GitHub Pack­ages. You’ll see an NPM pack­age dis­played on the side­bar in your GitHub repo. Sweet!

Using the pack­age

To use this pack­age in your projects, you’ll first need to add an .npmrc file to your project di­rec­tory. This file will tell NPM to use GitHub Pack­ages as the reg­istry but only for the name­space that we’ll spec­ify.

Cre­ate the .npmrc file and add the fol­low­ing lines:

@johneatmon:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

Re­place @johneatmon with your GitHub user­name, and re­place GITHUB_TOKEN if you named your en­vi­ron­ment vari­able some­thing else.

We are telling NPM to only use GitHub Pack­ages for pack­ages that start with @johneatmon (in this case, my user­name). This is im­por­tant be­cause we don’t want NPM to use GitHub Pack­ages for all pack­ages, just the ones we spec­ify in this way.

Now, you can in­stall the pack­age in your project by run­ning the fol­low­ing com­mand:

npm install @your_github_username/your_package_name

To use the font in your project, you’ll need to im­port it in your CSS file. In my case, using Astro, I sim­ply add the fol­low­ing line to my <BaseHead /> com­po­nent:

src/components/BaseHead.astro
import "@johneatmon/blanco"

You may need to tai­lor this ap­proach to your project, how­ever.

Wrap­ping up

You can safely com­mit .npmrc to your project’s repo. It will not ex­pose your GitHub PAT token be­cause we kept it se­cret using a shell en­vi­ron­ment vari­able.

Note: When you do make changes to your fonts pack­age, you’ll need to bump the ver­sion num­ber in your package.json file. Then, you can pub­lish the new ver­sion by run­ning the npm publish com­mand.

As al­ways, drop me a line or tweet at me with any ques­tions or sug­ges­tions.

Fur­ther read­ing

Interested in working together?

Reach out to learn more about me and/or my work.