iT邦幫忙

2026 iThome 鐵人賽

DAY 17
0
佛心分享-SideProject30

打造 APR Engineer 的生產力平台,從 Flow Tracer 到 SignOff DashBoard 的落地實戰系列 第 17

Day 17 | 從檔案清單到畫面:讀檔整理如何把檔變成一頁

  • 分享至 

  • xImage
  •  

前言

Day 16 把兩堆 JSON 的契約寫死了。這堂課走進瀏覽器:檔案怎麼被發現、怎麼被收成內部資料、怎麼依網址變成「這一頁該有的那包東西」,最後才交給畫面去畫。Day 14 把這層叫做讀檔整理與資料包;今天把它拆開看。畫面長什麼樣子留給 Day 18 起的各頁,今天只關心 門房、整理、地圖、交包 這四件事。

  小伺服器(門房)              瀏覽器裡的讀檔整理                 畫面
  回答「有哪些檔名」  ──讀檔──►  收成內部表                      只認資料包
  不認得 block                 看網址停在哪一層 ──交出資料包──►  首頁 / 階層 /
  不組父親樹                   換頁不重讀;刷新才重問門房         Block / …

若你從「為什麼不在伺服器把頁面畫好」問起,答案與 Day 14 相同:現場要的是掃檔與送檔,不是再養一套後端樣板。讀檔整理活在瀏覽器裡,還有一個好處——版本譜系、最新一筆、葉節點,都用同一份已經整理過的記憶體來算,不必為每一頁再問一次伺服器。


一、門房只回答「現在有哪些檔」

瀏覽器不能掃磁碟。它第一次只做兩類請求:要網頁資產,以及問一份清單。清單路徑固定,回的是兩個檔名陣列——階層有哪些、上傳有哪些——並且告訴你不要快取。內容不在清單裡。清單是門房,不是倉庫。

這一步決定了大廳為什麼能「丟檔就出現新專案」。沒有寫死的專案表,也沒有要重啟才生效的設定。新同事加一份守規則的階層檔,下一輪載入就多一張卡。反過來說,清單若指錯目錄、或資料放在別層資料夾,整座大廳會誠實地空。空,應該先查門房,再查畫面。

檔名常帶特殊字元。向門房拿到名字之後,真正去取檔的路徑必須把名字編碼,不能直接接在網址後面。百分號在 Linux 上特別容易害 404。這不是畫面問題,是門房與倉庫之間的門牌寫法。編碼對了,同一份檔在 Windows 與 Linux 才會是同一個世界。

門房用 Python 標準庫就夠。它同時把執行目錄當靜態網站送出。除了清單以外,沒有「給我這個專案的統計」這類介面。統計在瀏覽器裡算。這個界線要守:伺服器不知道什麼是 block,也不知道誰是誰的父親。它只認識目錄與副檔名。


二、進門之後:先收成內部資料,再談頁面

清單到手,讀檔整理會把每一個上傳檔讀進來,收成一筆扁平紀錄;再把每一個階層檔讀進來,收成一個專案描述。這一步叫正規化。原始 JSON 可以很深、可以帶工具味的欄位名;內部紀錄必須穩定,後面所有頁都吃這份,不吃原始檔。

上傳那一筆大約會長成:自己的 id、來源檔名、父親、製程、專案、block、APR 或 ECO、版本與時間、有沒有 SignOff、整理過的指標、以及一組別名。別名很重要,因為父親欄位在現場可能寫 id、寫檔名、寫路徑尾端。組樹時會拿別名去對。id 則必須在這一輪載入裡唯一,撞名就加後綴,以免兩次 run 在樹上變成同一個點。

製程、block、階段的推導規則與 Day 16 的契約相同:製程從檢查或設計資訊來,block 從設計名來,階段從檔名或 stage 來。正規化不是重新發明契約,是 把契約執行一遍,讓畫面不必再猜。 路徑、報告檔、工作目錄會在抽指標時被丟掉。網頁上看不到內部路徑,是這一步做的,不是 CSS 藏起來的。

階層那一筆較短:id、製程、專案、來源路徑、樹上所有 block 名字(去重後的清單)。完整的樹另外放進專案快取,專案頁與摘要頁再展平。首頁只需要「這張卡底下有幾顆 block」,不需要整棵樹的縮排。

兩份清單都讀完,讀檔整理把它們放進一份總資料:專案陣列加上傳陣列。上傳會依日期新到舊排,讓「最新一筆」的定義單純。這份總資料在同一次瀏覽裡只建一次;換網址不會重讀全部檔,除非你整頁刷新。這是為什麼刷新等於重新問門房——你要最新磁碟時,請刷新,不要期待讀檔整理在背後監看資料夾。


三、地圖是網址,不是選單狀態

位置只活在井字號後面的路徑。沒有後綴是大廳;指出專案是階層;再指出 block 與階段是房間;再指出 version 是某次 run 的細節;專案底下的 summary 是總覽。解析時從深到淺認,避免短路徑把長路徑吃掉。認不出來的,當大廳。

這樣做有三個後果,全是優點。重新整理不會掉頁。複製網址給同事,對方看到同一層。伺服器不必把所有路徑都指回同一個首頁檔。缺點是你必須自己處理編碼:專案 id 與 block 名進出網址要成對。這與檔名編碼是兩件事——一個發生在 hash,一個發生在取 JSON 的 HTTP 路徑。

每次網址一變,讀檔整理走同一條短流程:

  井字號後面的路徑
      │
      ▼
  讀位置 → 先說「載入中」 → 總資料準備好 → 組出這一頁的資料包
      │
      ├── 沒後綴            大廳
      ├── /project/…       階層
      ├── /block/…/apr     房間(APR 門)
      ├── /…/signoff       檢查門
      └── 認不出來          當大廳

允許的階段目前是 APR、ECO、SignOff、Summary。PV、STA、IR 可以出現在頁籤上,但不會成為合法位置。這條流程裡沒有「先畫舊的再補資料」。載入中與失敗都是正式狀態,錯誤必須寫在主畫面。


四、資料包是讀檔整理與畫面之間的唯一縫

讀檔整理不再把 HTML 塞進頁面。它交出一張資料包:現在是哪一種頁、副標該寫什麼、這一頁需要的資料。畫面層(外框上的主畫面)只認資料包種類,再分派到首頁、專案、摘要、Block、版本、或「版本找不到」。

種類比頁面略多,是刻意的。載入中與錯誤不是某一頁的附屬品。版本找不到也不是讓版本頁自己去猜空節點——它是另一種資料包,帶返回上一層的連結。Block 頁的本體則包在資料包裡的 body:可能是檢查表、可能是一棵階段樹、可能是單一 block 的摘要、可能是尚未開放的占位。畫面依 body 的類型畫,不必再問讀檔整理「現在到底是 SignOff 還是 APR」。

這條縫的好處,在改東西時最明顯。改卡片排版、改表格欄寬、改燈號顏色,走畫面。改葉子怎麼數、父親怎麼對、最新一筆怎麼挑,走讀檔整理。兩邊透過資料包的欄位對談。欄位一旦不穩——例如某天把階層列的結構改掉卻沒改專案頁——縫就裂了。所以資料包的形狀要當契約看:寧願多一個明確的種類,也不要在同一個物件裡塞一堆可有可無的欄,讓畫面用條件猜。

外框本身更瘦。它畫品牌、副標、頂部路徑,把資料包交給主畫面。副標來自資料包,頂部路徑來自資料包裡的位置。外框不抓檔,也不懂什麼是 DRC。Day 14 說頂欄當外框、讀檔整理交出資料包,指的就是這件事。今天只是把「資料包」三個字換成可以點名的資料包種類。


五、快取:不要每次換頁都重算整座森林

階層樹與父親樹都可能被很多頁用到。專案頁要展平階層;Block 頁要 APR 樹與 ECO 樹;摘要要沿樹拿名字;版本頁要同一棵樹上的一條路。讀檔整理因此留了兩種快取:專案 id 對應原始階層,以及「製程/專案/block/階段」對應組好的父親樹。

總資料建好時,階層通常已經進快取。若有人用網址深連結直接進 Block,而總資料那一輪因故沒帶樹,會再補讀一次。父親樹則是第一次需要時才組,組完就記住。同一顆 block 在 APR 與 ECO 是兩棵樹,不要混。快取的代價是:你在磁碟換了檔卻不刷新,畫面仍可能拿舊樹。對唯讀儀表這可接受——真相以刷新為界。

組父親樹的細節留給 Day 20。這裡只要知道:它發生在讀檔整理,結果放進 Block 資料包或版本資料包,畫面不自己去對 father 字串。專案表上的「APR 葉子 / ECO 葉子」,也是問這棵樹的葉節點數,不是數檔案個數。有父親的中間版本不算葉子。所以快取不只是加速,它還統一了「葉子」這個詞在每一頁的意思。


六、除錯時沿這條河走,不要從 CSS 溯源

頁面不對,先問現在是哪一種資料包。副標會洩漏:幾張卡、Hierarchy、block 加階段、Version not found。再問清單有沒有檔、正規化後的製程與 block 是否仍是你在 JSON 裡寫的那些字。再問位置解得對不對——深連結少一段、階段寫成大寫被踢回 APR,都發生在地圖,不發生在表格。

只有資料包種類對、資料也對、就是長相不對,才進畫面元件。這個順序能省掉大量「我改了表格為什麼還是空的」:空,常常是鑰匙對不上,資料包裡的列本來就是空的。Day 16 的互認規則,在這一層變成正規化後的欄位;兩層對著查,比在 React 裡 console.log 整棵 props 有效。

開發時,打包工具會把清單與兩堆 JSON 的請求轉去那台小伺服器。你改的是畫面與讀檔整理,看的仍是同一份磁碟資料。不要為開發另做一份 mock 契約,否則上線那天契約會偷偷長出第二張臉。


七、這堂課之後,每一頁只是一種資料包的畫法

Home 要的是專案陣列與依製程分好的組。Project 要的是展平列加上每顆 block 的統計。Block 要的是標題列、階段、以及 body。Version 要的是節點、樹、從根到它的那一串。Summary 要的是每顆 block 的最新 APR 與最新 SignOff。這些「要的是」全部在讀檔整理組好。後面幾天可以深入每一頁長什麼樣子,不必再回頭解釋檔案怎麼進來。


Lab — catalog、F5 vs hash,然後加一頁 Notes

A. 門房與 cache

Browser 開 http://127.0.0.1:8080/api/catalog,記下 design 陣列長度。

  1. 只改 hash(例如從 Home 點進 project 再點回來):catalog 不會重抓,數字不變。
  2. F5:會再問門房。Day 16 若加了 N4_TUTORIAL.json,這裡應多一個檔名。
  3. src/legacy/dashboard.jsparseHash。把網址改成缺 block 那一段,應退回 Home——地圖認不出來就當大廳。

B. 加一條 route:#/project/<id>/notes

這是「新頁不是只加一個 .tsx」的最短路徑。做完可還原。逐步全文在 doc/tutorial/05-lab-add-route.md

契約先畫好:

{ kind: "notes"; projectId: string; blockCount: number; uploadCount: number }

照這個順序改:

  1. parseHash:在 project/<id> 後面加 parts[2] === "notes" && parts.length === 3{ view: "notes", projectId }
  2. src/views/types.tsRoute.view"notes"DashboardSnapshotkind: "notes" 那一包。
  3. render()route.view === "notes"publish 上面那包(block 數來自 hierarchy,upload 數 filter state.data.uploads)。
  4. syncRoute:讓 notesloadHierarchy,跟 project / summary 同一組。
  5. 新增 src/views/NotesView.tsx(沿用 block-head / card / btn,不必新 CSS)。
  6. DashboardMain.tsxkind === "notes" 時畫它,而且要在最後那個 return <VersionView> 之前
  7. Crumbs.tsx + helpers.tsxnotesHref + ProjectView.tsx 一顆 Notes 按鈕。

然後:

npm run typecheck

Vite 還在跑的話,點 Hierarchy 上的 Notes。Hash 應為 #/project/N4_SM8466/notes(或 TUTORIAL)。F5 仍停在這一頁。頂部路徑:Home / … / Notes

漏改哪一檔會怎樣:只加 .tsx → hash 當 Home;漏 types.ts → typecheck 炸;漏 DashboardMain → 誤 render Version;漏 Crumbs → 頁在、路看不見。

Done when: typecheck 過;Notes 上的 block / upload 數字對得上你在 catalog 數的。練習頁不想留在產品裡,把這條鏈還原即可。正式 dist/ 畫面要等到 Day 23 才 python build.py




上一篇
Day 16 | 第一份可跑的資料集:階層檔與上傳檔
系列文
打造 APR Engineer 的生產力平台,從 Flow Tracer 到 SignOff DashBoard 的落地實戰17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言