Topics

EmDash 正式版發布。從 0.22 升級至 1.2

  • column

2026年09月28日,EmDash 的 1.0 正式發布。
EmDash 是 Cloudflare 開發的基於 Astro 的開源 CMS,管理界面直接內嵌在 Astro 網站中,由 Cloudflare Workers + D1 + R2 驅動。
可以說是 WordPress 的 Astro 版本。

之前的文章中從 microCMS 遷移過來的公司內部部落格「ゆるろぐ」一直停留在 6 月發布的 0.22 版本,所以趁著這次機會一口氣升級到最新的 1.2.0。

1.0 的亮點是穩定性和升級安全性、在沙盒中運行的插件,以及針對代理的 MCP 伺服器。

說結論的話,遷移在一天內完成了,但陷阱真不少。
如果抱著「1.0 已經穩定了吧」的輕鬆心態開始,你會在 EmDash 本體之外的周邊依賴關係上卡殼。

前提:0.22 → 1.2 只能手動升級

1.2 內包含了名叫 upgrade-emdash 的官方升級 CLI。
它會更新依賴關係並生成特定於網站的 UPGRADE.md,但只支援 0.35 之後的版本,所以從 0.22 無法使用。

0.22 到 1.2 之間有 47 個數據庫遷移,其中還有幾個破壞性的變更。
「先試試 npm install emdash@latest」這種方法根本行不通。

1. 備份後,將生產數據庫複製到本地

npx wrangler d1 export <database-name> --remote --output=backups/pre-1.2.sql

將其導入本地 D1,用與生產相同的數據進行遷移測試。

2. 更新依賴項目

套件

遷移前

遷移後

emdash / @emdash-cms/cloudflare / @emdash-cms/admin

0.22.0

1.2.0

@emdash-cms/plugin-forms

0.1.1

0.2.9

astro

6.1.2

6.4.8

wrangler

4.80

4.148

wrangler 必須滿足 emdash 1.2 的 peer 需求(4.99 以上),因此在這個時機點移除了 0.22 時代的應急處置。
@astrojs/cloudflare滿足 peer 需求,所以在此時仍維持 13.1.6 版本。這成為了後續問題的根源。

  • OAuth 路由的 patch-package:0.22 時代為迴避 bug 所套用,本體已修復
  • 管理畫面的 CSS 注入:0.22 的 admin 針對 UI 函式庫 kumo 2.4 的 CSS,但 lockfile 卻引入了 2.6,導致登入和發布的強調按鈕呈現「透明背景加白字」而無法看見。1.2 版本已在本體修復

3. dev 無法啟動(陷阱:miniflare 版本不相符)

依賴更新後執行 npm run dev 無法啟動的原因是 miniflare 版本不相符。
wrangler 4.148 使用 miniflare 5,會將本機 D1 狀態(.wrangler/state/v3/下方)的 _cf_ALARM 表格更新為 3 欄。
另一方面@astrojs/cloudflare 13.1.6 內附的 miniflare 是版本 4,欄數不相符導致無法讀取本機狀態。

解決方式是同時升級據置不變的 @astrojs/cloudflare,讓 miniflare 的版本與 wrangler 保持一致。只要記住「wrangler 與適配器的 miniflare 版本要相符」,下次就能一次解決。

在 0.22 版本中,emdash dev 命令已被廢止,所以 dev 腳本改回 astro dev。遷移和型別生成會在 astro dev 啟動時執行。

4. 暫存環境的選單消失(陷阱:seed.json 中的 menus)

dev 啟動後 90 個遷移成功並推送到暫存環境,打開管理介面後發現 日文全域導覽為空。

原因是 seed/seed.json 中的 menus 和 widgetAreas。
EmDash 的種子處理若發現同名的選單或小工具區域,會 先刪除所有項目再以空狀態重新建立。
seed.json 中作為樣板保留了 "items": [] 的選單定義,因此每次執行種子時選單都被初始化。

解決方法是 menus 和 widgetAreas 整個刪除。
選單內容應在管理介面中管理,沒有理由保存在種子中。

5. 英文文章的連結變成 /en/posts/en/slug(陷阱:entry.id 的語言前綴)

這是 1.2 版本的規格變更。
在多語言網站中,getEmDashCollection() 回傳的 entry.id 現在會帶有語言前綴。英文文章會是 en/my-post。

由於 yuru.log 是從 entry.id 組建文章 URL,英文文章的連結變成了 /en/posts/en/my-post 雙重路徑。
已將清單、精選、搜尋結果、RSS 和 canonical 中所有 URL 組建的地方都改成 entry.data.slug。
由於 entry.data.slug 的型別是 string | null,接收端的型別也需要相應調整。

entry.id 是鍵值、entry.data.slug 是 URL、entry.data.id 是資料庫的 ULID(用於 API 呼叫),記住各自的角色會很有幫助。

6. 每分鐘出現錯誤(陷阱:Cron Trigger 和 Worker 進入點)

在 1.x 中,預約發佈和外掛定期處理由 Worker 的 scheduled() 處理程式驅動。
由於 Cloudflare 沒有內部計時器,如果沒有 Cron Trigger,預約發佈即使在公開時刻也不會發佈。
因此wrangler.jsonc新增了 Cron Trigger。

"triggers": { "crons": ["* * * * *"] }

接著每分鐘會出現「Handler does not export a scheduled() function」的錯誤。
這是因為 Worker 入口點沒有 export scheduled()。
解決方法是將 src/worker.ts 替換為官方入點。

export { default, PluginBridge } from "@emdash-cms/cloudflare/worker";

如此一來fetch和scheduled之外,還有適用於沙箱型外掛的PluginBridge。

實際嘗試使用後

升級到 1.2 的優點。

  • 編輯器煥然一新,更易使用。斜線選單已分組,工具列會跟隨游標。也可在行動裝置上使用。
  • 影片區塊已內置。之前用自訂外掛進行影片嵌入,打算之後逐步替換。
  • 0.22 時代的臨時措施全數移除。patch-package 和 CSS 注入都不再需要。

值得注意的地方。

  • 從 1.0 到 1.2 只花了 10 天,更新速度很快。今後似乎需要採取按次要版本號在預備環境確認的運營方式。

總結

  • 0.22 → 1.2 是手動遷移,upgrade-emdash CLI 僅支援 0.35 以後的版本。
  • wrangler 和適配器的 miniflare 世代需要一致→不一致的話 dev 會無法啟動
  • seed.json 中不要留下 menus / widgetAreas 的空白模板→每次執行 seed 時都會消失
  • 多語言網站的 entry.id 會附加語言地區前綴→URL 應該從 entry.data.slug 產生
  • 若要新增 Cron Trigger,Worker 進入點應設定為 @emdash-cms/cloudflare/worker

這些問題雖然一旦理解後只需要修改幾行代碼,但逐一檢查時往往比預期花費更多時間。

不過,0.22 版本時套用的補丁和 CSS 應急處理都能完全移除,這證明了朝向正式版發布時細微的錯誤已被逐漸修正。
半年前還是「試驗性地換上」的態度,但經過 1.0 版本後,只要考慮到跟進更新的工作量,EmDash 已經成為實際運用中充分值得檢討的 CMS 選項了。

本文作者

從 DTP 跨足 Web 世界,轉眼間便掌握了標記語言、frontend 開發、專案指導,以及 accessibility 等各項技能——是名真正的「技術高人」。自 Liberogic 創立初期便展現多才多藝的能力,如今儼然成為公司內的活字典。最近正沉迷於利用 AI 提示詞探索「accessibility 對應能否更多依靠 AI?」的效率化研究。技術與思維都在不斷進化中。

二俣 歩

IAAP 認證網頁無障礙專家(WAS)/ 標記語言工程師 / Frontend 工程師 / 網頁總監

查看此員工的文章

信心十足的團隊體制與迅速的應對能力是我們的優勢

Liberogic 擁有經驗豐富的人員積極推進專案,因而獲得客戶的高度評價。
我們恰當地安排專案經理和總監,致力於順利推進整個專案。 我們避免不必要的全面投入而導致成本增加,而是採用適材適所配置資源的方式,因此在業務把握到估價制作與提交的速度上也備受好評。

※ 請注意,我們不積極進行 SES 形式的駐場業務。

Slack、Teams、Redmine、Backlog、Asana、Jira、Notion、Google Workspace、Zoom、Webex 等幾乎所有主要的專案管理工具和聊天工具都可供您使用。

請諮詢我們解決您的網站問題。

案例分析