原型维护 是做什么的?
使用此技能使现有原型在多轮产品迭代中更易于修改。
目标不是重新设计产品。在提高可维护性、文件所有权和验证速度的同时,保留当前行为和视觉方向。
范围与交接
- 将本技能用于现有原型的持续结构迭代和所有权映射。对于首次静态拆分或打包,请在可用时使用
static-prototype-splitter;它不是必需的依赖项。 - 较小的副本、布局或行为请求不需要全面重构目录。仅拆分与该请求相关的职责。
- 保留现有的入口文件名、框架、脚本模型和预览工作流。下面的
app.html布局仅为示例,不是重命名要求。 - 遵循用户的文件替换、配置、依赖项、网络访问、本地服务器和存储数据的授权规则。此技能不授予这些权限。
触发时机
当用户要求以下内容时,触发此技能:
- 提高后续原型修改速度。
- 按页面、组件、字段、模态框、存储或数据层拆分 JS。
- 按基础、布局、页面、组件、模态框和字段范围拆分 CSS。
- 分离模拟数据、种子数据、模式、状态/存储逻辑。
- 创建或更新原型维护自述文件。
- 创建或更新将未来请求映射到文件的 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:特定页面的布局和例外。
如果选择器在多个页面间重用,请保留在组件或字段中。如果特定于某个页面,则将其移到该页面的 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-prototype.md。
包括:
- 总预览入口。
- 本地预览 URL 和保留端口(如果有)。
- 页面到文件的映射。
- 字段/组件到文件的映射。
- 模态框到文件的映射。
- 数据层位置。
- CSS 层位置。
- CHANGE-MAP 位置。
- 更改后如何刷新和验证。
- 常见的未来更改示例,例如“更改上传图片字段”或“更改表单提交页面”。
保持简洁有用。它是为维护原型的人类准备的,而不是一个长篇的开发日记。
工作流程
-
检查活动入口文件。
- 使用
rg --files、grep和定向读取。 - 确认合并预览实际加载了哪些脚本。
- 不要假设现有的拆分文件是活动的。
- 使用
-
识别当前所有权。
- 页面渲染器。
- 字段渲染器/配置。
- 模态框/抽屉。
- 存储/数据助手。
- 运行时/事件处理程序。
-
谨慎拆分。
- 在需要保留行为时,首选机械提取。
- 在
app.html中保持脚本加载顺序明确。 - 不要在拆分期间更改行为,除非用户也要求更改行为。
- 提取模块后,删除或缩减旧文件中相应的职责。不要为同一页面、组件、模态框、数据集或 CSS 选择器留下两个活动所有者。
- 保留遗留组合文件,使其不被使用,而不是删除它们,除非用户确认删除。
- 保留现有的经典脚本或 ES 模块模型。移动函数后,检查加载顺序、导出和内联事件处理程序。
- 明确视图挂载/卸载职责。离开视图时移除过时的事件监听器和计时器,以便重复导航不会复制操作。
-
当数据增长时拆分数据。
- 将大型模拟数据移出页面渲染器和存储文件。
- 保持种子固定数据确定且易于浏览。
- 尽可能将新种子数据合并到现有本地数据中。
- 如果数据迁移到
data/,让存储/状态文件消费该数据,而不是保留一个重复的活动副本。
-
当视觉更改变得缓慢时拆分 CSS。
- 从基础/布局/组件/页面开始。
- 将仅页面的选择器移到页面 CSS 中。
- 将可重用控件移到组件或字段 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;Date.now()直接放在 URL 中是固定字符串。单独的 HTML 查询不会刷新分别缓存的 JS/CSS,因此在需要时使用浏览器缓存控件或现有的资产版本控制策略。 - 当用户已选择端口时,保持本地预览端口稳定。
- 在浏览器中验证更改后的交互。
- 对于兼容的静态页面,直接文件打开是可以接受的。提取的片段和浏览器 ES 模块通常需要 HTTP;记录打开模式,并在可用时重用现有的预览服务器。启动新服务器需遵循用户的授权规则。
响应风格
完成时,告诉用户:
- 哪些内容被拆分或记录。
- 活动入口文件。
- 最重要的新文件路径。
- README-prototype.md 或 CHANGE-MAP.md 是否创建或更新。
- 完成了哪些验证。
- 有意保留的任何遗留文件。
保持最终响应简短实用。