简介
本技术文档面向DouPHP小程序开发者,系统化阐述小程序的整体架构模式与最佳实践。内容覆盖页面组织结构、组件体系、状态管理、API调用层、缓存策略、错误处理、路由与导航、以及前后端数据交互规范。通过分层清晰的架构图与流程图,帮助读者快速理解并落地一套可维护、可扩展的小程序工程方案。
项目结构
小程序采用“多主题”组织方式,默认主题位于 miniprogram/default,企业主题位于 miniprogram/company。每个主题内部遵循统一的目录约定:
- pages:页面集合,按业务模块划分目录,如 product、order、user 等
- components:可复用UI组件,如 navbar、mp-html
- services:网络与服务层,封装HTTP请求、引导数据、语言包等
- stores:基于MobX的状态管理,包含 auth、cart、common 等全局状态
- utils:通用工具函数,如 route、tabbar、i18n、格式化等
- types:TypeScript类型定义,统一前后端契约
- config:站点配置与种子数据
- style:全局样式与第三方样式
graph TB
subgraph "小程序入口"
A["app.ts"]
B["app.json"]
end
subgraph "页面层"
P1["pages/index"]
P2["pages/product_category"]
P3["pages/order"]
P4["pages/user"]
end
subgraph "服务层"
S1["services/http.ts"]
S2["services/bootstrap.ts"]
end
subgraph "状态层"
ST1["stores/common.ts"]
ST2["stores/auth.ts"]
ST3["stores/cart.ts"]
end
subgraph "工具层"
U1["utils/route.ts"]
U2["utils/tabbar.ts"]
end
A --> S1
A --> ST1
A --> ST2
A --> ST3
B --> P1
B --> P2
B --> P3
B --> P4
P1 --> S1
P1 --> U1
P1 --> U2
ST1 --> S2
ST2 --> S1
ST3 --> S1
核心组件
- 应用启动与生命周期:App入口负责初始化全局状态、注册HTTP拦截器、解析推广参数、自动更新、调试开关与全局错误钩子
- HTTP请求层:统一信封解析、鉴权头注入、去重与内存缓存、SWR刷新、错误拦截与调试增强
- 状态管理:commonStore承载站点信息、功能开关、导航列表;authStore管理登录态与会话恢复;cartStore驱动购物车角标与数量
- 路由与导航:命名路由生成URL,结合rewrite_enable与mp_url;TabBar路径动态识别,避免写死索引
- 应用引导:bootstrap接口拉取站点配置、功能特性、导航列表与语言指纹,配合本地持久化实现秒开体验
架构总览
小程序采用“前端三层+后端服务”的分层架构:
- 表现层:pages + components,聚焦视图与交互
- 服务层:services/http、services/bootstrap,统一网络与引导数据
- 状态层:stores/*,集中管理跨页面共享状态
- 工具层:utils/*,提供路由、TabBar、国际化等能力
- 后端:通过命名路由与Bootstrap接口提供站点配置、功能开关、导航列表与业务数据
sequenceDiagram
participant App as "App(app.ts)"
participant Stores as "Stores(index.ts)"
participant Common as "CommonStore(common.ts)"
participant Auth as "AuthStore(auth.ts)"
participant Http as "HTTP(http.ts)"
participant API as "后端API"
App->>Stores : bootstrapStores()
Stores->>Common : hydrate()
Stores->>Auth : hydrate()
Stores->>Common : refresh()
Common->>Http : GET bootstrap/index
Http->>API : 请求引导数据
API-->>Http : {site,param,data,features,nav_list,...}
Http-->>Common : BootstrapData
Common->>Common : applyData(合并lang/features)
Common-->>Stores : 完成
Stores->>Auth : restore()
Auth->>Http : GET user/index
Http->>API : 获取登录态
API-->>Http : {dou.auth}
Http-->>Auth : 登录标志
Auth-->>Stores : 更新is_login/is_vip等
详细组件分析
应用启动与全局错误处理
- 在onLaunch中注册HTTP错误拦截器,遇到UNAUTHORIZED统一登出
- 解析推广参数写入本地缓存,便于后续分销追踪
- 启动全局store引导,先hydrate再refresh,确保首屏秒开
- 计算导航栏高度,适配不同设备
- 开启自动更新与调试模式,捕获未处理异常与页面不存在错误
flowchart TD
Start(["App.onLaunch"]) --> RegErr["注册HTTP错误拦截器"]
RegErr --> ParsePromo["解析推广参数(user_sn)"]
ParsePromo --> BootStores["bootstrapStores()"]
BootStores --> CalcNav["计算导航栏高度"]
CalcNav --> AutoUpdate["检查并提示更新"]
AutoUpdate --> Debug["非正式版启用vConsole"]
Debug --> End(["启动完成"])
HTTP请求层与缓存策略
- 信封解析:code为OK视为成功,否则构造ApiError并触发错误拦截器
- 默认头注入:Content-Type与Authorization(Bearer token)
- 去重与缓存:相同GET请求在飞行中复用Promise;支持cache/ttl/revalidate
- 调试增强:记录request_id,调试期弹出服务端异常堆栈
- REST方法伪装:PUT/DELETE通过_method字段兼容PHP接收
flowchart TD
Req["发起请求(request/get/post)"] --> Interceptors["执行请求拦截器"]
Interceptors --> CacheCheck{"是否命中内存缓存?"}
CacheCheck -- 是 --> ReturnCache["返回缓存数据"]
CacheCheck -- 否 --> Dedupe{"是否重复GET且飞行中?"}
Dedupe -- 是 --> UseInflight["复用飞行中Promise"]
Dedupe -- 否 --> WxReq["wx.request发送"]
WxReq --> ParseEnvelope["解析信封(code/message/data/errors/request_id)"]
ParseEnvelope --> Ok{"code === 'OK' ?"}
Ok -- 否 --> ErrIntercept["构造ApiError并执行错误拦截器"]
Ok -- 是 --> SuccessIntercept["执行成功拦截器并缓存"]
ErrIntercept --> Reject["拒绝Promise"]
SuccessIntercept --> Resolve["返回data<T>"]
状态管理与数据流
- commonStore:单一真相源,负责站点信息、功能开关、导航列表、语言包与版本校验;采用SWR模式,先hydrate再refresh
- authStore:管理登录态与会话恢复,根据features.user决定是否降级;ensureLogin用于强制登录跳转
- cartStore:驱动购物车角标,绑定到TabBar对应页的badge显示
classDiagram
class CommonStore {
+site
+lang
+param
+nav_list
+features
+data
+applyData(payload)
+hydrate()
+refresh()
}
class AuthStore {
+api_token
+user_id
+loginEd
+is_login
+is_vip
+is_work
+is_distribution
+hydrate()
+restore()
+ensureLogin(redirectUrl)
+login(payload)
+logout()
}
class CartStore {
+badge
+refresh()
}
CommonStore <.. AuthStore : "读取features"
AuthStore <.. CartStore : "登录后刷新"
路由系统与导航管理
- 命名路由:通过route(name, params)生成URL,支持占位符替换与query拼接;rewrite_enable关闭时回退index.php?route=形态
- TabBar运行时:通过__wxConfig.tabBar.list动态识别pagePath对应的真实index,避免写死索引导致漂移
- 页面跳转:根据是否为TabBar页选择switchTab或navigateTo/redirectTo
- 生命周期:页面onLoad/onShow/onReady中按需刷新状态与数据
sequenceDiagram
participant Page as "页面(index.ts)"
participant Route as "route.ts"
participant Tab as "tabbar.ts"
participant WX as "微信API"
Page->>Route : route('product', {id})
Route-->>Page : 生成URL(含path/query)
Page->>Tab : isTabBarPath(url)?
alt 是TabBar页
Tab-->>Page : true
Page->>WX : switchTab({url})
else 非TabBar页
Tab-->>Page : false
Page->>WX : navigateTo({url})
end
组件体系设计
- 全局组件:navbar作为顶部导航组件,在app.json中声明usingComponents,供各页面复用
- 富文本组件:mp-html用于渲染富文本内容
- 组件职责:保持无状态或最小状态,通过props与事件与页面通信,提升复用性与可测试性
小程序与主站的数据交互架构
- 引导数据:bootstrap接口返回站点配置、功能开关、导航列表与语言指纹,commonStore负责合并与持久化
- 业务数据:页面通过http.get/post调用具体业务接口,统一信封解析与错误处理
- 鉴权:Authorization头携带Bearer token,UNAUTHORIZED统一登出
- 多语言:lang接口单独拉取,commonStore在refresh时合并,lang_v用于增量更新判断
- 后端导航:MiniprogramNavigationBuilder构建与端无关的导航项,由后台同步至小程序配置
graph LR
Client["小程序客户端"] --> API["后端API"]
Client --> Store["commonStore"]
Store --> Bootstrap["bootstrap/index"]
Store --> Lang["lang接口"]
Client --> Routes["命名路由(route.ts)"]
Routes --> API
Store --> Features["功能开关(features)"]
Features --> Modules["模块级降级/启用"]
依赖关系分析
- app.ts依赖stores与services,负责生命周期与全局初始化
- stores依赖http与services/bootstrap,负责数据获取与状态更新
- 页面依赖stores、services与utils,负责视图渲染与交互逻辑
- utils/route与utils/tabbar为横切关注点,被多处复用
graph TB
App["app.ts"] --> Stores["stores/index.ts"]
Stores --> Common["stores/common.ts"]
Stores --> Auth["stores/auth.ts"]
Stores --> Cart["stores/cart.ts"]
Common --> Bootstrap["services/bootstrap.ts"]
Auth --> Http["services/http.ts"]
Cart --> Http
Pages["pages/*"] --> Http
Pages --> Route["utils/route.ts"]
Pages --> Tabbar["utils/tabbar.ts"]
性能考量
- 首屏秒开:commonStore与authStore先hydrate从storage恢复,再refresh网络数据,减少白屏时间
- 请求去重与缓存:相同GET请求在飞行中复用Promise;支持内存缓存与TTL控制,降低重复请求
- SWR刷新:bootstrap/lang接口失败不影响已有数据,保证用户体验连续性
- TabBar动态识别:避免写死索引导致的跳转失败与额外判断开销
- 调试优化:仅开发环境启用vConsole与异常弹窗,生产环境保持轻量
故障排查指南
- 统一错误对象:ApiError包含code、message、errors、request_id,便于定位问题
- 调试增强:调试期将request_id附加到message,并在服务端异常载荷存在时弹出堆栈
- 会话失效:UNAUTHORIZED触发登出流程,清除本地凭证并重置状态
- 页面不存在:onPageNotFound捕获并提示,便于发现拼写错误
- 网络异常:NETWORK_ERROR统一处理,提示用户检查网络
结论
DouPHP小程序采用清晰的分层架构与标准化的数据交互协议,通过HTTP层统一信封解析与缓存策略、状态层集中管理跨页面状态、工具层提供路由与导航能力,实现了高内聚、低耦合的可维护工程。结合后端Bootstrap与导航构建器,小程序具备强大的功能开关与动态导航能力。建议开发者遵循本文档的架构原则与最佳实践,持续优化性能与用户体验。
附录
- 类型契约:BootstrapData、Features、NavItem等类型定义保障前后端一致性
- 主题切换:miniprogram/default与company两套主题,便于多站点差异化定制
- 配置管理:app.json统一管理页面、窗口、组件与TabBar,确保发布版与运行态一致