Getting Started with GPR

(Github Package Registry)

GitHub Packages

What's the difference with npm?

A new ๐Ÿก home for your packages

with the same experience.

With a great difference:

But that makes them a little more difficult to work with...

Let's create one of our own!

Only stored in GPR (and private)

1. Creating the lib

export const getBlahMessage = () => ({ message: 'blah' })
// src/index.js

1. Creating the lib

Type definitions (TS/JSDocs) for EXTRA POINTS!

2. Installing tools

> npm init
> npm i -D rollup
> npm i -D @babel/core rollup-plugin-babel  
rollup-plugin-terser  rimraf 

3. Configuring Rollup

export default {
  input: 'src/index.js',
  output: {
    file: `dist/blah.mjs`,
    format: 'esm', 
    sourcemap: true,
  },
  plugins: [/*...*/]
}
// rollup.config.js

Outputs 1 file

3. Configuring Rollup

export default [
  {/* ... */},
  {/* ... */},
]
// rollup.config.js

Outputs 2 files

3. Configuring Rollup

import babel from 'rollup-plugin-babel'
import { terser } from 'rollup-plugin-terser'
import pkg from './package.json'

const terserOptions = {
  compress: true,
  mangle: true
}

const createConfig = ({ minify, format, ext = 'js' }) => ({
  input: 'src/index.js',
  output: {
    name: pkg.name,
    file: `dist/index${minify ? '.min' : ''}.${ext}`,
    format,
    sourcemap: true
  },
  plugins: [
    babel({ exclude: 'node_modules/**' }), ...(minify ? [terser(terserOptions)] : [])
  ]
})

export default [
  { minify: false, format: 'esm', ext: 'mjs' },
  { minify: true, format: 'esm', ext: 'mjs' },
  { minify: false, format: 'esm' },
  { minify: true, format: 'esm' }
].map(createConfig)

4. Let's create the bundle!

{
  ...
  "scripts": {
    ...
    "build": "rimraf dist && rollup -c"
  }
  ...
}
> npm run build
// pacakge.json

4. Let's create the bundle!

5. Configure package.json

{
  ...
  "files": [
    "dist"
  ],
    
  "main": "dist/index.js",
    
  "module": "dist/index.mjs"
  ...
}
// pacakge.json

Like .gitignore, but the opposite and for the "artifacts" exposed. If empty, the whole project (src, dist...) will be included (except node_modules)

๐Ÿ‘‰๐Ÿฝ

๐ŸŒŸ

Learn more at Node Resolution Algorithmย docs

or see the npm-pkg-testย (private repo) for guidance

The module one is the one that webpack will use, in case it's present.

6. Creating the repo

(A regular repository... As usual!)

> git init

6. Creating the repo

๐Ÿ˜Ž๐Ÿ‘‰๐Ÿฝ

6. Creating the repo

> git add .
> git commit -m "initial commit :rocket:"
> git branch -M main
> git remote add origin git@...
> git push -u origin main

7. Make it installable

 {
+  "name": "@lovetoknow/npm-pkg-test",
+  "repository": "git://github.com/lovetoknow/npm-pkg-test.git",
+  "publishConfig": {
+    "registry": "https://npm.pkg.github.com/"
+  },
-  "private": true
 }

ย Edit package.json

*

* Name of the organization in github (in lowecase!)

7. Make it installable

registry=https://npm.pkg.github.com/lovetoknow

ย Add a .npmrc file

๐Ÿ‘†๐Ÿฝ Oh, must be lowercase!

8. Publish it!

8. Publish it!

But first, authenticate!

8. Publish it!

You have 2 options:

  1. adding a PAT (Personal Access Token) to the .npmrc file. (Preferred version for CI)
    ย 
  2. logging in via npm CLI

8. Publish it!

Working exampleย (private link)

Option 1

...
      - run: >
      	printf "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" > ~/.npmrc
...

This way, a PAT belonging to the CI will be appended to the file, no need to create a "personal" one!

8. Publish it!

> npm publish

Option 2

8. Publish it!

๐Ÿ† Tip! Pre-publish hook, if you publish from the CLI

"prepublish": "npm run build"

Now, let's install it!

9. Installing the lib

9. Installing the lib

> cd ..
> mkdir install-test
> npm init -y

(We set up a test project...)

9. Installing the lib

> npm install @lovetoknow/npm-pkg-test  

9. Installing the lib

Why?

We forgot to tell npm to look for in GPR!

registry=https://npm.pkg.github.com/lovetoknow
// .npmrc

9. Installing the lib

You need to be authenticated to install it!

You have 2 options:

  1. adding a PAT (Personal Access Token) to the .npmrc file.
    ย 
  2. logging in via npm CLI (Preferred option for humans)

๐Ÿ‘‰๐Ÿฝ

9. Installing the lib

PAT Permissions:

  • repo
  • write:packages
  • read:packages
  • delete:packages (optional)
  • read:repo_hook
  • delete_repo

9. Installing the lib

> npm install @lovetoknow/npm-pkg-test  

10. Installing the lib on a CI env

The "robot" ๐Ÿค– needs to be authenticated too. Depending on your needs:

- Via npm CLI

- Via .npmrc with a PAT

//npm.pkg.github.com/:_authToken=PERSONAL_ACCESS_TOKEN
// .npmrc

- Or...

10. Installing the lib on a CI env

Github actions!!

ย 

- GITHUB_TOKEN env var

- registry_url
...
      - uses: actions/setup-node@master
        with:
          registry-url: >
          	https://npm.pkg.github.com/
...
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: >
          	${{ secrets.GITHUB_TOKEN }}

Credit: Daniel Young

11. Updating our library

> git add .

> git commit -m 'change ...'

> git push

> npm version <major | minor | patch>

> npm publish

๐Ÿ‘†๐Ÿฝmanually?

๐Ÿ‘†๐Ÿฝmanually?

11. Updating our library

Alternative workflow:

  • You add as many pushes to master as you want.
  • Once you consider the library should get those changes, you create a git tag
  • npm version manually
  • npm publish automatically on a Github Action.
name: Publish package
on:
  push:
    tags:
      - v.*
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - uses: actions/setup-node@master
        with:
          node-version: 12.x
          registry-url: >
          	https://npm.pkg.github.com/
      - run: npm install
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: >
          	${{ secrets.GITHUB_TOKEN }}

Credit: Daniel Young

๐Ÿ‘‰๐Ÿฝ

11. Updating our library

> npm version

- Updates package.json and package-lock.json

- Creates git tags

- And a commit

11. Updating our library

npm versioning should follow semver

  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards compatible manner, and
  3. PATCH version when you make backwards compatible bug fixes.

12. npm audit

> npm audit

12. npm audit

> npm audit --registry https://registry.npmjs.org/

Credit: Carlo and Josh

13. Good practices

- Tests! (and using the dist files in your tests, not the src)

- npm hooks (pretest, prepublish/postversion)

- semver!

- Publishing a changelog file

Example

Resources

Thank you

Thanks for your help!

Joshua Coady

Carlo D'Ambrosio

Daniel Young
Lluis de Lasaosa

Rakhi Neigi

Credits