| name | miniprogram |
| description | Develop WeChat Miniprogram features following platform conventions and best practices. Use this skill when adding pages, components, or features to a WeChat Miniprogram project, debugging platform-specific runtime errors, or configuring routing, TabBar, or subpackage structure. |
- Adding, modifying, or deleting pages or subpackages in a miniprogram
- Creating or updating custom components
- Implementing Canvas 2D drawing, image processing, or export features
- Working with WeChat APIs (storage, navigation, media, album, network)
- Debugging WeChat Miniprogram-specific runtime errors
- Configuring routing, TabBar, or subpackage split strategy
- Applying design systems or SCSS styling
**Typical directory layout**:
```
miniprogram/
app.ts / app.json / app.scss ← global entry, design tokens, TabBar config
components/ ← globally shared custom components
pages/ ← main package (TabBar and entry pages)
subpackages/ ← lazy-loaded feature subpackages
utils/ ← shared helpers and service modules
data/ ← static assets such as JSON config files
typings/ ← project-level TypeScript type declarations
```
app.json is the source of truth for all registered pages and subpackage roots.
- Main package: TabBar pages and globally shared components only.
- Feature non-tab pages: one subpackage per feature under
subpackages/<feature>/.
**Lifecycle hooks**:
- `onLoad(options)` — init data, read storage, parse route params
- `onShow()` — refresh state that may have changed while the page was hidden
- `onReady()` — DOM ready; safe to query canvas nodes with `wx.createSelectorQuery`
- `onUnload()` — clean up timers or listeners
- `onPullDownRefresh()` — call `wx.stopPullDownRefresh()` when done
- `onReachBottom()` — use for pagination/infinite scroll
**Navigation API**:
| Destination | API |
|---|---|
| TabBar page | `wx.switchTab` |
| Non-TabBar page (push) | `wx.navigateTo` |
| Replace current page | `wx.redirectTo` |
| Go back | `wx.navigateBack` |
| Return data to caller | EventChannel via `getOpenerEventChannel()` |
Data-passing pattern selection:
| Situation | Pattern |
|---|
| Small scalar (ID, flag) | Route query param |
Structured result after redirectTo | wx.setStorageSync → wx.getStorageSync |
| In-flight object within one flow | getApp().globalData (clear when flow ends) |
| Return value from child picker page | EventChannel |
| Persist across app restart | wx.setStorageSync with stable key |
**User feedback** (adjust text to the project's language):
- Toast success: `wx.showToast({ title: '保存成功', icon: 'success' })`
- Toast error: `wx.showToast({ title: '操作失败,请重试', icon: 'none' })`
- Confirmation: `wx.showModal({ title, content, success(res) { if (res.confirm) { ... } } })`
Key APIs:
- Media:
wx.chooseMedia({ count, mediaType, sourceType, success })
- Save to album:
wx.saveImageToPhotosAlbum({ filePath, success, fail }) — requires scope.writePhotosAlbum
- Network:
wx.request<T>({ url, method, data, header, success, fail }) — domain must be in the server allowlist
- Permission: check with
wx.getSetting, request with wx.authorize; show modal guidance if denied
- System info:
wx.getSystemInfoSync() — call once per scope, cache the result
→ See examples/wechat-api-usage.md for network request, permission authorization, and media code templates.
- Storage total quota: **10 MB**; store only serialisable metadata, not binary blobs.
- Canvas: always `type="2d"`; the legacy `wx.createCanvasContext` API is deprecated and must not be used.
- Banned in all committed code: `console.log`; hardcoded `appId` or secrets; `wx.getSystemInfoSync()` inside loops.
See [reference/pii-permission-checklist.md](reference/pii-permission-checklist.md) for the full API-to-data-category mapping table and the four privacy obligations to verify before shipping any feature that collects user data. Load on demand when adding a feature that uses a sensitive API.
Load only the example directly relevant to the current task to minimize context size.
| Load when | Provides | File |
|---|
| Adding a new page to a subpackage — applying configure-subpackage | Full walkthrough: subpackage page file creation and app.json registration | examples/add-subpackage-page.md |
| Implementing Canvas 2D drawing, image processing, or export — applying canvas-setup-and-draw | Full walkthrough: node acquisition, drawing, and export patterns | examples/canvas-feature.md |
| Creating a custom component (observers, lifetimes, event triggering) — applying create-component | Full file templates: observers, lifetimes, and triggerEvent patterns | examples/custom-component.md |
| Managing data flow between pages (route params, storage, globalData, EventChannel) — applying add-page | All four inter-page data passing patterns with code templates | examples/inter-page-data-flow.md |
| Implementing persistent storage (read/write/trim) — applying manage-storage | Read/write/trim code templates with try/catch error handling | examples/storage-patterns.md |
| Using WeChat APIs (network requests, permissions, media) — applying add-page or create-component | Network request, permission authorization, and media code templates | examples/wechat-api-usage.md |
| Setting up TypeScript types for a miniprogram codebase — applying apply-typescript-patterns | tsconfig setup, IAppOption declaration, and WeChat canvas type cast examples | examples/apply-typescript-patterns.md |
| Styling pages or components with the SCSS design system — applying apply-styling | Design token definitions, BEM class naming patterns, and rpx vs px guidance | examples/apply-styling.md |
Steps to create and register a new page:
1. Read `app.json` to determine whether the page belongs in the main package or a subpackage.
2. Create `.wxml`, `.ts`, `.scss`, `.json` in the correct directory.
3. Add `"usingComponents": {}` in the page `.json`; add `"renderer": "webview"` if the page uses Canvas.
4. Register in `app.json` → `"pages"` (main package) or `"subpackages[].pages"` (subpackage, path relative to subpackage root).
5. Use `this.setData()` for all data mutations; never mutate `this.data` directly; batch calls, avoid in loops.
6. Encode complex route params with `encodeURIComponent(JSON.stringify(obj))`; decode in `onLoad(options)`.
→ See examples/inter-page-data-flow.md for route param encoding, storage hand-off, globalData, and EventChannel patterns.
Steps to build a custom component:
1. Create `.wxml`, `.ts`, `.scss`, `.json` with `"component": true` in the `.json`.
2. Expose the public API through `properties`; never reach into parent page state.
3. Communicate upward exclusively via `this.triggerEvent()`.
4. Use BEM class names scoped to the component name.
5. React to property/data changes with `observers`; use `lifetimes` (`attached`/`detached`) for setup and teardown.
6. Register the component using an absolute path (e.g. `/components/my-comp/my-comp`).
→ See examples/custom-component.md for full file templates, observers, and lifetimes patterns.
Steps to implement a Canvas 2D feature:
1. In `onReady`, call `wx.getSystemInfoSync()` once and cache `pixelRatio`.
2. Inside `wx.nextTick`, acquire the canvas node via `wx.createSelectorQuery().select('#id').fields({ node: true, size: true })`.
3. Set physical dimensions: `canvas.width = logicalWidth * pixelRatio`; call `ctx.scale(ratio, ratio)` so all drawing uses logical units.
4. Load images with `canvas.createImage()`; assign `src` after setting `img.onload` and `img.onerror`.
5. Export the result with `wx.canvasToTempFilePath({ canvas, ... })`.
→ See examples/canvas-feature.md for the complete node acquisition, drawing, and export pattern.
Steps to implement persistent storage:
1. Centralise all access in `utils/storage.ts`; define keys as named constants.
2. Before every array write, trim to the project limit: `items = items.slice(-MAX_ITEMS)`.
3. Wrap every read and write in `try/catch`; return safe defaults on read failure; show a toast on write failure.
→ See examples/storage-patterns.md for read/write/trim code templates.
How to type a miniprogram codebase:
1. Enable `"strict": true`, `"noImplicitAny": true`, `"strictNullChecks": true` in `tsconfig.json`.
2. Place shared types in `typings/index.d.ts`; always declare `IAppOption` to type `getApp().globalData`.
3. Prefer `interface` for object shapes and `type` for unions/aliases.
4. Load static JSON via `require('../../data/file.json') as MyType`.
5. Use `as WechatMiniprogram.Canvas` / `as CanvasRenderingContext2D` only for WeChat canvas types; add a comment explaining why.
→ See examples/apply-typescript-patterns.md for tsconfig setup, IAppOption declaration, and WeChat canvas type casts.
How to style pages and components:
1. Define design tokens as CSS custom properties on `page {}` in `app.scss`; reference via `var(--token-name)`.
2. Use BEM naming (`block__element--modifier`) scoped to each page or component SCSS file; no global class leakage.
3. Use inline `style` in WXML only for values computed at runtime in TypeScript; never for static styles.
→ See examples/apply-styling.md for design token definitions, BEM class naming patterns, and rpx vs px guidance.
Steps to add a page to a subpackage:
1. Create the page files under `subpackages//pages//`.
2. In `app.json`, add or update the entry under `"subpackages"`: set `"root"` to `subpackages/` and list the page path **relative to that root** under `"pages"`.
3. Navigate to the page using the **full absolute path** including the subpackage root (e.g. `subpackages/feature/pages/detail/detail`).
4. Never import large assets or libraries from inside a subpackage into the main package.
→ See examples/add-subpackage-page.md for the full file-creation and registration walkthrough.
When adding any new page, use add-page.
When a page needs Canvas, use canvas-setup-and-draw.
When building a reusable component, use create-component.
When placing a non-TabBar feature page, use configure-subpackage.
When choosing a navigation call, consult the navigation-apis knowledge table.
When passing data between pages, select the pattern from the navigation-apis data-passing table based on the situation.
When reading or writing persistent data, use manage-storage.
When writing TypeScript, follow apply-typescript-patterns.
When sizing UI elements, follow apply-styling.
Before implementing any feature that uses an API or component listed in pii-permission-checklist, verify all four privacy obligations: requiredPrivateInfos declaration, privacy-agreement popup, denied-permission guidance, and privacy policy update. Remind the user if any obligation is unmet.
When referencing examples, load only the one file relevant to the current task.