改造 Blog 使用 Eleventy 與 Cloudflare Pages

2024-11-11

說明

伴隨著 GitHub Copilot Edits 的測試,發現 Eleventy 可以用於靜態網頁的生成 (Server Site Generator)。原本的部落格是使用 Hexo 進行生成並且部署在 GitHub Pages 上,四年多的使用期間沒有太大的問題,但偶有的擴充需求,受限於自己有限的 Node.js 能力總是作罷。

這次的改造結合 GitHub Copilot Edits 直接透過描述的方式讓 Copilot 能夠幫忙生成多檔案的編輯,同時也將 CSS Framework 加入到部落格中,簡化原本在 Hexo Style 過多的 inline,讓自己對於整體部落格樣式的控制更加容易。

使用 Eleventy

起心動念想要使用 Eleventy 的原因是可以使用資料檔案來生成網頁,在 Copilot Edits 的協作下,實驗了如何 fetch 資料 API 來生成網頁,對於有批次生成資料的需求會非常方便。

使用 Eleventy 所有的設定都是集中在 .eleventy.js 檔案中,包含元件的使用、資料流程的設定與資料輸出入等等,透過 Copilot Chat 的問答之間,沒有花太多的時間翻查文件,一邊開發一邊詢問的過程中,慢慢就熟悉了 Eleventy 的初步使用方式。

轉換部落格

Tailwind CSS

以往在 Hexo 的開發過程,是使用已經具有主題的 SASS 進行樣式設計,沒有 Utility Class 可以使用。而這次的開發誤打誤撞,沒有使用相對更為熟悉的 Bootstrap 進行開發,而是使用了 Tailwind CSS (特色是有方便的 Utility Class,但沒有預設的元件可以使用。)

引入的方式按照 Copilot 所提供的建議,結合了 postcssautoprefixer 進行 CSS 的編譯,預設上 Tailwind 在編譯的過程中移除沒有使用到的 Class,有效減少最後 CSS 檔案的大小。

  eleventyConfig.on('beforeBuild', async () => {
    const cssFile = path.join(__dirname, './src/css/style.css');
    const destDir = path.join(__dirname, './_site/css');
  
    // 確保目標目錄存在
    fs.mkdirSync(destDir, { recursive: true });
  
    // 讀取並處理 CSS
    try {
      const css = fs.readFileSync(cssFile);
      const plugins = [
        require('postcss-import'),
        require('tailwindcss'),
        require('autoprefixer')
      ];
  
      if (process.env.NODE_ENV === 'production') {
        plugins.push(require('cssnano')({
          preset: ['default', {
            discardComments: { removeAll: true },
            minifyFontValues: false,
            colormin: false
          }]
        }));
      }
  
      const result = await postcss(plugins).process(css, {
        from: cssFile,
        to: path.join(destDir, 'style.css'),
        map: false
      });
  
      fs.writeFileSync(path.join(destDir, 'style.css'), result.css);
      if (result.map) {
        fs.writeFileSync(path.join(destDir, 'style.css.map'), result.map.toString());
      }
    } catch (error) {
      console.error('Error processing CSS:', error);
    }
  });

在撰寫 CSS 檔案時,也可以透過 @apply 的方式來使用 Tailwind 既有的 Utility Class,非常方便。

@tailwind base;
@tailwind components;
@tailwind utilities;

.markdown h1 {
    @apply text-4xl font-bold mb-8 text-gray-800;
}

以往在 Hexo Theme SASS 的模組化程度較高,但在本次的遷移過程中,簡化成單檔 CSS 並相容以往針對 Blog 特殊樣式進行相容,順利的解決在 Eleventy CSS 的管理。

Markdown 轉換

主要的處理是針對 FrontMatter 的資料去處理。原本在 Hexo 當中有 <!-- more --> 的標籤會自動判斷預覽內容與圖片,但這次轉換時直接處理成 FrontMatter 的 Excerpt 與 Image,優點是設計文章樣式的時候更好操作,但在編輯上則會稍微麻煩,需要主動去設定 Excerpt 與 Image。

此外以前的部落格有 Category 與 Tag 的區別,Category 是主題,每篇文章只會有一個主題,而可以有多個 Tag 標籤,但這次透過資料處理,把文章的 Category 加回到 Tag,並且移除掉 Tag,讓文章的分類簡化。

Search, Tags and Archive

配合文章分類的簡化,新的部落格則是強化了搜尋功能,以前的搜尋僅支持標題搜尋,現在支援對於標題、標籤與文章網址進行搜尋,搜尋正確結果的簡便性大幅提高。

以往是透過 jQuery 與 lodash 的方式去處理搜尋。這次則加入了輕量的雙向綁定框架 Alpine.js

Archive 文章庫存同樣使用 Alpine.js 進行處理,取代以往多 HTML 頁的方式,速度上並沒有因此犧牲,反而更有互動性,同時可以一目了然每月、每年的文章數量,實現了長久以來的心願 😄

Tag 的變化則是從原本單純找到同標籤的文章以外,還增加了標題搜尋功能,免去以往需要透過 Ctrl + F 的方式找到文章的麻煩。

而上述的功能能夠順利的實現,有賴於 Eleventy 的資料處理能力以及 Nunjucks 的模板引擎,讓我可以更加靈活的處理資料與模板的關聯,同時藉由描述性的方式請 Copilot Edits 進行處理 (過程中混合使用 Cluade 3.5 與 ChatGPT 4o,前者對於問題解決較有幫助,後者則是簡單的問題速度快,各有應用場景),開發的過程極少在逐行程式碼之間苦思,而是反覆的詢問與測試。

寬螢幕利用

原本部落格文章的呈現方式,最上方是顯示 TOC 資訊,提供文章目錄與文章內快速連結。這次的改造藉由固定式區塊的呈現方式,將 TOC 資訊呈現在文章左側,並在文章右側加入相關文章的顯示,提供使用者沒有盡頭的閱讀體驗 😊

開發的過程很享受 Copilot Edits 的協助,透過描述式的開發方式,幾輪調整就完成自己想要的樣式。

遷移與部署

本次的部落格改造的兩大重點,除了使用 Eleventy 作為新的靜態網頁生成器外,另外一個重點是將部落格的部署平台從 GitHub Pages 遷移到 Cloudflare Pages。

近日才將部落格透過 Cloudflare 反向代理,解決部分地區連線的速度問題,而在操作過程中驚訝發現 Cloudflare 也提供了靜態網頁部署的服務 Cloudflare Pages,在簡單比較後發現,Cloudflare 的頁面速度更快,比 GitHub Action 更為簡易的編譯與部署設定方式,於是就決定調整部署平台。

調整的操作是在 Cloudflare 的 DNS 設定當中,將原本的 A Record 移除,改為加入 root domain 指向 Cloudflare Pages 與設定 www.domain 的 CNAME 指向就完成了,設定與啟用的過程在五分鐘之內就可以完成生效,非常快速 ⚡

結論

整個遷移的過程大約費時一星期,如果沒有 GitHub Copilot,可能會無疾而終或者是遙遙無期完成整的遷移。透過 GitHub Copilot 並且在良好工具的基礎上 (Eleventy, Nunjucks, Tailwind CSS & Alpine.js) 進行開發,讓整個遷移的過程非常順利,

在完成網站部署後使用 Google PageSpeed Inshts 進行測試,電腦環境取得完全滿分,Mobile 則是在效能取得 94 分,因此試圖要從 HTML Minify 以及 CSS Minify 著手。

但再加入 html-minify 以及使用 cssnano 分別進行壓縮後,部署確有問題,其中一個原因是與 Cloudflare 設定環境變數 NODE_ENV 相關,另外則是 HTML Entites 與壓縮 HTML 的處理,這邊目前還沒有解決。

另外目前的文章數近 850 篇的情況下,npm run serve 約 15 秒的時間才會啟動,有些調整 (.eleventy.js) 需要重新啟動時,反覆地等待較為煩人,雖然以往在 Hexo 也是類似,但對於這個痛點沒有解決還是略為遺憾。

未來還想實作的功能是對於系列文章的處理與呈現,把系列文章進行分類,讓尋找更為輕鬆與便利,也增強撰寫系列文章的動力 😊