把閱讀器嵌進網站:宿主與 LumaReader 怎麼分工

把閱讀器嵌進網站:宿主與 LumaReader 怎麼分工

保留原版閱讀器,釐清 iframe 通訊、儲存確認、選取註記與版本相容,避免整合時重做一套編輯器或遺失文件。

把閱讀器嵌進網站:宿主與 LumaReader 怎麼分工

這是 LumaReader 技術系列第 04 篇,補充 Technical/kainnne lumareader/02_architecture_and_release_20260824 未涵蓋的 Web 嵌入與註記契約。第 02 篇仍保留桌面架構與當時的發行紀錄;第 03 篇是獨立的 macOS 事件紀錄,不由本篇取代。

網站需要閱讀或修改 Markdown 時,我希望嵌入的是原本的 LumaReader。語言、設定、閱讀與編輯方式應該一致,外層網站再處理自己的文件流程。若每個網站都另做工具列和編輯器,修一個共同問題就得追好幾份程式。

本文以 2026-10-19 核對的原始碼、docs/EMBED.md 與公開註記契約為依據,說明目前介面與整合時的判斷。這次更新沒有重新執行上游瀏覽器測試,也不代表每個宿主網站都已完成後台保存。

共用閱讀器,分開業務流程

目前嵌入版透過 iframe 載入與一般 Web 版共用的閱讀器。額外的橋接層處理資料傳送,不另做一套閱讀介面。宿主是包住 iframe 的網站,可以是文章管理頁、文稿工作台,或其他需要 Markdown 的應用。

工作 主要負責者
文字編輯、格式、閱讀設定、Undo/Redo Reader
目前選取、註記位置與原文變動狀態 Reader
文件身分、登入與後台授權 宿主與後台
儲存目的地、素材生成與跨裝置保存 宿主與後台
外層步驟、放大入口與頁面導覽 宿主

外層只放自己的操作。例如工作台有「下一步」,Reader 裡仍使用既有儲存與編輯,不再疊一排意思相同的按鈕。正文唯讀、側欄隱藏或功能關閉可以調整操作範圍,但這些前端選項不構成後台存取權限。

已按儲存,不等於資料已寫入

SDK 的基本入口是 mountLumaReader(container, options),文件帶有固定 id、title 與 markdown。宿主提供 onSave,並在真正保存成功後才讓它完成;失敗就回報失敗,讓編輯器保留尚未保存的內容。

切到下一個步驟時,順序應是:

// 節錄整合順序;onSave 必須已接上實際保存。
await editor.save();
await editor.destroy();
goToNextStep();

若儲存失敗,或儲存期間又有更新的修改,不能照樣拆掉 iframe。現在的介面會追蹤 revision,並拒絕直接移除未儲存內容。宿主也要保留錯誤訊息與重試入口,不能 catch 之後仍跳下一頁。

瀏覽器草稿方便暫存,不是跨裝置的後台。清除網站資料、換裝置,或儲存容量不足,都可能讓它不再可用。需要長期保存,就把持久化接在 onSave,不能只把畫面上的成功提示改成「已上雲端」。

目前文章與完整草稿不是同一份輸出

嵌入工作區目前最多支援三份 Markdown。一般網站提交文章時,可用 getActiveDocument() 取得目前開啟的內容;需要還原整個工作區,則保存 getDocument() 的完整快照,包括 files 與 activeFileId。

這個差別很實際:網站正在發布 A 文章,不應把 B、C 草稿一起合併成正文;但如果只保存頂層的 markdown,之後也不能宣稱所有草稿都可恢復。宿主必須先決定自己存的是文章,還是工作區備份。

放大時保留同一個實例

放大與還原只改容器尺寸,不重新建立閱讀器,才能保留編輯歷程與當前狀態。現有 SDK 提供 expand()、collapse();外層版面仍要避免讓容器受祖先的 transform 或 contain: paint 限制。

驗收不能只看剛放大的畫面。長標題、捲到文件中段、正在編輯、還原後再放大,都可能出現不同問題。要一起核對:操作有沒有被網站頁首蓋住、文件是否仍是同一份、捲動是否正常、返回原尺寸後能否繼續編輯。

選取文字後,再交給宿主處理素材

目前已有可選的原生註記能力,支援重點、文字註解與圖片附件。以 features.annotations: true 開啟後,Reader 管理定位與原生編輯歷程,宿主可透過 selectionActions、onAction 接自己的選圖或生成流程。

這裡要區分兩種需求:圖片插入正文會改變 Markdown;圖片註記則綁在一段文字上,正文和附件分開保存。小說分鏡、段落配圖或編輯備註常需要後者,不能一律塞進 Markdown 當圖片語法。

非同步生成尤其需要保留當時的文件身分與版本。例如使用者選了一段話開始生成圖片,等待期間又修改文字,回來的圖片不能憑同樣一句話就貼到現在的位置。SDK 以 session、文件 ID、revision 與 selection token 核對;失效就請使用者重新確認,把生成素材保留下來,不悄悄換到另一段。

原文偏移目前採 exact 或 unavailable,不是每種 Markdown 都保證能精確映射。遇到相同句子、特殊格式或不支援的區塊,宿主不能自行用 indexOf 猜位置。正文改動後,註記也可能成為待確認或失去定位的狀態,這是需要處理的資訊,不能當作已成功附上。

註記與圖片也要保存

註記必須跟同版本正文一起保存。只下載 .md 會得到正文,不包含完整註記備份;只保存文字,也會丟掉宿主沒有接住的新增欄位。

本機圖片註記可留在 iframe 所屬網站的瀏覽器儲存區。若要跨裝置,宿主還需在目前文件仍可存取時,以 getAttachment() 取出被引用的圖片,傳到自己的儲存目的地,再保存可恢復的快照。SDK 能傳出資料,不等於網站已經實作了上傳。

目前註記契約以 direct 模式為範圍;正文唯讀與註記唯讀分開控制。超大文件或不支援的選取會明確回報不可用,整合頁應接住這個結果,而不是顯示一個永遠不會成功的按鈕。

通訊與更新要守住舊整合

iframe 訊息不能只看一個事件名稱就採用。現有橋接會核對來源視窗、origin、channel 與 boot,避免其他視窗或舊實例的訊息被當成目前內容。這些檢查保護通訊邊界,後台仍須自行驗證使用者能否讀寫該文件。

固定載入網址、文件 ID、草稿鍵與 v1 訊息契約則是相容性的一部分。Reader 內部更新,不應要求每個網站重做 HTML;新增快照欄位也要考慮舊宿主是否會丟棄它。若真的要破壞既有介面,就另開版本入口並保留舊契約。

整合測試至少涵蓋跨來源載入、儲存失敗、等待期間再修改、重載、切換文件、放大還原與窄畫面。需要註記時,再加上選取失效、附件還原和唯讀限制。結果要以實際後台存下的內容核對,不能只看 callback 有被呼叫。

來源與延伸

相關筆記