1. 程式人生 > 實用技巧 >使用 Github Actions 自動部署 Angular 應用到 Github Pages

使用 Github Actions 自動部署 Angular 應用到 Github Pages

前言

最近在學習 Angular,一些基礎的語法也學習的差不多了,就在 github 上新建了一個程式碼倉庫,準備用 ng-zorro 搭個後臺應用的模板,方便自己以後寫些小東西時可以直接使用。前端專案,最主要的還是能夠實際看到,因此考慮找個地方部署,因為自己的部落格是部署到 github page 上的,並且這個專案也只是一個靜態網站,所以這裡同樣選擇使用 github page

同時,考慮到釋出專案時,雖然使用 github page 已經幫我們省略了拷貝檔案到伺服器上這一步,但是還是需要自己手動的敲命令來完成專案的釋出,因為釋出的流程很單一,所以這裡選擇通過 github action 這個自動化工具來實現程式的自動化部署

程式碼倉庫地址:ingos-admin

預覽地址:https://yuiter.com/ingos-admin

Step by Step

2.1、手動部署

示例的 Angular 應用,你可以通過 Angular CLI 直接生成,如有需要,可以點選此連結進行跳轉檢視(電梯直達),這裡就不演示建立的過程了

按照正常的前端專案釋出流程,當我們需要釋出時,需要使用 npm 命令來完成專案的打包。整個專案中所涉及的 npm 命令,我們可以通過查閱專案的 package.json 檔案中的 scripts 節點進行檢視

這裡通過 Angular CLI 建立的專案可以通過 ng build 命令來完成專案的打包釋出

當 build 命令執行完成後,專案根路徑下 dist 資料夾中以專案名稱命名的資料夾就是我們需要部署的檔案。此時,如果是部署到自己的伺服器上,只需要把這個資料夾拷貝到伺服器上,通過 nginx 之類的伺服器指向檔案所在路徑即可

同樣的,當我們想要部署到 github page 時,我們也只需要將檔案提交到 github 程式碼倉庫中即可,之後 github 會自動完成應用的部署工作

因為 git 預設是會忽略編譯生成的 dist 資料夾的,此時,想要把編譯生成的檔案推送到遠端倉庫,你需要修改 .gitignore 檔案,或是通過 subtree 的形式,將 dist 資料夾作為一個分支推送到遠端伺服器

# 建立並切換到 gh-pages 分支
git checkout -b gh-pages
# 將 dist 資料夾下的檔案新增到 gh-pages 分支
git add -f dist
# 提交到本地分支
git commit -m 'created gh-pages'
# 推送到遠端分支
git subtree push --prefix dist origin gh-pages

當然,這樣還是顯得有些麻煩,對於 angular 應用來說,我們完全可以使用社群提供的 angular-cli-ghpages 外掛來簡化這個操作

首先我們需要通過 npm 將外掛安裝到需要部署的程式中

ng add angular-cli-ghpages

安裝完成之後,我們就可以通過 ng deploy 命令來完成部署,外掛會自動把打包生成的檔案釋出到 github 上,並建立一個 gh-pages 分支作為 github page 顯示的站點

ng deploy --base-href=/ingos-admin/

在之前學習 angular 中路由時有提到,在 angular 應用中,框架會將 index.html 檔案中的 base 標籤的 href 屬性值配置為元件、模板、模組檔案以及其它一些靜態檔案的基礎路徑地址。而當我們將程式部署到 github page 時,實際對應的網站地址是 https://<username>.github.io/<repositoryname>,因此,這裡如果不指定 href 的話,程式會在根路徑下去尋找站點相關的靜態檔案,毫無疑問,最終是無法找到的,所以這裡我們需要調整 href 屬性值 為我們的倉儲名稱

可以看到,在打包生成的 index.html 檔案中,外掛已經幫我們修改了 base 標籤的 href 地址。以後當我們需要更新網站時,再使用上面的命令即可釋出到 github page 上

因為每次執行 ng deploy 命令時都需要在命令中新增 base-href 引數,所以這裡我們可以在 package.json 檔案中新增一個 script,這樣當後面我們需要釋出時,直接執行自定義的 ng deploy 命令即可

{
"name": "ingos-admin",
"version": "1.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"deploy": "ng deploy --base-href=/ingos-admin/",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
}
}

2.2、自動部署

在上面的操作中雖然實現了將程式部署到 github page,但是還是需要我們手動的通過 npm 命令來完成部署,接下來就進行改造,通過 github actions 來實現自動部署

github actions 與其它的各種自動化工具相似,允許我們通過指定特定的 git 事件來觸發我們的自動化任務,例如這裡我需要在推送程式碼到伺服器的 master 分支時自動觸發程式的釋出事件

你可以在程式碼倉庫的 Actions tab 頁面新增一個 workflow,也可以直接在原生程式碼根路徑中新建一個 .github/workflows 資料夾來存放相關的指令碼,因為 github actions 的執行指令碼採用的是 yaml 格式,所以這裡對於程式碼格式有著嚴格的要求,而每一個 yaml 檔案則是一個單獨的 workflow

這裡我通過直接調整 github 預設的 workflow 檔案來實現自動化部署功能,整個 yaml 檔案包含了如下的三個部分

  • name:當前 workflow 配置的名稱
  • on:任務觸發時機,這裡是在向 github 上的 master 分支提交程式碼以及提交 PR 時進行觸發
  • jobs:需要觸發的任務資訊,一個 workflow 可以包含多個的 job,這裡只有一個名為 build 的 job
# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [master]
pull_request:
branches: [master] # A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/[email protected] # Runs a single command using the runners shell
- name: Run a one-line script
run: echo Hello, world! # Runs a set of commands using the runners shell
- name: Run a multi-line script
run: |
echo Add other actions to build,
echo test, and deploy your project.

一個 workflow 檔案中最重要的就是包含的 jobs,它表明了當前 workflow 所能實現的功能,一個 job 任務主要包含了如下的屬性

  • runs-on:當前 job 需要執行在的系統環境
  • steps:實現一個 job 需要執行的各個步驟
  • env:當前 job 執行時需要的各種環境變數
  • needs:當我們定義多個 job 時,預設是並行執行的,但是存在 job2 需要等 job1 執行完成後才可以執行的情況,這時,我們就可以在 needs 屬性中指定 job2 依賴於 job1,從而確保整個 workflow 的正確執行

在 steps 節點中,定義了當前 job 需要執行的各個步驟,step 分為兩種,一種是我們使用 users 屬性來直接引用別人已經發布的 action,例如這裡通過引用 github 官方的 actions/[email protected] 在宿主機中執行 git checkout 命令來拉取程式碼;另一種,則是我們通過 run 屬性來手動編寫指令碼

對於我們想要的實現的功能,其實只包含了如下的四步:拉取程式碼 =》安裝 node.js 環境 =》還原依賴 =》部署釋出

對於拉取程式碼以及安裝 node.js 環境,我們可以使用 github 官方的 action 來簡化我們的指令碼,因為我們在每次構建時都需要執行 npm install 命令來還原專案所需的各種依賴,因此這裡在執行 install 命令之前,我們可以通過官方的 actions/[email protected] 來快取專案依賴,以加快構建的過程

這裡在還原依賴時,使用到了 npm ci 而不是 npm install,從命令的名稱就可以看出,ci 主要是在各種自動化環境構建時使用,通過讀取 package-lock.json 檔案中所包含的具體的依賴版本資訊來加快還原過程

steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/[email protected] # Install node js
- name: Setup Node.js environment
uses: actions/[email protected]
with:
node-version: 12.x # Cache node modules
- name: Cache node modules
uses: actions/[email protected]
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}- # Install required dependencies to build app
- name: Install dependencies
run: npm ci

當還原完成之後,就可以執行 package.json 檔案中的 deploy 命令了,這裡需要注意,因為在 action 中執行的命令更多的都是隻讀許可權,所以為了能夠有足夠的許可權執行釋出操作,我們需要在執行時在環境變數中附加上 GITHUB_TOKEN 變數

steps:
# Use angular-cli-ghpages to deploy app
- name: Deploy to github pages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run deploy

secrets.GITHUB_TOKEN 因為是 github 預設建立的,因此我們可以在 workflow 中直接使用,而對於一些另外需要授權的服務,直接將密碼寫在 yaml 檔案中會不安全,這時你就可以在程式碼倉庫的 settings tab 下通過設定 secrets 金鑰資訊,然後就可以通過變數的方式在 workflow 中直接使用

當我們添加了環境變數之後,還需要對我們的實際執行的 npm 命令指令碼進行一個調整

在本地執行釋出命令時,本地的 git 配置中已經包含了相關的賬戶資訊,而當在 workflow 中執行時因為處於一個匿名的狀態,angular-cli-ghpages 沒辦法知道具體的執行人是誰,因此,我們需要在 ng deploy 命令中新增上 git 賬戶相關的配置引數

{
"name": "ingos-admin",
"version": "1.0.0",
"scripts": {
"deploy": "ng deploy --no-silent --base-href=/ingos-admin/ --name='賬戶名' --email='密碼'",
}
}

至此,完整的 workflow 指令碼如下,當我們將原生程式碼推送到 github 倉庫時,就會自動完成程式的釋出部署

# This is a basic workflow to deploy angular app into github pages
name: Deploy Github Pages # Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [master] # A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/[email protected] # Install node js
- name: Setup Node.js environment
uses: actions/[email protected]
with:
node-version: 12.x # Cache node modules
- name: Cache node modules
uses: actions/[email protected]
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}- # Install required dependencies to build app
- name: Install dependencies
run: npm ci # Use angular-cli-ghpages to deploy app
- name: Deploy to github pages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run deploy

這裡需要需要注意,因為程式碼中包含了 workflow 檔案,可能在推送到 github 時遇到如下的錯誤,此時需要我們對 access token 進行重新的設定

開啟 GitHub Personal Access Tokens 頁面,點選右側的 Generate new token 按鈕,選擇新建一個 token 資訊,在編輯許可權時確保 workflow 有被勾選上,

複製生成的 token 資訊,開啟電腦的憑據管理器,在 Windows 憑據標籤內,找到 github 相關的憑據,此時你可以將已經存在的憑據密碼更新成剛才複製的 token 資訊,或者直接將已經存在的 github 憑據刪除,這樣再推送到 github 時會要求你進行登入,重新登入時將密碼錄入為你複製的 token 資訊即可

當推送成功之後,再次點選程式碼倉庫的 Actions 選單,則會顯示已經執行的 workflow 記錄,當我們點選具體的一個 workflow 記錄,則可以顯示出 workflow 中每個步驟的執行詳情,你可以根據執行情況自行調整,至此,也就完成自動化部署的功能

參考

  1. GitHub Actions 入門教程
  2. 是時候體驗一下github action的魅力了
  3. npm-ci
  4. Git Extensions is a great tool but the credential management is very weak