← 返回 Skill 列表
extension
分类: 开发与工程API Key 暂未确认

taro-miniprogram-dev

Taro 4.x + React 18 + TypeScript 微信小程序开发框架技能。适用于:(1) 初始化或维护 Taro 4 项目并编译为微信小程序/H5;(2) 创建页面、组件、样式与页面配置;(3) 搭建 services 请求层(真实后端或 Mock);(4) 配置 app.config、TabBar、路由与设计系统;(5) 排查跨端差异。触发关键词:小程序开发、Taro开发、Taro4、微信小程序、mini program、Taro框架、项目初始化。

person作者: l576298567hubModelScope

Taro 4.x 小程序开发技能

面向 Taro 4.3 + React 18 + TypeScript + @tarojs/components(截至本次核对,npm 上 @tarojs/cli 最新稳定版就是 4.3.0)。

三条版本底线,先记住再写代码:

  • Node.js ≥ 18(@tarojs/cli@4.3.0 的 engines.node 就是 >= 18)。
  • React 只能是 18:@tarojs/react@4.3.0 与 @tarojs/plugin-framework-react@4.3.0 的 peer 都是 react ^18,上 React 19 会在安装期或构建期炸。
  • 不要再加 NODE_OPTIONS=--openssl-legacy-provider:那是 webpack4/md4 时代的历史包袱,Taro 4 + webpack5 在 Node 24 下直接构建通过。

初始化

# 装 CLI(npm / yarn / pnpm 任选,下面以 pnpm 为例)
pnpm add -g @tarojs/cli

# 用官方模板创建(交互式:框架 / TS / CSS 预处理器 / 包管理器)
taro init myApp
npx @tarojs/cli init myApp     # 不想全局安装时

# 或用本技能自带的 4.3 模板骨架(含 services 层、Mock 开关、示例页面)
bash scripts/init_project.sh my-miniprogram

taro init 会按 yarn > cnpm > npm 探测并自动装依赖;装失败再进目录手动 pnpm install。

pnpm 10+ 的硬门槛:默认拒绝执行依赖的 postinstall,pnpm 12 直接让 pnpm install 以 ERR_PNPM_IGNORED_BUILDS 失败。Taro 的 @tarojs/cli / @tarojs/binding / @swc/core / esbuild / core-js 都要跑 postinstall,必须放行:pnpm approve-builds(交互式,自动写回配置),或在 pnpm-workspace.yaml 写 allowBuilds: { '@tarojs/cli': true, ... } —— pnpm 12 的键名是 allowBuilds,pnpm 10 那个 onlyBuiltDependencies 已改名。模板已带这份白名单(实测 pnpm install 退出码 0);npm / yarn 项目不需要这个文件。

命令

| 命令 | 说明 | |------|------| | pnpm dev:weapp | = taro build --type weapp --watch,微信开发者工具导入 dist/ | | pnpm build:weapp | 微信小程序生产构建 | | pnpm dev:h5 / build:h5 | 同一份代码跑浏览器 | | taro build --type <t> | 目标:weapp swan alipay tt qq jd h5 rn | | taro build --type weapp --pages pages/a/index | 只编指定页面,大项目调试提速 | | taro build --type weapp --blended / --new-blended | 混编:Taro 页面嵌进原生小程序工程 | | taro build --plugin weapp | 小程序插件工程 | | taro create --name=xxx --type=page | 由 @tarojs/plugin-generator 生成页面骨架 | | taro info / taro doctor / taro inspect | 环境信息 / 项目体检 / 导出 webpack 配置 |

目录结构

config/index.ts        # defineConfig<'webpack5'>,designWidth / mini / h5
types/global.d.ts      # /// <reference types="@tarojs/taro" /> + 图片模块声明
babel.config.js        # 仅 webpack 编译器需要;babel-preset-taro { framework: 'react', ts: true }
src/
├── app.config.ts      # defineAppConfig:pages / window / tabBar
├── app.tsx            # 函数组件入口,返回 children
├── index.html         # H5 端模板
├── styles/global.scss # 设计系统 token
├── pages/{module}/{page}/index.tsx + index.scss + index.config.ts
└── services/{api,utils}/ + mock.ts

编译配置(config/index.ts)

import { defineConfig, type UserConfigExport } from '@tarojs/cli';

export default defineConfig<'webpack5'>(async () => ({
  sourceRoot: 'src',
  outputRoot: 'dist',
  framework: 'react',
  compiler: 'webpack5', // 'webpack4' | 'webpack5' | 'vite'(vite 自 Taro 4.0.0 起支持)
  designWidth: 750,     // 见下方「px → rpx」
  deviceRatio: { 375: 2, 640: 2.34 / 2, 750: 1, 828: 1.81 / 2 },
  mini: { postcss: { pxtransform: { enable: true, config: {} } } }, // 小程序端配置键是 mini,早期按平台写 weapp 的写法已不再使用
  h5: { publicPath: '/', devServer: { port: 10086 } },
}));

px → rpx:designWidth: 750 时源码 1px → 1rpx(按 750 设计稿直接量);designWidth: 375 时 1px → 2rpx(按 CSS 像素写)。两种都不能混用——本技能模板走 375,仓库里的 apps/miniprogram 走 750,改基线要连带改所有尺寸。

页面写法

新代码一律函数组件 + hooks(类组件的生命周期仍被支持,但别在新增页面里用):

import { Text, View } from '@tarojs/components';
import Taro, { useRouter, useDidShow, usePullDownRefresh } from '@tarojs/taro';
import { useState } from 'react';
import './index.scss';

export default function TaskDetailPage() {
  const { params } = useRouter();               // 替代 3.x 的 this.$router.params
  const [loading, setLoading] = useState(true);

  useDidShow(() => {
    // 每次页面显示刷新
  });
  usePullDownRefresh(async () => {
    // TODO: 换成真实请求,例如 await getTaskDetail(params.taskId)
    setLoading(false);
    Taro.stopPullDownRefresh();                  // 必须手动收起
  });

  return (
    <View className="page">
      <Text>{loading ? '加载中...' : `任务 ${params.taskId ?? ''}`}</Text>
    </View>
  );
}
// pages/task/detail/index.config.ts —— 页面配置是 .config.ts + definePageConfig
export default definePageConfig({
  navigationBarTitleText: '任务详情',
  enablePullDownRefresh: true,
});

细节(路由 API、TabBar 片段、分包、生命周期对照表)见 references/pages.md。

API 一律走 Taro.*

不要出现裸 wx.:H5/RN 端直接失效,且绕开 Taro 的类型。这是硬约束,不是风格问题。

import Taro from '@tarojs/taro';

Taro.setStorageSync('token', token);
const token = Taro.getStorageSync<string>('token');
await Taro.navigateTo({ url: '/pages/home/index' });

需要平台分支时用 process.env.TARO_ENV('weapp' | 'h5' | 'rn' | ...),别用 typeof wx !== 'undefined'。

请求层与 Mock

// services/utils/request.ts —— 切真实后端只改这两行
const IS_MOCK = true;
const BASE_URL = 'https://api.example.com';

// services/api/index.ts
import { get, post } from '../utils/request';
export const getUserInfo = () => get<UserInfo>('/api/auth/user-info');

响应约定、鉴权头、模块划分见 references/api-design.md。

流式接口(SSE)在小程序端要 Taro.request({ enableChunked: true }) + onChunkReceived,回调给的是 ArrayBuffer 且可能在多字节字符中间切断,必须增量解码:

decoder ??= new TextDecoder('utf-8');
buffer += decoder.decode(res.data as ArrayBuffer, { stream: true }); // 不带 stream:true 中文必乱码

设计系统

见 references/design-system.md。里面那套粉色是示例品牌,换项目请整组替换 token,不要只改一两个色值。

编译与预览

微信开发者工具导入 dist/,AppID 先用测试号 touristappid,开发期勾选「不校验合法域名」。

  • project.config.json 的 miniprogramRoot 指向 dist/,别改到根目录。
  • src/sitemap.json 不会被自动拷进 dist/,配了 sitemapLocation 就必须用 copy.patterns 显式拷贝(from 以 src/ 开头、to 以 dist/ 开头,from 不支持 glob),否则开发者工具会报文件不存在。
  • tabBar 的 iconPath 必须是真实存在的图片文件,缺文件开发者工具直接报错——这也是本技能模板默认不配 tabBar 的原因,需要时按 references/pages.md 补。
  • dist/ 与 node_modules/ 要进 .gitignore;dist/ 里的 project.config.json 每次构建会被覆盖。

真机相关坑(跨端不一致的高发区)

  1. 自定义导航栏(navigationStyle: 'custom')要自己算状态栏与胶囊按钮:
const { statusBarHeight = 0, windowWidth } = Taro.getWindowInfo();
const menu = Taro.getMenuButtonBoundingClientRect();
const navbarHeight = (menu.top - statusBarHeight) * 2 + menu.height;
const safeRight = windowWidth - menu.left + 8;
  1. ScrollView 的 scrollTop 是受控属性:不跟 onScroll 里回写真实值,重渲染时会把上一次的旧目标值重新应用,表现为「点开折叠区就跳回底部」。
  2. H5 端 Taro 组件的真实类名带前缀(Textarea 渲染成 taro-textarea、Button 成 taro-button-core,已在 @tarojs/components 产物里核对),样式要打到这一层,只写「自定义类名 + 原生标签」的组合会被它自己的默认样式压掉。
  3. disabled={false} 在 H5 会渲染成 disabled="false" 属性,CSS 的 [disabled] 选择器照样命中,置灰态请用显式的 class 判断,别用属性选择器。
  4. Button 有默认背景/边框/字号,重写时同时清 button 与 [role="button"],并补 ::after { border: none }。
  5. useShareAppMessage / useShareTimeline 只在微信端生效,H5 分支要给降级入口,别把分享按钮做成永久高亮却什么都不发生。
  6. 4.3 的 TARO_ENV 类型里出现了 harmony / jdrn,但 taro build --type 的可选项仍是 weapp/swan/alipay/tt/qq/jd/h5/rn,别在代码里假定它们能构建。

从 Taro 3 迁过来的破坏性改动

| 3.x 写法 | 4.x 写法 | |----------|----------| | NODE_OPTIONS=--openssl-legacy-provider | 删掉 | | 配置里的 weapp: {} | mini: {} | | index.config.js / app.config.js | index.config.ts + definePageConfig / defineAppConfig | | class Page extends Component + componentDidShow | 函数组件 + useDidShow / useLoad | | (this as any).$router.params | useRouter().params | | wx.request / wx.setStorageSync | Taro.request / Taro.setStorageSync | | @tarojs/cli init . --framework react | taro init myApp(交互式,含 CSS 预处理器与包管理器选择) |