PrimeVue DataTable Frozen Column 錯位之謎:兩層 Root Cause,與一個 ResizeObserver Directive 解法
專案裡的 PrimeVue DataTable 用了 frozen column(凍結欄),QA 回報一個詭異的現象:表格內容變多、垂直 scrollbar 出現的那一刻,凍結欄的位置就錯了——欄與欄之間出現縫隙或互相重疊,橫向捲動時整個版面破掉。更麻煩的是它「時好時壞」,看起來像隨機發生。
專案裡的 PrimeVue DataTable 用了 frozen column(凍結欄),QA 回報一個詭異的現象:表格內容變多、垂直 scrollbar 出現的那一刻,凍結欄的位置就錯了——欄與欄之間出現縫隙或互相重疊,橫向捲動時整個版面破掉。更麻煩的是它「時好時壞」,看起來像隨機發生。
寫了很多年前端,「冪等(idempotent)」這個詞我當然看過——HTTP 規範裡有、面試題裡有。但我從來沒有意識到它:沒有在設計系統時把它當成一個要主動守住的性質。直到我的爬蟲系統經歷了一連串資料庫事故(覆盤見系列第二篇),我才發現整個系統能自癒的地基就是這兩個字,而且回頭一看——前端其實天天在用它,只是沒人告訴我它的名字。
我是前端工程師,對資料庫的心智模型來自 MySQL/Postgres 的常識:row-level lock、多個連線併發寫入、connection pool。直到我用 Turso(雲端版 SQLite / libSQL)跑了一個爬蟲系統、經歷了幾次事故(覆盤見系列上一篇),才發現這套常識在 SQLite 世界整組不適用。
前情提要:我有一個 vibe coding 出來的台股行情爬蟲,跑在 Fly.io 上、資料庫用 Turso(libSQL,SQLite over HTTP)。上一篇〈讓 AI 全面 review 我 vibe code 出來的 production 專案〉提到,我做過一次全面 review、修掉 20 個問題。兩週後,它還是在盤中死掉了。
我有一個 side project:一個台股行情資料的爬蟲系統,每天開盤自動啟動、收盤停止、晚上全量重抓,跑在雲端、透過 Telegram 推播訊號。它是我一路 vibe coding 迭代出來的——功能一直長,但我從來沒有系統性地檢視過整個 codebase。它能跑,而且跑了好幾個月。
有一個共用的 composable,負責去後端撈一份「選項清單」(下拉選單用的 label)。它用 module scope 的 ref 做成 singleton + cache,設計上要外層 component 先呼叫 fetch() 把資料載進來,子 component 再直接讀 cache。
最近在重構一個「把分析資料匯出成 CSV / Excel」的功能時,自動化的 code review 工具在其中一段 CSV 產生邏輯標了一個 CWE-1236(CSV Injection)。第一眼看它像個可以延後處理的舊問題,但認真追下去,卻意外帶出一整套關於「injection 的本質」與「威脅模型如何決定優先級」的思考。這篇就記錄這段收穫——幾乎不談那個重構本身,只談那個被掀開的攻擊面。
你有沒有想過,請 LLM 幫你寫一個包含 \u200B 的 regex,它到底能不能寫對?
前一篇結尾預告了這次改版唯一一個讓我卡住超過幾小時的 bug。獨立寫一篇,因為它的「形狀」比細節更值得記。
上一篇寫完設計診斷,這篇換工程的角度。