UniApp Mini Programs Are a Compatibility Minefield, and Here's the Map
Mini programs are the primary mobile delivery channel for Chinese internet services, and UniApp is the default bridge for Vue teams. The platform inconsistencies documented here — missing `Intl`, divergent Promise behavior, silent tree-shaking of CSS imports — are not edge cases; they are the baseline every team shipping to WeChat will hit, and the wrapper patterns shown prevent them from scattering platform-specific hacks across business logic.
UniApp promises to let Vue developers write once and ship to H5 and WeChat Mini Programs. The reality is a long list of behavioral differences between the two targets — slots fire lifecycle hooks when they shouldn't, `v-if` accepts different types, and audio contexts break on replay. The official HBuilderX IDE hides dependencies, removes `package.json`, and locks projects into a walled garden that only it can maintain. The CLI path keeps standard tooling but forces manual easycom configuration and IDE plugin hunting just to get component resolution working.
The core defense is a wrapper layer around every `uni.*` API. Raw calls return inconsistent shapes across platforms: WeChat rejects a missing storage key while Alipay resolves with null, and `uni.login` returns different success flags per vendor. A `wrapUni` utility forces everything into a typed `Promise` with normalized `MpError` objects, and business code never touches `uni` directly again. Internationalization, state management with Pinia, and SSE streaming all demand similar defensive layers because the runtime on real devices lacks `Intl` and `TextDecoder`.
Package size limits, qualification reviews, and a sub-packaging system that the documentation barely mentions turn the first deployment into a separate ordeal. Third-party Markdown parsers fail at build time or on real hardware, and upgrading `@dcloudio/*` packages can silently break the project. The takeaway is not that UniApp is unusable — it ships — but that every assumption about cross-platform behavior must be verified on real devices, and the framework's own tooling is often the biggest obstacle.
UniApp's design assumes developers will surrender their toolchain to HBuilderX; the CLI escape hatch works but the framework punishes you with manual config and missing IDE support.
The platform inconsistency table is not a bug list — it is the actual API contract. Any team treating H5 as a development proxy for the mini program will ship broken behavior.
Wrapping `uni.*` is not premature abstraction. The type definitions in `@dcloudio/types` are wrong (e.g., `chooseImage` typed as `void` but returns a `Promise`), and the runtime behavior diverges per vendor in ways the types cannot express.
Internationalization breaks on real devices because WeChat's JavaScript engine strips `Intl`; this is a runtime constraint, not a UniApp bug, but the framework's docs do not surface it prominently.
The dependency tree is fragile: pinned versions, a custom update CLI, and a years-old unresolved issue where upgrading `@dcloudio/*` packages silently breaks the project suggest the maintainers prioritize HBuilderX compatibility over the npm ecosystem.
Both UniApp and Taro force developers to accept outdated toolchains and API design compromises that originate in WeChat's own API; the choice is less about framework quality and more about which set of legacy constraints a team can tolerate.