uni-app: ten real pitfalls moving from web to WeChat Mini Program
Our main frontend is uni-app: one codebase shipping both H5 and WeChat Mini Program. The ideal is attractive; the two months of migration gave us ten Mini-Program-specific pitfalls. Every one of them was reproduced on a real device and fixed — none of these are hearsay.
Critical: zero compile errors, an entire page goes dead
The sneakiest one: referencing an undefined variable inside setup()'s return object. Vue on the web warns you, but the uni-app Mini Program build is completely silent, and the runtime ReferenceError makes every event handler on the page stop working. The symptom is disorienting: the page renders perfectly, images load, and nothing is clickable.
The classic cause is a rename: goWithdraw becomes goExchange, the function definition and the template @tap both get updated, but the return object keeps the old name — or the reverse. Our countermeasure is a three-way cross check: return keys × defined names × template bindings, run as a checklist after every large refactor.
Lifecycle: never import page hooks from vue
uni-app page lifecycle hooks (onLoad / onShow / onReady) must come from @dcloudio/uni-app, or be written as options on the exported object. Importing same-named functions from the vue package raises no error, yet on Mini Program they never fire. On H5 it works fine because the underlying layer is Vue Router. This difference kept our profile page broken on Mini Program for a week before we found it.
Build output: deleted pages don't delete themselves
Remove a page from pages.json and rebuild — the old page files remain in the output directory. If those leftovers contain prohibited content (for us it was a withdrawn withdrawal feature), the whole package still fails review. The correct habit: wipe the output directory, rebuild from scratch, then verify every page in app.json has matching output files.
The same applies to build working copies: overlay-copying (cp -r src dst) only adds and never removes, so stale files accumulate. Our build script is now fixed to three steps: wipe, compile, and fully verify output against app.json.
Styling: rpx, fixed, and the safe area
- A
position: fixedelement is viewport-relative on both platforms — unless an ancestor has atransform, which makes fixed behave like absolute within that ancestor. Invisible on H5, guaranteed on Mini Program. - Bottom bars must consume
env(safe-area-inset-bottom), or buttons touch the screen edge on full-screen phones. Simulators don't show it. - The Mini Program root node is
page, notbody. Global background belongs inpage{}.
Networking: two separate whitelists
wx.request only reaches hosts on the "request legal domain" list, and file uploads additionally require the "uploadFile legal domain" — the two whitelists are independent. Our avatar upload kept failing in the trial version because only the first was configured. WebSocket and download each have their own entries too.
Payments: appid and merchant ID are hard-bound
requestPayment failing with APPID_MCHID_NOT_MATCH is not a frontend problem: the appid used to place the order backend-side doesn't match the merchant ID. Merchant accounts bind strictly to specific appids, and across a multi-brand matrix it's easy to cross the wires. We keep an "appid ↔ merchant" mapping as backend constants and route by platform server-side, never trusting the client to pass it.
Conditional compilation and platform checks
#ifdef MP-WEIXIN is compile-time only; runtime platform checks use uni.getSystemInfoSync().platform or the conditional-compile constants — don't mix them. And process.env.NODE_ENV is unreliable on Mini Program; environment detection belongs to backend config or a custom flag.
Real devices are the only truth
One final advisory that isn't a pitfall so much as a policy: the simulator and real devices are different worlds. Vibration, subscription messages, customer-service sessions, Bluetooth — absent or fake-success on simulators. Our team rule: any feature touching device capabilities or payments must pass real-device verification before review submission. Simulator green never counts as done.
After fixing these ten, we distilled them into a pre-release checklist. It's under twenty lines, and it has caught more issues than any code review we've run.