個人網站遷移之旅:從部落格到知識庫,從 Hexo 到 Docusaurus

MarkDay發表於2021-11-13

或是出於跟風,或是為了簡歷能好看點,2020 年 2 月,在翻看了中文網際網路大量的「免費個人網頁搭建教程」後,我選擇了 Hexo + Github Pages 的方案,找了一款看上去還不錯的主題,搭建了自己的第一個部落格網站。

很難量化我在這接近兩年的時間裡有了什麼成長,我迎來了一學期的網課(甚至期末考試都是線上),見證了前所未有的生活方式的轉變(從此社恐人可以合理戴口罩了),學習了更多的計算機專業課知識(雖然已經忘光),寫了更多的漢字(我都不好意思說能叫文章),體驗了一邊在網際網路企業 996 一邊趕學期大作業 Deadline 的生活(然後現在推行「1075工作制」),準備考研又開始準備找工作,準備找工作又準備 Gap 去支教……

這之中大概還是有很多值得記錄的吧,然而從結果上看我並沒有留下什麼,因此我也開始思考就我個人的情況而言,用時間軸將文章串聯起來的部落格,是否是個人網站最合適的載體。

你需要的怎樣的個人網站?

知乎、簡書、部落格園、微信公眾號……那些優秀或不那麼優秀的寫作平臺已經有很多很多。而選擇獨立於這些大平臺,去運營自己的個人網站,這件事多少帶點理想主義色彩——個人網站缺乏穩定的流量來源,在國內更是需要備案等操作,雖然能免於平臺稽核的等待,但更多時候恐怕只是小圈子的孤芳自賞。

而我最早是為什麼開始寫文章的呢?雖然「nobody cares」,但我現在想想依然覺得有些不可思議,當時的自己為什麼有勇氣做這種事(順帶一提我突然想起了粉絲剛剛破一萬時我是如何聲情並茂地和舍友講了一下午我是怎麼漲粉的的黑歷史,太尷尬了,現在我已經忘了當時他的臉上是怎樣的神情)。

搭建個人網站則主要是為了尋找一種將所學知識歸類展示的渠道,希望可以通過筆記避免知識的遺忘。從我之前在 Hexo 上釋出的部落格來看,我釋出的內容以課程內容、軟體技巧為主,這些內容一般有比較明確的分類和標籤,比起瀑布流式的文章,更適合用樹狀的Docs進行整理,這也成了本次遷移到 Docusaurus 的主要動力。

Hexo 有哪些不適合你的地方?

在使用 Hexo 的過程中,我主要遇到了以下痛點(事實上很多痛點都是技術菜所導致的):

  • Node 版本問題:此前 Hexo 在 Node 14.x 以上版本執行時會存在相容問題(我不清楚現在是否解決了),網上的資料通常是建議將 Node.js 降級至 12.x 版本使用。為此我不得不安裝 nvm 管理電腦上不同的 Node 版本,每次寫部落格前還需要切換 Node 環境,在一定程度上打擊了創作積極性。
  • 不夠省心的客戶端:體驗過幾個 Hexo 客戶端,感覺介面和自己的期待有些差距,使用時也會遇到一些小問題,於是又回到了命令列建立新部落格的方式。
  • 瀑布流式的文章組織方式:雖然 Hexo 提供了標籤、分類等功能,但是沒有進一步的層級關係,標籤過多也不利於日後覆盤。因此,文件式的知識庫也許更符合我的需求。
  • 較高的主題定製門檻:我使用的是從 Github 上找的 Hexo 主題,作者主要使用 JQuery 開發,然而我在前端上學藝不精,只會站在 React、Vue 的肩膀上修修補補,似乎除了改改主題顏色就沒有別的能做的事情了。
  • CI/CD 部署問題:之前建立部落格時沒有使用 CI/CD,每次更新 Github Pages 都需要經過「寫部落格 → 生成靜態頁面 → 上傳到 Github」的過程,所以這次採用 Docusaurus 構建個人知識庫時就用了自動部署。

Docusaurus 是什麼?有哪些優勢?

Docusaurus 是一款基於 React 構建的站點生成器,可用於構建文件網站、部落格、營銷頁面(落地頁)等。

  • Docusaurus 的文件和部落格功能都是開箱即用的,背靠 Facebook 開源專案團隊(現在應該叫 Meta ?),官方文件對於中文的支援也很友好,主要功能都能在文件上找到。
  • 支援在 Markdown 語法中嵌入 React 元件,此外還有豐富的外掛庫,比如能線上執行的程式碼執行器等,可以進一步豐富個人網站的功能。在這次的遷移過程中我就用 Infima 的 Note 元件美化了遷移資訊。
  • Docusaurus 是一款 React 應用程式,對於曾在「軟體工程」課上被 React + Typescript 折磨的我來說,我對於 React 語法比較熟悉,可以嘗試增加自己所需的功能。
  • 顏值高:第一眼看上去感覺 Docs 很像 Gitbook,自身的配色我感覺也挺不錯,之後可能會微調下標題字號。

當然,經過近一週的使用我也發現了一些小問題:

  • 標籤功能並不好用:Docusaurus 會將標籤按照首字母進行分類,英文標籤還好,中文標籤則每一個單字都會成為一個分類。
  • 暫時還沒有評論功能:Docusaurus 支援新增文件搜尋模組,但我還沒找到類似 Gitalk 的評論外掛(雖然這個功能也沒啥必要)。
  • 同樣缺乏 GUI:好在 Docusaurus 會自動根據 docs 下的目錄樹劃分文件層級,便於建立個人知識庫。部落格則需要在標題中註明時間與題目,可能需要自己寫一個簡單的指令碼。
  • 導航欄定製問題:Docusaurus 採用 Infima 的Navigation Bar 元件,通過注入的方式設定導航欄引數。原生導航欄定製自由度不高,好在可以放棄引入,自行編寫導航欄(從「Docusaurus 站點展示 | Docusaurus 中文文件 | Docusaurus 中文網」裡的原始碼學到的)。

目前 Docusaurus v2 還是 beta 版本,社群很活躍,看好這個工具的前景。

從 Hexo 遷移到 Docusaurus 需要幾步?

忍不住講起某個大象與冰箱的笑話,雖然我一直感覺這個笑話好冷。HexoDocusaurus 的 Front-matter 存在部分命名上的差異,好在它們都是用 YAML 格式組織的,因此我寫了兩個簡單的 Ruby 指令碼(Github 倉庫地址),可以提取出原先在 Hexo 生成博文的時間戳、標題、標籤、分類等資訊,將其分別轉換為 Docusaurus 格式的文件和部落格 Markdown。

#!/usr/bin/ruby

require 'pathname'
require 'tmpdir'
require 'yaml'

def copy_not_null_array(hexo_yaml_info, hexo_key, docusaurus_yaml_info, docusaurus_key)
  if hexo_yaml_info[hexo_key]
    if hexo_yaml_info[hexo_key].class != Array
      docusaurus_yaml_info[docusaurus_key] = [hexo_yaml_info[hexo_key]]
    else
      docusaurus_yaml_info[docusaurus_key] = hexo_yaml_info[hexo_key]
    end
  end
end

def parse_markdown_file(filepath)
  output_directory_name = "./output"
  text_all = File.read filepath.to_s

  # 分割博文的頭部和正文
  begin_split = text_all.index('---')
  unless begin_split
    return
  end
  end_split = text_all.index('---', begin_split + 1)
  head = text_all[0, end_split]
  body = text_all[end_split + 4, text_all.size]

  # 讀取YAML頭部資訊
  temp_filename = File.join(Dir.tmpdir, "yaml_head.temp")
  temp_file = File.new(temp_filename, "w")
  temp_file.puts head
  temp_file.close
  hexo_yaml_info = YAML.load_file(temp_filename)
  File.delete(temp_filename)

  # 遷移所需的YAML資訊
  # - Docusaurus文章屬性: https://www.docusaurus.cn/docs/blog#header-options
  blog_name = hexo_yaml_info['title'].gsub(/[()]/, '('=>'「', ')'=>'」')

  docusaurus_yaml_info = Hash.new
  docusaurus_yaml_info['authors'] = 'mondaycha' # 在authors.yml中完善資訊
  # docusaurus_yaml_info['author_url'] = 'https://github.com/MondayCha'
  # docusaurus_yaml_info['author_image_url'] = 'https://github.com/MondayCha.png'
  # docusaurus_yaml_info['author_title'] = '我逐漸理解了一切(完全沒理解)'
  docusaurus_yaml_info['title'] = blog_name
  docusaurus_yaml_info['date'] = hexo_yaml_info['date'].strftime("%Y-%m-%d %H:%M:%S")
  copy_not_null_array(hexo_yaml_info, 'tags', docusaurus_yaml_info, 'tags')
  copy_not_null_array(hexo_yaml_info, 'categories', docusaurus_yaml_info, 'keywords')
  if hexo_yaml_info['photos'] and hexo_yaml_info['photos'][0]
    docusaurus_yaml_info['image'] = hexo_yaml_info['photos'][0]
  end

  # 將新頭部和正文寫入檔案
  unless File.directory? output_directory_name
    Dir.mkdir(output_directory_name, 755)
  end
  create_time = hexo_yaml_info['date'].strftime("%Y-%m-%d") # 時區有問題,待修復
  title = hexo_yaml_info['title']
  output_filename = File.join(output_directory_name, create_time << '-' << blog_name.gsub(' ','-') << '.md')
  if File.file? output_filename
    File.delete(output_filename)
  end
  output_file = File.open(output_filename, 'a+')
  output_file.puts docusaurus_yaml_info.to_yaml

  # 生成摘要,否則縮略頁不忍直視
  truncate = "---\n<!--truncate-->"
  output_file.puts truncate
  output_file.puts body
  output_file.close
end


directory_name = "./"
file_list = Pathname.new(directory_name).children.select { |c| c.to_s.match('.*.md$') }
file_list.each do |filepath|
  puts filepath
  parse_markdown_file(filepath)
end

將指令碼放在 Hexo 目錄下的 \source\_posts資料夾下,與此前建立的博文平級,之後執行指令碼即可獲得適用於 Docusaurus 的 .md檔案。

從零開始的 Docusaurus 配置生活

1. 環境配置

以 Windows 系統為例,需求 Node.js 版本 ≥ 14,最好選擇 Yarn 作為你的包管理工具。從官網下載 Node.js 的安裝包並安裝完成後,確保 Node.js 已經新增到了環境變數中:

PS F:\FuckNPM\l1lBlog> node -v
v16.13.0

使用自帶的 npm 完成 Yarn 的安裝,正如曾幾何時 Edge 開啟的第一個與最後一個網頁就是 Chrome 下載頁。

npm install -global yarn
yarn config set registry https://registry.npm.taobao.org/ # 使用淘寶維護的npm映象源
yarn config set proxy http://XX
yarn config set https-proxy http://XX

2. 初始化網站

Docusaurus 已經提供了一個模板(或者說 Scaffold?),我在 Github 上也看到有人做的精簡後的模板。如果你已經完成了 Node.js 和 Yarn 的安裝,那麼只需要幾行命令就能很快啟動網站:

npx create-docusaurus@latest my-website classic
cd my-website
yarn start

部署完成後,如果 3000 埠沒有被佔用,那麼訪問 localhost:3000 就能看到提供的模板頁面了。

3. 創作你的創作

如果你已經有 Hexo 博文,那麼正如上一節,將博文的 Front-matter 轉換後放入根目錄下的blogdocs資料夾。可以參見官方文件中的說明,非常詳細。

4. 最期待的 CI/CD 環節

我選擇使用 Github Pages 進行部署,先參考「部署 | Docusaurus 中文文件 | Docusaurus 中文網」一節,修改docusaurus.config.jsmodule.exports部分,否則 Github Actions 會顯示無權訪問,因為你把網頁部署到 Facebook 那裡去了……

參考「部署 | Docusaurus 中文文件 | Docusaurus 中文網」一節進行 ssh key 的設定,由於我並非生成某個 Github 專案的文件頁,而是生成 Github 的根部落格,官方提供的documentation.yml程式碼並不能很好執行,在參考了其他專案後,我使用瞭如下配置檔案:

name: documentation

on:
  push:
    branches: [documentation]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      # checkout && nodejs 
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '15'

      - run: yarn install && npm run build
      
      # delopy
      - uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./build

我的 Github 專案分支結構可以參考「MondayCha/MondayCha.github.io: MondayCha's blog, made with Docusaurus v2.

至此就完成了從 Hexo 到 Docusaurus 的遷移與部署工作了,如果說您有疑問的話也可以在評論區或 Github Issue 區留言,我有看到就會回覆的。

相關文章