原型維護
使用此技能讓現有的原型在多次產品迭代中更容易修改。
目標不是重新設計產品。在改善可維護性、檔案所有權和驗證速度的同時,保留當前的行為和視覺方向。
範圍與交接
- 在現有原型中,將此技能用於持續的結構迭代和所有權對應。對於初次靜態拆分或封裝,請使用
static-prototype-splitter(若可用);它不是必需的依賴項。 - 一個小型的複製、版面或行為請求不需要進行目錄大改造。僅拆分與該請求相關的職責。
- 保留現有的進入點檔案名稱、框架、腳本模型和預覽工作流程。下面的
app.html佈局只是一個範例,並非重新命名的要求。 - 遵循使用者對於檔案取代、設定、依賴項、網路存取、本地伺服器和儲存資料的授權規則。此技能不授予這些權限。
觸發時機
當使用者要求以下事項時觸發此技能:
- 改善後續原型修改的速度。
- 按頁面、元件、欄位、模態框、儲存庫或資料層拆分 JavaScript。
- 按 base、layout、page、component、modal 和 field 範圍拆分 CSS。
- 分離模擬資料、種子資料、結構描述和狀態/儲存邏輯。
- 建立或更新原型維護 README。
- 建立或更新 CHANGE-MAP,將未來請求對應到檔案。
- 繼續優化現有的互動原型。
- 讓組合預覽和拆分檔案能共同保持可維護性。
- 解釋未來原型修改應該在哪裡進行。
預設原則
- 遵循使用者的語言和原型的現有術語。
- 在編輯前先讀取當前的進入點和活動腳本參考。
- 保留原始的視覺設計和互動意圖,除非使用者要求重新設計。
- 除非明確要求,否則不要將所有內容重寫成某個框架。
- 避免產生第二個分歧的實作。組合預覽應載入共享/拆分的模組,或從它們產生。
- 將變更範圍集中在可維護性和所要求的產品行為上。
- 當僅添加新檔案時,拆分尚未完成。每個拆分還必須減少舊檔案的職責,以便未來的編輯有唯一且明確的負責人。
- 保留不相關的變更不變,並保留原始的輸入和已取代的檔案。將授權的編輯集中在活動實作上;未經批准,請勿刪除舊有檔案或取代受保護的文件。
- 變更後,在可行時驗證語法和主要預覽互動。
建議結構
根據專案調整名稱,但對於靜態互動原型,偏好以下形狀:
prototype/
├── app.html
├── README-prototype.md
├── CHANGE-MAP.md
├── assets/
│ ├── css/
│ │ ├── base.css
│ │ ├── layout.css
│ │ ├── components.css
│ │ ├── modals.css
│ │ ├── fields.css
│ │ └── pages/
│ │ ├── home.css
│ │ ├── editor.css
│ │ └── fill.css
│ └── js/
│ └── app/
│ ├── core.js
│ ├── runtime.js
│ ├── pages/
│ ├── components/
│ ├── fields/
│ ├── modals/
│ ├── data/
│ ├── store/
│ └── utils/
└── pages/
└── ...
當原型領域不同時,使用等效的名稱。重要的是責任劃分。
對於小型原型,較扁平的結構即可。對於頻繁變更的原型,較偏好上述目錄結構,這樣每個未來的請求都能對應到一個小檔案。
各層責任
進入點層
保留當前的組合預覽進入點;下方使用 app.html 作為範例名稱。
它應包含:
- 裝置框架或預覽外殼(若有的話)。
- 根容器。
- CSS 連結。
- 有序的腳本參考。
它不應包含大部分業務邏輯。
頁面層
使用頁面檔案處理頁面渲染和頁面特定的佈局:
- 首頁/列表/搜尋/分頁標籤。
- 編輯器/建立/編輯頁面。
- 填寫/預覽/提交/詳細頁面。
- 登入/註冊/引導頁面。
- 設定/帳戶頁面。
當使用者要求更改頁面佈局或頁面文案時,從這裡開始。
如果一個頁面檔案包含多個頻繁編輯的子視圖,則再次拆分。範例:
pages/home/
├── index.js
├── search.js
├── my-forms.js
└── submitted.js
欄位或元件層
使用欄位/元件檔案處理重複的 UI 區塊:
- 欄位類型標籤。
- 欄位預設值。
- 編輯器中的欄位預覽。
- 填寫頁面控制項。
- 上傳/圖片/檔案/單選鈕/核取方塊/OCR/日期渲染器。
當使用者要求變更某一元素類型時,避免先搜尋整個應用程式。從欄位設定和渲染器檔案開始。
當原型有許多表單控制項或重複的卡片時,偏好使用註冊表:
fields/
├── registry.js
├── text.js
├── image.js
├── file.js
├── options.js
└── ocr.js
模態框層
使用模態框檔案處理:
- 欄位設定面板。
- 類型選取器面板。
- 排序抽屜。
- 確認對話框。
- 新增元素庫面板。
盡可能保持模態框狀態為局部,並僅在確認動作後提交資料。
資料層
將資料與儲存庫行為分離。
使用 data/ 處理:
- 模擬模板。
- 產業/類別列表。
- 欄位類型定義。
- 示範使用者和範例。
- 種子記錄和測試用資料。
使用 store/ 處理:
- 本地儲存金鑰。
- 表單儲存/刪除/更新。
- 提交紀錄儲存/刪除/更新。
- 資料正規化和遷移。
除非原型非常小,否則不要將儲存規則混入頁面渲染器中。
當現有本地資料可能已存在時,保留其金鑰和使用者的編輯。僅透過穩定的 ID 添加缺少的種子記錄,並使種子植入具有冪等性;不要覆寫已編輯的記錄、複製項目或在重新載入時重設本地儲存。將結構描述遷移視為一個獨立的、已授權的操作,並附有文件記錄的復原路徑。
CSS 層
按所有權拆分 CSS,而不僅僅是按大小:
base.css:變數、重置、排版。layout.css:外殼、裝置框架、頁面容器、網格原語。components.css:按鈕、輸入框、卡片、分頁標籤、晶片。modals.css:面板、抽屜、確認對話框、吐司提示。fields.css:欄位控制項和表單元素預覽。pages/*.css:頁面特定的佈局和例外。
如果一個選擇器跨頁面重用,則保留在 components 或 fields 中。如果它特定於一個頁面,則將其移至該頁面的 CSS。
變更對應層
為預計會接受多輪編輯的原型添加 CHANGE-MAP.md。
它應將常見的使用者請求直接對應到檔案:
# 變更對應
## 頁面
- 首頁:assets/js/app/pages/home/index.js
- 模板頁面:assets/js/app/pages/templates/index.js
- 表單編輯器:assets/js/app/pages/editor/index.js
## 欄位
- 圖片上傳欄位:assets/js/app/fields/image.js
- 檔案上傳欄位:assets/js/app/fields/file.js
- 單選鈕/核取方塊欄位:assets/js/app/fields/options.js
## 模態框
- 欄位設定模態框:assets/js/app/modals/field-settings.js
- 排序抽屜:assets/js/app/modals/sort.js
## 資料
- 模板資料:assets/js/app/data/templates.js
- 產業類別:assets/js/app/data/industries.js
## 樣式
- 模板頁面樣式:assets/css/pages/templates.css
- 欄位樣式:assets/css/fields.css
保持 CHANGE-MAP 簡短。它是一個編輯索引,而不是產品文件。
執行時期層
使用執行時期檔案處理:
- 路由器/渲染分派。
- 事件委派。
- 手勢處理。
- 動作分派。
- 啟動引導。
如果執行時期變得很大,則按互動類型拆分,但保留一個清晰的進入點。
維護 README
當被要求時,在原型根目錄下新增或更新 README-prototype.md。
包含:
- 總覽進入點。
- 本地預覽 URL 和保留的連接埠(若有的話)。
- 頁面對應檔案。
- 欄位/元件對應檔案。
- 模態框對應檔案。
- 資料層位置。
- CSS 層位置。
- CHANGE-MAP 位置。
- 如何在變更後重新整理和驗證。
- 常見的未來變更範例,例如「變更上傳圖片欄位」或「變更表單提交頁面」。
保持簡潔且有用。它是給維護原型的人類閱讀的,而不是一個冗長的開發日記。
工作流程
-
檢查活動進入點檔案。
- 使用
rg --files、grep和目標性讀取。 - 確認哪些腳本實際上被組合預覽載入。
- 不要假設現有的拆分檔案是活動的。
- 使用
-
識別當前所有權。
- 頁面渲染器。
- 欄位渲染器/設定。
- 模態框/抽屜。
- 儲存庫/資料輔助程式。
- 執行時期/事件處理器。
-
小心拆分。
- 當需要保留行為時,優先進行機械式提取。
- 在
app.html中明確指定腳本載入順序。 - 避免在拆分期間變更行為,除非使用者同時要求行為變更。
- 提取模組後,從舊檔案中移除或縮小對應的責任。不要為同一個頁面、元件、模態框、資料集或 CSS 選擇器留下兩個活動的負責人。
- 保留舊有的組合檔案不予使用,而不是刪除它們,除非使用者確認刪除。
- 保留現有的 classic-script 或 ES-module 模型。移動函式後,檢查載入順序、匯出和內聯事件處理器。
- 使視圖掛載/卸載的責任明確。離開視圖時,移除陳舊的監聽器和計時器,以便重複導覽不會重複執行動作。
-
當資料增長時拆分資料。
- 將大型模擬資料移出頁面渲染器和儲存庫檔案。
- 保持種子測試用資料具確定性且易於掃描。
- 盡可能將新的種子資料合併到現有的本地資料中。
- 如果資料被移到
data/,讓儲存庫/狀態檔案消費該資料,而不是保留一份重複的活動副本。
-
當視覺變更變慢時拆分 CSS。
- 從 base/layout/components/pages 開始。
- 將僅頁面使用的選擇器移至頁面 CSS。
- 將可重用的控制項移至 components 或 fields CSS。
- 移動選擇器後,從先前的全域樣式表中移除重複的活動選擇器,除非有意保留它們作為共享的元件樣式。
- 保留階層順序和回應式斷點;重新調整 CSS 中的
url(...)、字型和匯入路徑,使其相對於新檔案位置。
-
更新或建立 README 和 CHANGE-MAP。
- 記錄最終的活動結構。
- 明確指出常見的未來請求應編輯哪個檔案。
- 包含本地預覽 URL、保留的連接埠和快取清除說明(若相關)。
-
驗證。
- 遞迴檢查原型實際擁有的 JavaScript 檔案,包括巢狀的頁面/元件檔案。當 Python 和 Node 已可用時,此範例檢查
assets/js下方的.js、.mjs和.cjs檔案;根據專案調整根目錄。不要僅為了執行它而安裝執行時期。python3 - <<'PY_CHECK' from pathlib import Path import subprocess import sys root = Path("assets/js") files = sorted(p for p in root.rglob("*") if p.is_file() and p.suffix in {".js", ".mjs", ".cjs"} and not {"node_modules", "vendor", ".git"}.intersection(p.parts)) if not files: sys.exit("No JavaScript files found; verify the check root.") failed = False for path in files: failed |= subprocess.run(["node", "--check", str(path)]).returncode != 0 sys.exit(1 if failed else 0) PY_CHECK - 對於框架專案或不同的模組模式,使用現有的專案檢查。語法檢查通過並不能證明瀏覽器行為。
- 開啟組合預覽。
- 將受影響的行為與基準線進行比較,包括前進/後退導覽、重新訪問已編輯的視圖、模態框確認/取消,以及在適用時重新整理後保存的狀態。
- 在可行時檢查瀏覽器主控台錯誤。
- 遞迴檢查原型實際擁有的 JavaScript 檔案,包括巢狀的頁面/元件檔案。當 Python 和 Node 已可用時,此範例檢查
拆分粒度規則
使用這些規則來避免拆分不足和拆分過度:
- 如果一個檔案因不相關的請求而被重複編輯,則拆分它。
- 如果一個頁面包含多個獨立變更的子視圖,則拆分子視圖。
- 如果模擬資料佔用的空間比其周圍的邏輯還多,則將其移至
data/。 - 當多個欄位/控制項類型獨立變更時,考慮使用
fields/;不要僅僅為了達到某個數量而拆分。 - 當對話框或抽屜有獨立的狀態或維護需求時,考慮使用
modals/。 - 如果 CSS 變更需要搜尋大型的全域樣式表,則按頁面和元件拆分。
- 如果一個檔案穩定且很少被編輯,不要僅僅為了美觀而拆分它。
驗證輔助工具
偏好簡單、無依賴的靜態原型驗證方式:
- 使用
node --check檢查 JS 語法。 - 對於快取清除,代入實際值,例如
app.html?t=20261109-153000;在 URL 中直接鍵入Date.now()是一個固定字串。單靠 HTML 查詢字串無法重新整理獨立快取的 JS/CSS,因此請在需要時使用瀏覽器快取控制項或現有的資產版本化策略。 - 當使用者已選擇了一個連接埠時,保持本地預覽連接埠穩定。
- 在結構重構後,在瀏覽器中驗證已變更的互動。
- 對於相容的靜態頁面,直接開啟檔案是可以接受的。擷取的片段和瀏覽器 ES 模組通常需要 HTTP;記錄開啟模式並在可用時重用現有的預覽伺服器。啟動新伺服器需遵循使用者的授權規則。
回應風格
完成時,告訴使用者:
- 哪些內容被拆分或記錄。
- 活動的進入點檔案。
- 最重要的新檔案路徑。
- README-prototype.md 或 CHANGE-MAP.md 是否已建立或更新。
- 完成了哪些驗證。
- 任何有意保留在原位的舊有檔案。
保持最終的回應簡短且實用。