kevin wang's blog

部署 Gatsby 專案到 Github Page

August 22, 2020

本文會提到

  1. 套用現成 Blog 樣板
  2. 部署到 Github-page
  3. 透過 travis-ci 自動部署

套用 Blog Starter

Gatsby.js 有很多現成的 blog starter,
有些 Starter 真的很不錯,
但我還是決定用官方的 blog-starter 起手,
再依需求改部落格。

一樣從 gatsby new 起手

gatsby new my-blog-starter https://github.com/gatsbyjs/gatsby-starter-blog

首先要調整 gatsby-config.js 內的樣版內容,
如果像我一樣移除掉 twitter 的話,
照著錯誤訊息將剩餘有引用到的地方一併移除即可,
要改的檔案分別是

.
└── src
    ├── bio.js
    └── seo.js

文章都會放在 blog 資料夾,

.
└── content
    └── blog
        └── 你文章的網址
            └── index.md

部署網站

gatsb y產生的是靜態網站,
只需要 host 可以提供靜態網頁瀏覽的功能就可以了,
我選擇使用 Github Page 來 host 部落格。

首先專案安裝 gh-pages 套件來產生發佈頁

npm install gh-pages --save-dev

並新增一個指令
package.json

{
  "scripts": {
    "deploy": "gatsby build && gh-pages -d public -b master"
  }
}

在 Github 也要設定

  1. Github 上建立一個用來發佈用到的 repo,
  2. 到 setting 設定一個並選擇一個分支作為 source(通常選 master)

我是多開一個 develop 分支來放我的部落格原始碼。

如果建立的repo是 {username}.github.io 這樣的命名規範,
就可以直接發佈了,
但如果不是使用 {username}.github.io 這樣的命名規範,
則需要在多增加以下設定

package.json

module.exports = {
  pathPrefix: "/reponame",
}

最後執行

npm run deploy

這樣我們就可以在 {username}.github.io 看到部署好的網站了。


gh-page 與 Gatsby 專案 分離

按照上述過程已經可以產生出一個靜態網站了,
但是這樣我們會直接 deploy 在當前repo的 master 分支,
接下來會實作 blog source 跟 Github page 的 repo拆開。

從上述過程我們已經知道其實部署是依靠以下指令。

gatsby build && gh-pages -d public -b master

其實稍微改一下部署指令就能做到 gh-page 以及實際 Gatsby 專案分離,

首先增加一個 deploy-ghpage.js 在根目錄

deploy-ghpage.js

const ghpages = require('gh-pages');

ghpages.publish(
  'public',
  {
    branch: 'master',
    repo: 你預計發佈的repo位置,
  },
  () => {
    console.log('Deploy Complete!');
  }
);

接下來跟剛剛一樣在 package.json增加一個自訂指令

"deploy:ghpage": "npm run build && node ./deploy-ghpage"

最後執行

npm run deploy:ghpage

就可以部署到gh-page的repo了。


CI/CD

到目前為止我們只需要在 content/blog/ 新增 文章資料夾 以及 編輯文章主體 index.md

開發的時候執行

gatsby develop

發佈的時候執行

npm run deploy:ghpage

就可以發文章了。

但這樣每次發佈的時候都要再打一次指令且在寫文章的機器上執行一輪 release,
如果可以在每次push完後自動做 deploy 發文體驗就會更好。

在花了一些時間尋找方案以後,
我決定用 Travis CI 來部署我的部落格。


前置設定

首先先要先準備好 Travis CI 的帳號,
然後參考 官方教學 連結 travis-ci 與 Github repo,
也可以到 Travis CI 的 setting 頁選擇你的部落格 repo。

參考以下流程

  1. Setting
  2. Manage repositories on GitHub
  3. Repository access 區域內的 Only select repositories 選擇你的部落格repo
  4. 點選 Approve and install

再來要產生 Github token,
到 Github/Settings/Developer settings 內的 Personal access tokens 區塊設定token,
要記得設定完後要記錄起來,
因為下次除了重新產生一組token以外沒有辦法看到token了。

如果是 build public repo 只需要 public_repo 權限,
如果是 build private repo 的話則需要整個 repo 權限。
這部分 Github 官網文件有更詳細的說明

接下來要建立 .travis.yml 在 專案根目錄才能讓 Travis CI 知道要執行什麼樣的任務

參考以下內容

.travis.yml

language: node_js
node_js:
  - "12"
install:
    - npm install
script:
    - gatsby build

由於我在開發機上發佈時的nodejs環境是使用 12,
在yml檔中也是指定 12。
完成後可以先 push 一個版本。

如果沒意外可以在
https://travis-ci.com/github/{username}/{repo name}
看到 Travis CI 會檢查這一次的 push 有沒有問題。

接下來到 https://travis-ci.com/github/{username}/reponame/settings 設定token,
要找到 Environment Variables 這個區塊並設定

Name         |Value           |
GITHUB_TOKEN |剛剛拿到的token  |

小插曲 為什麼不直接使用 deploy:ghpage 指令

其實我一開始是直接寫

script:
    - npm run deploy:ghpage

Travis CI 也真的跑過了,
但是我的 Github Page 卻沒有成功被更新,
思考了一下才想到,
我根本沒有在 build script 裡面指定 token ,
這個 deploy 當然不會過,
加上 build script 沒有顯示錯誤訊息,
才會導致沒有正確上版。

再次修改.travis.yml

設定完 token 也確定 Travis CI 可以完成 build 以後,
接下來要 push 完整的 .travis.yml
這裡使用的 travis 的 deploy 指令。

參考以下設定

language: node_js

sudo: false

branches:
  only:
  - master

cache:
  - npm #保存npm lib 避免每次 Travis CI build的時候會產生全新環境都要先下載一次所有lib

node_js:
  - "12"

before_script:
  - npm install

script:
  - gatsby build

deploy:
  provider: pages
  skip-cleanup: true
  github-token: $GITHUB_TOKEN #剛剛在Travis CI設定的環境變數
  repo: {user/repo-name} # 不填寫就是deploy到當前分支
  local-dir: public #gh-page輸出的是public 資料夾
  keep-history: false
  # target_branch: gh-pages #預備發佈的branch 預設是gh-pages
  on:
    branch: master #source branch

**更詳細的設定可以參考 Travis CI官網文件

最後將設定好的 yml 檔 push 到 master 就完成 Travis CI 自動部署了。

做完一輪,
找了一下文件才發現 private repo build 有一百次的限制
在使用上要注意一下。

ref:

  1. How Gatsby Works with GitHub Pages
  2. Building a JavaScript and Node.js project
  3. GitHub Pages Deployment