把閱讀器嵌進網站:宿主與 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 有被呼叫。
來源與延伸
- LumaReader 嵌入入口:安裝與功能設定。
- 嵌入註記 v1 契約:完整欄位、限制、錯誤碼與整合範例。
- Projects/Products/kainnne lumareader:產品用途與桌面閱讀器背景。
- Systems/ai document delivery:文件內容、定稿與交付檢查。