﻿# 如何讓 Node.js 應用程式在 GitHub Action 大幅提昇 CI/CD 執行效率

我手邊有個 Next.js 的應用程式，在設定 GitHub Action 的 CI/CD 自動部署到 Azure Web App 的過程，在 CI 的 `actions/upload-artifact@v2` 這個步驟花費了超級大量的時間上傳 `node_modules` 資料夾中的檔案，實在是太沒效率了。因此我改在上傳前壓縮整個目錄，結果整體 CI/CD 的時間直接從 `26m 34s` 降到 `8m 58s` 之多，部署效率大幅提升。今天這篇文章我就來說說我的寫法。

![GitHub Action Workflow](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/03979c13e35c3b7dda10-227678940-e043cdd6-180d-4fb3-b3f7-87481073b79d.jpg)

以下是我的第一版 GitHub Action 的 Pipeline 定義：

```yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions

name: Build and deploy Node.js app to Azure Web App - promptingguide

on:
  push:
    branches:
      - zh-tw
  workflow_dispatch:

jobs:
  build:
    runs-on: windows-latest

    steps:
      - uses: actions/checkout@v2

      - name: Set up Node.js version
        uses: actions/setup-node@v1
        with:
          node-version: '18.x'

      - name: npm install, build, and test
        run: |
          npm install
          npm run build --if-present
          npm run test --if-present

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v2
        with:
          name: node-app
          path: .

  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'Production'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v2
        with:
          name: node-app

      - name: 'Deploy to Azure Web App'
        uses: azure/webapps-deploy@v2
        id: deploy-to-webapp
        with:
          app-name: 'promptingguide'
          slot-name: 'Production'
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_4915FCCCD4F747A2BAEEE6861ADFA577 }}
          package: .
```

由於這是一個 [Next.js](https://nextjs.org/) 應用程式 (Node.js)，所以我將 build agent 從 `windows-latest` 更改為 `ubuntu-latest`，理論上 Node.js 都是跨平台的，不太會出什麼大問題，除非有用到什麼平台相關的 npm 套件才會出錯。

這裡我一定要選擇用 `ubuntu-latest` 的原因，就是 Linux 底下有內建一個 `zip` 與 `unzip` 工具，壓縮/解壓縮目錄特別方便。如果一定要在 `windows-latest` 的話，可以改用 [7-Zip](https://www.7-zip.org/) 或 PowerShell 來進行壓縮/解壓縮動作。

我修改後的 git diff 示意圖如下：

![修改後的 git diff 示意圖](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/51bdf1b6df19207c00e3-227676860-1824b996-d314-4cc5-9937-f78bf146165a.jpg)

完整的 GitHub Action Pipeline 內容如下：

```yaml
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions

name: Build and deploy Node.js app to Azure Web App - promptingguide

on:
  push:
    branches:
      - zh-tw
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: Set up Node.js version
        uses: actions/setup-node@v1
        with:
          node-version: '18.x'

      - name: npm install, build, and test
        run: |
          npm install
          npm run build --if-present
          npm run test --if-present

      - name: Zip artifact for deployment
        run: |
          zip release.zip . -r

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v2
        with:
          name: node-app
          path: release.zip

  deploy:
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'Production'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v2
        with:
          name: node-app

      - name: unzip artifact for deployment
        run: |
          unzip release.zip
          rm release.zip

      - name: 'Deploy to Azure Web App'
        uses: azure/webapps-deploy@v2
        id: deploy-to-webapp
        with:
          app-name: 'promptingguide'
          slot-name: 'Production'
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_4915FCCCD4F747A2BAEEE6861ADFA577 }}
          package: .
```

### 補充說明：PowerShell 的壓縮、解壓縮指令

1.  壓縮目錄
    
    ```powershell
    Compress-Archive * release.zip
    ```
    
    > 注意: 這裡用 `*` 而不是 `.` 是為了避免壓縮時產生額外的資料夾出現在壓縮檔中第一層！
    
2.  解壓縮目錄
    
    ```powershell
    Expand-Archive release.zip -DestinationPath .
    ```
    
    > 注意: 這裡用 `-DestinationPath .` 是為了避免解壓縮時產生額外的資料夾出現在當前目錄！
    

### 相關連結

-   [node.js - How to archive files in artifact for github workflow actions in order to fix this warning? - Stack Overflow](https://stackoverflow.com/a/69402502/910074)
-   [GitHub Actions Documentation](https://docs.github.com/en/actions)
    -   [About workflows](https://docs.github.com/en/actions/using-workflows/about-workflows)
        -   [Workflow syntax for GitHub Actions](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions)
