本节导读:承接 1.2 的机制讲解,本节回答"这套体系从哪来、往哪去"。梳理从 html5+ 到 uni-app、再到 uni-app X 的演化时间线,以及 Vue2 与 Vue3、webpack 与 vite 两条并行技术线的由来——老项目维护与新项目选型都绕不开这张地图。
最初让 DCloud 站住脚的并不是 uni-app,而是更早的 html5+ 体系与 5+ App:把 WebView 封装成可调用原生能力的容器,让网页拿到推送、扫码、支付等系统能力。那一代方案证明了"Web 技术写原生应用"可行,但也暴露了体验短板——页面切换生硬、长列表掉帧。真正把这套积累收敛成跨端框架的转折点,是微信小程序的爆发:小程序验证了"逻辑层与渲染层分离 + 编译期转换"这条路,也制造了一个新问题——同一业务要在小程序和 H5 各写一遍。uni-app 的出发点就是把这两遍合成一遍:以 Vue 为语法基座,编译时输出小程序与 H5 两种产物,随后补上 App 端,形成三大宿主的统一。

理解今天的 uni-app,要分清两条并行的线。语法线:老项目多为 Vue2 写法(options 配置式),新项目推荐 Vue3(组合式 API,setup 语法糖);两套写法在同一框架里长期并存,编译器都认。工程线:HBuilderX 内置编译器开箱即用;CLI 方式则经历 vue-cli(webpack)到 vite 的迁移。两条线的组合决定了你的项目长什么样——这也是很多网上示例"抄不动"的根源:人家是 Vue3 加 vite 的工程,你的是 Vue2 加 HBuilderX 编译,生命周期名、插件安装方式、配置文件位置都可能有差别。判别自己工程的身份,看三处就够:
// 1) manifest.json 里 vueVersion 字段 { "vueVersion": "3" } // Vue3 工程 // 2) 依赖清单:@dcloudio/vite-plugin-uni 存在即 vite 线 // @dcloudio/webpack-uni-pages-loader 存在即 webpack 线 // 3) 入口写法:出现 defineComponent 与 setup 即 Vue3 语法 import { defineComponent, ref } from 'vue'; export default defineComponent({ setup() { const count = ref(0); return { count }; } });
演化路线图落到工程里,就变成几类具体的兼容问题。第一类是框架版本与编译器的绑定关系:HBuilderX 的版本号决定内置编译器的能力,Vue3 工程对 HBuilderX 版本有下限要求,团队里两个人用不同版本的 IDE 打开同一工程,一个人能编译、另一个人报语法错误,是真实发生过的场景。CLI 线对应地看依赖清单里 uni-app 相关包的版本,锁定版本是团队协作的底线。第二类是小程序基础库的碎片化:你代码里用的某个新 API,要求用户侧微信基础库在某个版本之上;低版本用户拿到的是运行时报错。工程上的对策是把版本要求写进 manifest 的兼容配置,并在代码里做能力检测兜底:
// 能力检测:不确定基础库是否支持时,先问再调 function vibrateShort() { if (uni.canIUse('vibrateShort')) { uni.vibrateShort(); } else { // 老基础库的降级路径:静默跳过或换用旧接口 console.log('当前环境不支持短震动'); } }
第三类是写法层面的世代差异:Vue2 时代的社区方案(过滤器、事件总线、mixin 复用)在 Vue3 线各有替代,抄老方案进新工程是版本演进最常见的"翻车路径"。判断一份资料的新旧,看它用不用组合式 API、提不提 vite,比看发布日期更可靠。
能力检测与条件编译是互补的两件工具:条件编译裁决"这段代码属于哪个平台",能力检测裁决"这个平台上的这个版本有没有这个能力"。前者在编译期完成,后者在运行时发生——把两者各归其位,版本碎片化带来的问题就剩下测试覆盖问题了。
uni-app X 代表演化的下一个阶段:不再把 JavaScript 桥接到原生,而是用 uts 语言在编译期直接产出 Kotlin(Android)与 Swift(iOS)代码,类型检查因此前移到编译期。对学习路线的意义在于:uni-app X 里条件编译的地位不降反升——既然最终产物是真正的原生代码,哪些代码属于哪端必须在编译期裁得更干净。本册主体仍聚焦成熟的 vue 版 uni-app,但会把 uni-app X 的关键差异在 7.4 节集中交代,方便你判断新项目要不要押注。
其一,双线并存是常态而非过渡,接手老项目先鉴定语法线与工程线,再动手;其二,框架的每次演化都在把差异裁决向编译期前移,条件编译的书写规范值得从一开始就当团队公约;其三,小程序生态的扩容(各家平台陆续接入)意味着平台标识表会继续变长,代码里别硬编码"端数量"之类的假设,永远以平台标识为准。
时间线对维护期团队还有一层实用价值:给代码"断代"。打开一座老仓库,看依赖清单里的框架版本、manifest 的 vueVersion、组件的写法风格,三处一对照就能断出仓库的年代——断代的目的是校准修改策略:老世代的代码遵循最小改动原则,别顺手把新写法混进去,混进去的每一处都是断代裂缝上的隐患。商城团队接手老仓库时做过一次断代盘点,把"可以安全修改的区域"与"只读保留的区域"画成两张清单,此后半年的维护再没出现"改一处崩一片"的事故。时间线不是历史知识,是修改半径的量尺。