Github Actions Publish npm Package

tags: npm Github Actions
category: DevOps
description: Github Actions Publish npm Package
created_at: 2023/08/11 00:00:00

cover image


前言

本來應該會在六月底左右就寫這篇文章,不過因為實在是太忙了,所以一直拖到現在才來寫。 (寫完再來還要寫一篇是關於 JavaScript Event Loop 的,不過那篇應該會比較快寫完(?),至少已經把練習的網站寫好了,可以到這邊看)

這一篇主要是紀錄如何在 Github Actions 上面發布 npm 套件,因為我自己在寫 npm 套件的時候常常會忘記更新 package.json 的版本號,所以就想說寫一個 Github Actions 來幫我自動更新版本號,並且發布到 npm 上面。

然後自從自動化之後就回不去了

不過要注意的是,我這邊的版本號並不是遵從 semantic version 這一種規範,而是學 react 的版本號規範,所以如果你是用 semantic version 的話,可能要再去找相應的作法。


為什麼不用 semantic version 的規範

我自己覺得 semantic version 還不錯,可以清晰知道這個版本是做了什麼樣的更新,但在 npm 上版本沒有辦法被刪除,所以如果你發布了一個錯誤的版本,那麼你就只能再發布一個新的版本來修正,而且如果你的套件有很多人在使用(雖然現在沒有QQ),那麼你就只能在發一個 Deprecation Warning 來告知使用者這個版本有問題。(但我就懶惰)

可能會想說在 README.md 上面寫一個警告可能也行,但在 npm 上你要改 README.md 的話,你就必須要發布一個新的版本,所以又回到原本的問題。

所以我的策略是,開發過程走 react 的版本號規範,但發布的時候就走 semantic version 的規範,這樣就可以保證發布出去真的要用的版本都是能用的(理論上如果沒犯蠢的話)

: 我不確定 react 的版本號規範有沒有個名稱,所以就先這樣稱呼吧。


react 的作法

react 的版本號看起來是這樣的:

Version Tag
18.2.0 latest
18.3.0-canary-a20eea251-20230809 next
18.0.0-rc.3 rc
0.0.0-experimental-201becd3d-20230808 experimental
18.0.0-beta-24dd07bd2-20211208 beta
18.3.0-canary-a20eea251-20230809 canary

會注意到說通常在用的(latest)是 semantic version ,而其他的則是 semantic version-tag-hash-date,所以我們就可以在同個 semantic version 下面發布多個版本,直到你覺得這個版本可以發布了,再把後面那一坨刪掉,然後把 tag 改成 latest,這樣就可以保證發布出去的版本都是可以用的。

然後這邊偷偷廣告一下 lai-cmd,因為我自己也有在用,所以我也有在用這個策略來發布版本,如果你想要看看的話可以到這邊看。 只是我目前還沒併回 main,不知道什麼時候會有空去處理他,反正現在用的很快樂,感覺也不急(?)

既然都要廣告了就乾脆上圖 lai-cmd v2

總之就是他會一次幫你把開發工具裝好,讚


平常怎麼發布 npm 套件

上面說了一堆廢話之後,現在來看看怎麼發布 npm 套件。

先假設你一定有 Githubnpm 的帳號,然後我們需要準備一個 repository,然後準備好你要發布的專案。

準備好之後下以下指令:

登入:

$ npm login

然後發布:

$ npm publish

打完收工


看到這邊感覺不麻煩阿,因為麻煩的地方主要在於其他地方,例如上面提到的版本號,這種能自動化幫忙處理的就交給自動化工具,手動常常會忘記。


先做一個專案

這邊用一個最簡單的範例來 Demo,目標很簡單,就是要做一個 Hello Worldnpm 套件,然後他可以用 npx 來執行。

首先開新資料夾,例如這邊建立一個 gh-to-npm-demo 然後切進去初始化專案

$ npm init -y

然後我們要新增一個 index.js,內容如下:

#! /usr/bin/env node
console.log("Hello World")

然後 package.json 要加入一個 bin 的設定(當作可執行文件,這樣你就可以用 npx 執行,甚至全域安裝也可以用):

{
  // ...
  "bin": "index.js",
  // ...
}

這時候你也可以先嘗試手動發布一次,看看有沒有成功,成功的話能不能用 npx 執行。

然後自己玩玩看,然後後面再來接著看怎麼自動化。

如果以我上面這個範例的話,丟上去之後只要下下面這行,就可以印出 Hello World 了:

$ npx gh-to-npm-demo@latest

自動化

在使用之前,必須先到 npm 上面申請一個 tokenGithub 用,這樣才能讓 Github 幫你發布 npm 套件。

所以可以先到自己的 npm 帳號那邊 access tokens 頁面申請一個 token

申請好之後再到 github repositorySettings 頁面,然後點選 Secrets,然後新增一個 secret,名稱為 NPM_TOKEN,然後值就是剛剛申請的 token

github-actions-add-secrets

做好之後就可以開始寫 Github Actions 了。

建立 .github/workflows/publish-dev.yml,內容如下:

name: Publish main
on:
    push:
        branches:
            - develop
jobs:
  publish-to-dev:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'
          registry-url: 'https://registry.npmjs.org'
      - name: Setup env
        run: |
          echo "GITHUB_SHA_SHORT=$(echo ${{ github.sha }} | cut -c -9)" >> $GITHUB_ENV
          echo "CURRENT_DATE=$(date +%Y%m%d)" >> $GITHUB_ENV
      - name: Update package.json version
        run: npm pkg set version=$(npm pkg get version | sed -e 's/^"//' -e 's/"$//')-dev-${{ env.GITHUB_SHA_SHORT }}-${{ env.CURRENT_DATE }}
      - name: Publish to npm
        run: npm publish --tag=dev
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

這裡先假設是送到 develop 分支,然後他會幫你修改 package.json,把版本號改成 dev 的版本,然後指定 tag 發布到 npm 上面。

可以先推到 develop 分支試試看,當他跑成功之後,你就可以像下面這樣使用他

$ npx gh-to-npm-demo@dev

那這時你在開發就可以重複使用一樣的版本號,不用每次都手動改,只有當你要上正式版的時候才需要手動改一下。

這時就要補上一個 Github Actions 來幫你發布正式版了。

建立 .github/workflows/publish-main.yml,內容如下:

name: Publish main
on:
    push:
        branches:
            - main
jobs:
  publish-to-main:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'
          registry-url: 'https://registry.npmjs.org'
      - name: Publish to npm
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

這樣就完成了,之後只要推到 main 分支,他就會幫你發布正式版。

然後用法就是

$ npx gh-to-npm-demo@latest

其實會發現只是把修改 package.json 的部分拿掉,然後 publish 的部分也不指定 tag,這樣就會發布正式版了。


結論

這樣就完成了,今天都是以最簡單的方式來做,所以沒有加上 linttestbuild 等等或是其他的步驟,這些都可以自己再加上去。

設定好之後只要推到 develop 分支,他就會幫你發布 dev 版本,然後推到 main 分支,他就會幫你發布正式版。

其實感覺上也可以包成一個 action,然後直接用 action 的方式來使用,這樣就不用每個專案都要重寫一次一樣的內容了。

但這等我有空的時候再來弄


最後的最後

不要嘗試去跑 npx gh-to-npm-demo 相關的指令,因為我已經把這個套件刪掉了,所以會跑不出來。

因為我只是拿來當範例,確定跑得起來,實際上用不到,就還是刪掉了




最後更新時間: 2023年08月11日.