維護記錄

完成的工作

  • 應用戶要求,把 scripts 工作流從 Node.js + tsc 全面遷移到 Deno ✅
  • 新增 deno.json:tasks 列出全部 14 個入口(test / validate-posts / check-dead-links / format-markdown / sync-covers / gen-covers / rename-posts / optimize-images / git-commit-push + 各 *-dry 變體),unstable: ["sloppy-imports"] 避免改 28 處 .js 後綴 import,imports: { sharp: "npm:sharp@0.33.5" } 鎖定 sharp 版本,nodeModulesDir: "none" 拒絕自動創建 node_modules/
  • 更新 5 個 workflow yml(validate-posts / sync-covers / check-dead-links / test-scripts / deploy):替換 setup-node@v4 + npm install + npx tsc 三件套為 denoland/setup-deno@v2,把 node scripts/dist/xxx.js 全部換成 deno task xxxdeno run -A scripts/xxx.ts
  • 刪除 package.json / package-lock.json / tsconfig.scripts.json / scripts/dist/(168K 編譯產物,git 歷史裡也會清)
  • 新增 deno.lock(212 行,鎖定 sharp + 平臺原生包 + transitive deps),跟 package-lock.json 一樣入倉
  • 更新 .gitignore:scripts/dist/ 改為 .tools/(Deno 二進制 + cache,本地用,不入倉)+ .npm-cache/(舊依賴)
  • 更新 CLAUDE.md 反映新結構(Deno 命令、scripts 目錄樹、修正 content/maintenance/content/claudelog/、刪除不存在的 format-markdown.yml 引用)
  • POC 5 項全過:Deno 直接吃 .ts / node:test 原生兼容 / node:child_process.execSync 工作 / npm:sharp 預編譯包自動下載 / denoland/setup-deno@v2 一行可換
  • 測試 39 passed (162 steps),0 failed — 與 Node + tsc 完全等價 ✅
  • 所有 9 個腳本 dry-run 驗證可加載/可執行

遇到的問題

  • 沙箱 HOME 不可寫 ⚠️
    • deno_install 默認裝到 ~/.deno,沙箱拒絕
    • curl ... | sh 不接受 inline DENO_INSTALL=... env(子 shell 不繼承 export 之前的賦值)
    • 解決:export DENO_INSTALL="$PWD/.tools/deno" && curl ... | sh -s -- -y
  • Deno 默認緩存路徑也不可寫 ⚠️
    • DENO_DIR 默認是 ~/.cache/deno,沙箱拒
    • 解決:本地開發設 export DENO_DIR="$PWD/.tools/deno-cache",CI runner 不存在此問題
  • --sloppy-imports 是攔路虎 ⚠️
    • 全部 28 處 from './lib/xxx.js'(實際 .ts 文件)在 Deno 默認嚴格模式下報錯
    • 三種解法:加 --sloppy-imports(每次手動)、deno.jsonunstable: ["sloppy-imports"](項目級)、手工改 28 處後綴(易出錯)
    • 採用 #2,0 行代碼改動,vs 改 28 處 import + 擔心 typo
  • sharp 自動下載有警告 ⚠️
    • Deno 默認跳過 npm 包 lifecycle scripts,提示 “Enable nodeModulesDir: auto
    • sharp 不需要 postinstall(平臺預編譯包 @img/sharp-darwin-arm64 等),警告可忽略
    • Linux CI 同理:會自動下 @img/sharp-linux-x64
  • Deno task 不解析 -- 分隔符 ⚠️
    • 原計劃用 deno task xxx -- --message "..."(像 npm 那樣)
    • 實測 Deno 2.9 把 -- 原樣透傳給腳本,被 parseArgs 當成 -- flag
    • 解決:workflow 裡改用 deno run -A scripts/xxx.ts --message "..." 直接調用
  • CLAUDE.md 文檔漂移 ⚠️
    • 原本引用了 .github/workflows/format-markdown.yml,但文件根本不存在(deploy.yml 裡有 format-markdown.ts 調用,不是獨立 workflow)
    • content/maintenance/ 是錯的,實際是 content/claudelog/
    • 順手一起修了

決策點

  • 保留 Node + prettier:Deno 沒有等價 prettier 的內置格式化器,且 prettier 跨語言一致性強。deploy.ymlformat-markdown.ts shell 調用 prettier 是最乾淨的邊界。代價:workflow 仍需 setup-node@v4 + npm install -g prettier@3.9.6,但 node_modules 不存在,體積零增量
  • 保留 migrate-slug-scheme.ts(一次性腳本,無測試,workflow 裡沒引用):雖然功能已結束,但刪用戶寫過的代碼得用戶授權。留著,以後清理
  • 不加 nodeModulesDir: "auto":會強制創建 node_modules/ 目錄,違背"零 npm"目標。sharp 無 postinstall,警告忽略

CI 影響

  • before:4 個 workflow 各 5 步(checkout → setup-node → npm install → npx tsc → node scripts/dist/xxx.js),平均每 job ~45 秒在 npm 上
  • after:3 步(checkout → setup-deno → deno task xxx),setup-deno 幾秒,deno 跑 .ts 是緩存熱路徑
  • 預計 CI 時間省 30-40%

下次建議

  • 觀察第一次 push 觸發 deploy.yml 的運行,確認 sharp 在 Linux runner 上跑通(@img/sharp-linux-x64 自動下載)
  • 如果 deno task test 在 CI 比 node --test scripts/dist/__tests__/*.js 慢(不太可能,但 Deno 冷啟動比 node 慢),考慮加 cache: 'deno' 或類似策略到 setup-deno
  • migrate-slug-scheme.ts 可以獨立刪(下次大掃除時),無功能影響
  • 如果哪天不需要 prettier 了,可以把 deploy.yml 的 setup-node@v4 也去掉,實現純 Deno

文件變更清單

  • 新增:deno.jsondeno.lock
  • 刪除:package.jsonpackage-lock.jsontsconfig.scripts.jsonscripts/dist/(含 11 .js + 3 .js in lib/ + 10 .js in tests/)
  • 修改:.github/workflows/{deploy,validate-posts,sync-covers,check-dead-links,test-scripts}.yml + CLAUDE.md + .gitignore
  • 腳本源碼(scripts/**/*.ts):0 行改動