FR-047 SPEC 手冊站台 — 側欄/CSS/JS 外部共用檔重構 SUMMARY

項目 內容
日期 2026-07-20
觸發 新增 Release Notes 頁面那次 commit 一次動了 323 個檔案,暴露 build 機制的結構問題
Tag v1.9.0(沿用既有版號,不視為新 release,pyproject.toml1.9.0;未 push)
Commits dfc6ecc6(重構本體)、852b0e55(analysis 文件 + docstring)
§1

為何做

scripts/deliverables/render_html.py 原本把全站 CSS(206 行)、lightbox JS(85 行)、 以及完整側邊欄 <nav> HTML 全部內嵌進每一個輸出的 .html 頁面。三個版本目錄 (current/v1.9.0/v1.8.0)合計 273 個頁面,每個都帶一份幾乎一模一樣的複本。

任何「側欄結構」變化(新增一頁、調整 NAV 分組)都會讓該版本目錄下全部頁面被 重新 render——因為側欄 HTML 是 build time 算好、字串拼接進每一頁的。這次觸發點是 新增 Release Notes 頁面那次 commit 動了 323 個檔案,邏輯上很小的改動卻在 git diff 上難以核對「是不是只有側欄段落變了」。

§2

做了什麼

把 CSS、lightbox JS、側欄渲染邏輯抽成外部共用檔,側欄改成瀏覽器端 JS 動態渲染:

  • 新增 docs/specs/_shared/site.css(跨三版本共用的靜態全站樣式)
  • 新增 docs/specs/_shared/site.js(lightbox 邏輯原樣搬移 + 新側欄渲染邏輯: fetch nav-data.json → 動態組 DOM → 綁收合事件;file:// 開啟時 fetch() 會被 CORS 擋下,此時側欄顯示明確可見的錯誤提示,非沉默空白)
  • render_html.py
    • build_nav() 拆成 nav_data(pages, src) 純資料版(無 HTML 字串、無 current 高亮——同一份會被同版本目錄下所有頁面共用,current 判斷交給瀏覽器 端 JS 依 data-current attribute 比對)
    • TEMPLATE<nav class="sidebar"> 改成空殼,只帶 data-current / data-navdata 兩個 attribute;<style><link rel="stylesheet">; 尾部內嵌 <script><script src="">
    • build() 每次執行對該 src 呼叫一次 nav_data(),寫出 <src>/html/nav-data.json(per-version,因為三個版本目錄頁面清單不同)
    • CSS / NAV_JS 兩個 Python 常數整段移除(內容已搬到 _shared/
  • 三個版本目錄(current/v1.9.0/v1.8.0)重新 build,docs/specs/index.htmlbuild_version_index())未變動
  • docs/analysis/2026-07-20-spec-site-shared-assets-extraction.md(問題假設 / 考慮過的選項 / 選擇理由 / 被排除選項與原因 / 未來反悔條件),render_html.py 檔頭 docstring 同步補新機制說明
§3

行為差異

項目 重構前 重構後
側欄內容來源 build time 內嵌進每頁 HTML 瀏覽器端 fetch nav-data.json 動態渲染
改側欄結構(新增一頁 / 調分組)的異動範圍 該版本目錄下全部頁面 .html 只有 nav-data.json(+render_html.py
CSS / lightbox JS 每頁各帶一份複本 三版本共用一份 _shared/ 靜態檔
current 高亮判定時機 build time 瀏覽器端(依 data-current attribute)
file:// 直接雙擊開啟 正常(側欄內嵌) 側欄顯示明確錯誤提示,要求改用 HTTP server(新限制,已附 fallback UI)
Cloudflare Pages / 本地 HTTP server 開啟 正常 正常(無差異)
§4

驗證結果

  • 三版本 build 均「⚠️ nav 未涵蓋」警告;index.html 正常重生
  • 瀏覽器實測(Chrome DevTools MCP,docs/specs/ 為 webroot 起 python3 -m http.server):
    • 側欄完整渲染,樣式與互動跟重構前一致(234 個 nav 項目全部正確含 collapse button / current class / ↺ 重複掛載標記)
    • 點連結導頁正常、current 高亮正確、當前頁鏈自動展開
    • 收合功能:點擊收合 + reload 後 localStorage 記得住(測了「當前頁鏈強制 展開」與「非當前頁群組記憶收合」兩種情境)
    • file:// 直開:CSS/JS 正常載入,fetch() 被 CORS 擋下時側欄顯示可見警告框
      • console 印清楚訊息
    • 三版本 × 多深度頁面(首頁、SSP 巢狀子頁、Release Notes 動態子頁、↺ 重複 掛載頁)全部零 console error
    • lightbox 縮放/拖曳/Escape 關閉功能正常
  • 效果驗證:模擬新增一頁並掛進 NAV_STRUCTURE,重 build 後 git diff --stat 顯示只有 nav-data.json(+7 行)與 render_html.py(+1 行)異動,既有 .html 頁面被觸動。已 revert 模擬變更。
§5

已知限制 / follow-up

  • file:// 直接雙擊開啟本機 .html 檔時側欄無法載入(fetch() CORS 限制), 這是重構引入的行為差異(重構前側欄內嵌,file:// 可正常開)。已在 site.js 加明確可見錯誤提示,判斷此限制優先度低(部署面本來就是 Cloudflare Pages, 本地預覽建議用 python3 -m http.server)。反悔條件見 analysis 文件末段。
  • 若未來 Cloudflare Pages 靜態檔快取造成 nav-data.json 更新後沒有即時反映, 可能需要加 cache-busting(目前尚未觀察到此問題,暫不處理)。
  • 未 push(v1.9.0 tag 也未 push),push 時機等 user 明示。
§6

規範文件更新狀態

  • docs/analysis/2026-07-20-spec-site-shared-assets-extraction.md(新增)
  • render_html.py 檔頭 docstring(補新機制段落)
  • ✅ 本 SUMMARY
  • docs/features/FR-047-2607-feature-spec-handbook/tracker.md Session 紀錄補一行
  • ✅ memory project_fr047_spec_handbook.md 補一段
  • ✅ Notion 任務清單補一條