iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
Software Development

從零打造網頁簡報編輯器系列 第 23 篇

Day 23|驗證專案格式並保護既有資料

  • 分享至 

  • xImage
  •  

系列:一張投影片背後的工程:從零打造網頁簡報編輯器

對應程式版本:Git tag v0.4.0

版本說明:本文聚焦匯入邊界的格式驗證與失敗時保留原專案,完整備份往返留到下一篇。

使用者選到的專案檔不能直接當成 PresentationDocument。TypeScript 型別只在開發期間生效,從磁碟讀進來的 JSON 仍是未知資料;即使 JSON.parse() 成功,欄位也可能缺少、重複或超出畫布。

先解析,再逐層驗證

匯入檔案上限為 32 MB。讀成文字後先捕捉 JSON 語法錯誤,再檢查備份版本、文件與資產陣列:

if (
  !isRecord(value) ||
  value.backupVersion !== 1 ||
  !isPresentationDocument(value.document) ||
  !Array.isArray(value.assets)
) {
  throw new Error('The project file uses an invalid format.')
}

isPresentationDocument 會確認 schemaVersion、畫布尺寸、投影片順序與實際投影片完全對應,並要求至少一張未隱藏投影片。每張投影片的物件 ID 必須唯一,座標必須是有限的非負數、寬高必須為正數,而且整個 frame 要留在畫布內;文字、圖片與圖形也各自檢查允許的欄位和值。

圖片參照必須完整對得上

解析器先從文件收集所有被引用的 assetId,再檢查每筆資產的 ID、PNG/JPEG MIME、尺寸、時間與 Data URL。重複 ID、錯誤的 Base64 前綴、缺少被引用圖片,或夾帶文件沒有使用的資產,都會讓整份專案被拒絕。

這不是只為了顯示友善錯誤。若文件先寫入、圖片後來才驗證失敗,使用者原本的專案就可能被半套資料取代。

驗證成功後才一次換掉舊資料

介面先完整執行 readProjectBackup(),成功後才呼叫 saveProject(),在同一筆 IndexedDB transaction 寫入文件與圖片。等待寫入完成後,才用 replace() 更新畫面中的文件:

const project = await readProjectBackup(file)
await saveProject(project.document, project.assets)
replace(project.document)

任何一步失敗都會顯示「原本的簡報沒有變更」。測試也涵蓋無效 JSON、缺少被引用資產,以及含 Blob 的合法專案可以解析;匯入邊界因此有可重現的保護,而不是只靠 try/catch 猜測資料正確。

不過驗證只保證壞檔不會取代原簡報。合法的備份一匯入就會直接換掉目前的簡報,沒有額外確認;replace() 又會清空復原紀錄,選錯檔案就無法用 Ctrl+Z 找回,匯入前最好先下載目前的備份。解析器也只檢查 MIME 與 Base64 格式,不會解碼圖片;圖片資料損毀但格式正確的檔案仍會匯入,只是畫面上會出現破圖。這兩點到 v0.15.0 仍是如此。

目前 backupVersion: 1 遇到其他版本會直接拒絕。等格式真的需要演進時,再加入明確的遷移程序,比默默接受不完整資料安全。

參考資料


上一篇
Day 22|用 IndexedDB 保存文件、圖片與狀態
下一篇
Day 24|讓含圖片的備份可以完整往返
系列文
從零打造網頁簡報編輯器 共 25 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言