The scenario
I created a project, bootstrapped with tsdx, and deployed it to npm. I achieved this by logging into npm in my terminal and running
npm publish
or npm publish --access public
The challenge
Subsequently, I decided to publish to the github package registry. That's when I realized that to publish to the github registry, the name of my package needed to be scoped (unlike with npm where this is optional).
According to npm
Scopes are a way of grouping related packages together, and also affect a few things about the way npm treats the package.
Each npm user/organization has their own scope, and only you can add packages in your scope. This means you don't have to worry about someone taking your package name ahead of you. Thus it is also a good way to signal official packages for organizations.
In summary, scoping a package allows two packages with the same name to co-exist, as long as they are scoped differently. Typically, a scoped package would be have the name
field in your package.json
be something like: @someuser/common-package-name
or @someorganization/common-package-name
but mine was more like common-package-name
.
Please note that your package does not have to be @someuser
on github package registry. It could be @anything
but in my case, it seemed like a good idea to just scope it to my username.
Naturally this would not be a problem if your npm package was already scoped like @someuser/common-package-name
on npm. In my case it was not
The Solution
After some googling, I found this closed issue
Basically, alehechka created a great github action to so solve this problem.
The only issue with it was, if your github username had any uppercase characters in it, it will not successfully deploy to the github package registry.
Note
While you could manually do all of this each time you want to deploy, using github actions would be a better and more efficient way to do this.
So, I made some slight modifications to his solution, and with just two steps, you could deploy your package to the github registry and npm.
- Step 1: add this to your package.json
"publishConfig": {
"registry": "https://registry-url"
}
- Step 2: create a workflow file. For instance, deploy.yml and paste in:
name: npm-publish
on:
push:
branches:
- master # Change this to your default branch
jobs:
npm-publish:
name: npm-publish
runs-on: ubuntu-latest
steps:
# Publish to Node Package Manager
- name: Checkout Repo
uses: actions/checkout@main
- name: Setup Node.js (NPM)
uses: actions/setup-node@master
with:
node-version: '12.x'
registry-url: 'https://registry.npmjs.org'
- name: Use cached node_modules
uses: actions/cache@master
with:
path: node_modules
key: nodeModules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
nodeModules-
- name: Install dependencies
run: yarn install --frozen-lockfile
env:
CI: true
- name: Update Publish Config
run: sed -i 's^registry-url^registry.npmjs.org^' package.json
- name: Publish to NPM
run: npm publish --access public
env:
CI: true
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
gpr-publish:
name: gpr-publish
runs-on: ubuntu-latest
steps:
# Publish to GitHub Package Registry
- name: Checkout Repo
uses: actions/checkout@main
- name: Store lowercase actor name
run: |
echo 'actor_name<<EOF' >> $GITHUB_ENV
echo ${{ github.actor }} | tr "A-Z" "a-z" >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
- name: Store package name
run: |
echo 'package_name<<EOF' >> $GITHUB_ENV
grep -Po '"name": *\K"[^"]*"' package.json | grep -oP '"\K[^"\047]+(?=["\047])' >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
- name: Setup Node.js (GPR)
uses: actions/setup-node@master
with:
node-version: '12.x'
registry-url: https://npm.pkg.github.com/
scope: '${{ env.actor_name }}'
- name: Use cached node_modules
uses: actions/cache@master
with:
path: node_modules
key: nodeModules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
nodeModules-
- name: Install dependencies
run: yarn install --frozen-lockfile
env:
CI: true
- name: Update Package Name
run: |
sed -i 's,"name": "${{ env.package_name }}","name": "@${{ env.actor_name }}/${{ env.package_name }}",' package.json
cat package.json
- name: Update Publish Config
run: |
sed -i 's^registry-url^npm.pkg.github.com/@${{ env.actor_name }}^' package.json
cat package.json
- name: Publish to GitHub Package Registry
run: npm publish --access public
env:
CI: true
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
That's really all you need.
The changes I made to this are:
Adding the following script to convert the username to lowercase
- name: Store lowercase actor name
run: |
echo 'actor_name<<EOF' >> $GITHUB_ENV
echo ${{ github.actor }} | tr "A-Z" "a-z" >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
I added this to get the package name from the package.json and store in an environment variable.
- name: Store package name
run: |
echo 'package_name<<EOF' >> $GITHUB_ENV
grep -Po '"name": *\K"[^"]*"' package.json | grep -oP '"\K[^"\047]+(?=["\047])' >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
I then updated to the github action to change the name of the package in the package.json, to a scoped version.
- name: Update Package Name
run: |
sed -i 's,"name": "${{ env.package_name }}","name": "@${{ env.actor_name }}/${{ env.package_name }}",' package.json
cat package.json
and finally, I switched out every use of ${{ github.actor }}
with @${{ env.actor_name }}
which is the author's name in lowercase.
Top comments (4)
Thanks for this great tutorial.
Perfect timing, exactly the insights I was looking for
This article changed my out look on life and it's meaning.
Dude π€£ππ