分层的依据:按变更频率,而不是按文件类型
很多项目的目录是「按文件类型」堆出来的:所有 js 放一起,所有组件放一起。项目小时没问题,一旦要同时面向微信、抖音和 App,就会出现「改一个端、三个端都得重新验证」的局面。
更稳的做法是按变更频率分层:越靠下的层越稳定,越靠上的层越易变。稳定层被多个端共享,易变层承载端差异,这样大部分改动被限制在局部,不会产生跨端连锁回归。
目录骨架
src/
├── pages/ 页面,按业务域分子目录(如 home、post、user)
├── components/ 跨页面复用组件
├── api/ 接口定义与请求封装
├── store/ 全局状态
├── utils/ 纯函数与工具(含平台网关)
├── config/ 多环境配置
├── static/ 图片、字体等静态资源
└── App.vue / main.js
页面按业务域划分,而不是按端划分。端差异不体现在目录上,而体现在文件内的条件编译块与 utils/platform 网关里——这是控制目录膨胀的关键。
公共层如何组织,避免循环依赖
公共层最容易失控的是相互引用。约束方式非常简单:依赖只能单向向下。
api只依赖utils与config,不反向依赖页面或组件;utils是叶子层,不依赖store、api、components;components可以依赖api、utils,但不依赖pages;store可以依赖api、utils,但不依赖pages与components。
一旦出现「组件去读页面数据」的需求,说明这段状态应该上提到 store,而不是让组件反向依赖页面。此外,跨页面的公共逻辑优先抽成 utils 里的纯函数,纯函数没有副作用,天然易测。
条件编译文件放哪里
条件编译是 uni-app 处理端差异的主要手段,但写法需要有统一约定,否则会散落各处:
- 平台专属组件:放在组件目录内,文件名后缀标识平台(如
xxx.mp-weixin.vue),并在同目录 README 中说明用途; - 平台专属逻辑:抽到
utils/platform/下,函数内部用// #ifdef MP-WEIXIN之类的注释块包裹,对外暴露统一函数名; - 平台专属页面配置:统一写在
pages.json对应页面的条件编译块中,不要散落到业务代码。
原则是:端差异集中在少数几个文件里,页面层保持「不知道有几个端」。
多环境配置的命名约定
配置建议拆为 config/dev.js、config/test.js、config/prod.js,再由 config/index.js 按编译环境统一导出。业务代码只 import config from '@/config',不直接引用具体环境文件。这样切换环境只改构建配置,不动业务代码。
小结
目录结构的本质是把「经常改的」和「很少改的」分开。稳定层向下沉淀、易变层向上收敛、端差异集中隔离,这套结构在后续接入新端时,改动范围可以被控制在 utils/platform 与配置文件之内,而不需要翻遍整个工程。