Craft Agents ESLint自定义规则实践:no-localstorage等规则如何防止架构腐化
【免费下载链接】craft-agents-oss项目地址: https://gitcode.com/GitHub_Trending/cr/craft-agents-oss
Craft Agents 是一款开源的 AI Agent 协作桌面应用。它的 Electron 客户端内置了一整套 ESLint 自定义规则(如 no-localstorage、no-hardcoded-z-index),用机器可执行的检查来替代口头约定,从根源上防止大型前端项目的架构腐化。本文将带你逐个看懂这些规则的设计思路与落地方式。
为什么需要 ESLint 自定义规则?
通用的 ESLint 规则只能发现语法层面的问题,而"架构腐化"往往来自更隐蔽的坏习惯:
- 有人随手用
localStorage存了个配置,设置就散落在浏览器沙箱里; - 有人直接写死
navigator.platform判断系统,跨平台兼容性悄悄埋雷; - 有人硬编码
zIndex: 9999,层级系统彻底失控。
Craft Agents 的做法是:把团队的架构约定写成自定义 ESLint 规则,让违规代码在保存时就被拦截。规则集中放在 apps/electron/eslint-rules/ 目录,统一注册到 eslint.config.mjs。
规则一:no-localstorage —— 统一持久化出口
这是最典型的"防腐化"规则。no-localstorage.cjs 会拦截所有localStorage.getItem()、window.localStorage等写法,并给出明确指引:
请把设置存到
~/.craft-agent/preferences.json,通过window.electronAPI.readPreferences/writePreferences读写。
文件头部的注释把设计动机写得明明白白:基于文件的配置可迁移、可手动编辑、集中管理、便于调试。该规则还做了精细的 AST 判断——既拦截成员表达式访问,也拦截把localStorage直接当参数传递的写法,同时放过纯类型引用,避免误报。
它背后的偏好 API 实现在 packages/shared/src/config/preferences.ts,规则报错信息会直接指向这个文件,开发者"看到报错就知道去哪修"。
规则二:no-direct-navigation-state —— 收敛导航状态
no-direct-navigation-state.cjs 只针对AppShell.tsx一个文件:禁止在点击回调里直接调用setSidebarMode(),必须走navigate(routes.xxx())。
这样能保证三件事:URL 与深度链接一致、历史记录支持前进后退、进入新视图自动选中第一项。规则内部还处理了 ESLint 9 移除context.getAncestors()的兼容问题,通过sourceCode.getAncestors()白名单放行事件监听器内部的合法调用。
规则三:跨平台规则 —— 消灭隐性兼容 Bug
- no-direct-platform-check.cjs:禁止直接读
navigator.platform,强制使用@/lib/platform导出的isMac / isWindows / isLinux / PATH_SEP,并对"规则真相源"platform.ts本身豁免。 - no-hardcoded-path-separator.cjs:捕获
filePath.startsWith(dir + '/')这类在 Windows 上必然出错的写法,引导使用pathStartsWith()工具函数。
这两条规则的共同点是:错误信息不只要报"错了",还要报"应该怎么改、去哪个模块改"。
规则四:样式与交互一致性规则
UI 层的腐化往往最直观。Electron 应用中还配置了两条样式规则:
craft-styles/no-hardcoded-z-index(no-hardcoded-z-index.cjs):拦截zIndex: 400这类字面量,只允许 CSS 变量 token(如var(--z-floating-menu, 400))或命名常量。craft-styles/no-nonstandard-shadows(no-nonstandard-shadows.cjs):只放行配置中列出的shadow-minimal、shadow-modal-small等白名单阴影类,保证视觉质感统一。
UI 共享包 packages/ui/eslint-rules/ 里还有更细粒度的no-floating-z-tokens-in-island.cjs,专门约束"标注岛"组件必须使用--z-island专属 token,防止浮层层级互相打架。
架构边界的守护者:no-restricted-imports
在 eslint.config.mjs 中,除了自定义规则,还利用内置的no-restricted-imports划出了后端抽象边界:主进程代码禁止直接import具体的 Agent 提供方 SDK(如 claude-agent、pi-agent),必须经由@craft-agent/shared/agent/backend的统一抽象层。
这等于用 ESLint 强制了"依赖倒置"——未来更换或新增 Agent 后端时,上层代码一行都不用改。类似地,craft-links/no-direct-file-open(no-direct-file-open.cjs)禁止渲染进程直接调用openFile(),确保文件打开一律经过链接拦截器,从而支持应用内预览。
规则如何生效:配置即策略
所有规则在 eslint.config.mjs 中以 flat config 格式注册到craft-agent、craft-platform、craft-styles等命名空间插件下,并按严重级别分档:
| 规则 | 级别 | 守护的架构约定 |
|---|---|---|
| no-direct-navigation-state | error | 导航走统一路由 |
| no-localstorage | warn | 持久化走文件配置 |
| no-direct-platform-check | error | 平台检测单一出口 |
| no-hardcoded-path-separator | warn | 跨平台路径安全 |
| no-hardcoded-z-index | error | 层级 token 化 |
| no-nonstandard-shadows | error(带白名单) | 阴影样式统一 |
值得一提的是,配置中还保留了受控例外清单:少量未完成迁移的文件被显式列出并关闭阴影规则,迁移完成后即可移除。这种"默认严格、例外显式化"的策略,比一刀切更容易在真实项目中落地。
给项目的启示
Craft Agents 的实践给出了一套可复用的"防腐化"方法论:
- 约定要可执行:写进代码评审的口头约定,不如一条 100 行的自定义规则;
- 报错即指引:错误信息里直接给出正确写法和目标模块路径(规则源码中随处可见 "Use xxx instead");
- 按模块分层治理:packages/shared/eslint-rules/ 的
no-inline-source-auth-check与 Electron 侧规则复用同一份逻辑,保证共享包与客户端遵循同一套架构原则; - 例外要显式化:白名单和例外文件都写在配置里,迁移进度一目了然;
- 配套单测:如 no-hardcoded-z-index.test.ts 为规则本身编写测试,确保检查逻辑不失效。
对新手来说,这套机制的学习成本很低——你只需要运行一次 lint,就能顺着报错信息读懂整个项目的架构约定。这正是自定义 ESLint 规则最有价值的地方:它不只是查错的工具,更是团队架构知识的活文档。
总结
Craft Agents 用 no-localstorage、no-direct-navigation-state、no-hardcoded-z-index 等十余条自定义 ESLint 规则,把"统一持久化、统一导航、统一层级、抽象后端"等架构原则固化进了开发流程。规则源码集中、错误信息友好、例外显式可控,这套实践对任何正在长大的前端项目都有很强的参考价值。
【免费下载链接】craft-agents-oss项目地址: https://gitcode.com/GitHub_Trending/cr/craft-agents-oss
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考