7.7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Build & Development
# WeChat mini-program
npm run dev:weapp # Watch/dev build → weapp/
npm run build:weapp # Production build → weapp/
# H5 (web)
npm run dev:h5 # Watch/dev build → build/
npm run build:h5 # Production build → build/
Output directories are determined by TARO_ENV: for H5 it's build/, for all other platforms it matches the platform name (e.g., weapp/).
No test or lint scripts are configured. ESLint (eslint-config-taro) and Stylelint are installed but must be run manually.
Architecture
This is a Taro 3.6 cross-platform app using React 18 (concurrent mode), TypeScript, and Webpack 5. It targets WeChat, Alipay, DingTalk, JD, Kwai, QQ, Baidu, Toutiao mini-programs, and H5 web.
UI Library: @antmjs/vantui
The UI library is @antmjs/vantui (v3), a Taro-compatible port of Vant. Components are imported from @antmjs/vantui directly (e.g., import { Button } from '@antmjs/vantui'). The babel-plugin-import in babel.config.js handles on-demand style imports.
Page Structure
Each page lives in src/pages/<name>/ and consists of three files:
index.tsx— page component (functional or class)index.config.ts— page-level config (title, navigation style, etc.)index.less— page styles
Pages must be registered in src/app.config.ts under the pages array.
Path Alias
@ maps to src/ (configured in config/index.js).
Theme & Global Styles
src/app.less— global app styles (imported inapp.ts)src/styles/index.less— theme variable overrides for Vant UI. It imports@antmjs/vantui/es/style/var.lessand uncomments/redefines Less variables to customize the theme. This file is injected into every.lessfile via LessmodifyVars(configured inconfig/index.jsunder bothmini.lessLoaderOptionandh5.lessLoaderOption).
Webpack Customizations (config/webpack/)
commonChain.js— Overrides Taro's defaultscriptruleexcludeso that Babel also processes thesenode_modulespackages:taro,inversify,@antmjs,react-spring,recoil,buffer,qrcode. Do NOT include "taro" in the project name or all node_modules will be recompiled.miniChain.js— Applied to mini-program builds. Adds:MiniFixPlugin— fixes path param encoding differences between WeChat/Douyin and Alipay/DingTalkGlobalFixPlugin— polyfills theglobalvariable for Alipay, DingTalk, and Baidu mini-programs
h5Chain.js— Applied to H5 builds. AddsH5FixPluginfor H5 compatibility fixes.
Build Config Layers
config/index.js exports a function that merges the base config with config/development.js or config/production.js based on NODE_ENV. Environment variables:
| Variable | Purpose | Default |
|---|---|---|
TARO_ENV |
Target platform (weapp, h5, alipay, etc.) |
weapp |
NODE_ENV |
Build mode | production |
API_ENV |
API environment selector | real |
designWidth: 750— all px values are converted to rpx at this ratio@tarojs/plugin-framework-reactis configured withreactMode: "concurrent"(React 18 concurrent features)browserslisttargets iOS 9+ for production
App Entry
src/app.ts— class-based App component, rendersthis.props.children(the current page)src/app.config.ts— defines routes (pagesarray), window config, and app-level settingssrc/index.html— H5 entry HTML template
VantUI Component API Reference (v3.7)
This project uses @antmjs/vantui v3.7. The official docs: https://antmjs.github.io/vantui/main/
Always check the actual type definitions in node_modules/@antmjs/vantui/types/ when unsure about props. Key API notes for commonly used components:
Search
shape:'square'(default) |'round'background: background color string (default#FFFFFF)onFocus,onBlur,onChange,onSearch,onClear,onCancel— event callbacksleftIcon,rightIcon— icon name or image URLshowAction+actionText— right-side action button
Swiper (NOT the same as Taro's native Swiper)
autoPlay— auto-play interval in ms (0 = disabled). Notautoplayloop— infinite loop mode. NotcircularpaginationColor— indicator dot color. NotindicatorColorpaginationVisible— show/hide pagination dotsduration— animation duration (default 500)width/height— card dimensions- No
indicatorActiveColorprop — only onepaginationColor onChangecallback:(currPage: number) => void(not an event object)
SwiperItem
- Minimal component, only
classNameandchildren. No special props.
Grid / GridItem
Grid:columnNum,border,gutter,square,clickable,center,iconSizeGridItem:icon(string),text(ReactNode),iconColor,dot,info/badge,url+linkType
Tabs / Tab (v3.7)
Tabs:active— current tab index (number | string)sticky— enable sticky modeoffsetTop— sticky offset in px. NotstickyOffsetTopcolor,titleActiveColor,titleInactiveColor— color propstype:'line'|'card'swipeable— enable swipe gesture switchinganimated— enable tab switch animationellipsis— text overflow ellipsis (default true)- No
lineWidthorlineHeightprops onChange:(e: { detail: { index: number; name?: string; title?: string } }) => void
Tab:title(ReactNode),name(identifier),dot,info,disabled,titleStyle
Image (VantUI Image, not Taro's native Image)
src,fit('contain' | 'cover' | 'fill' | 'widthFix' | 'heightFix' | 'none'),width,height,radiusround— circular image (boolean)lazyLoad,showError,showLoadingrenderLoading,renderError— custom render slots
Common VantUI pattern: Taro's native components vs VantUI components
- Use
@tarojs/componentsfor:View,Text,ScrollView,Image(native, simpler) - Use
@antmjs/vantuifor: styled UI components (Search, Swiper, Tabs, Grid, Button, etc.) - VantUI component props extend Taro's
ViewProps, soonClick/onTapand style props are always available
Custom TabBar (src/custom-tab-bar/)
This project uses Taro's custom tabBar mechanism (tabBar.custom: true in app.config.ts). Key rules:
Component location
- The custom tabBar component MUST be at
src/custom-tab-bar/index.tsx— this is a Taro convention, not configurable - Taro automatically renders this component on every tab page; do NOT import
<CustomTabBar />in individual pages
Do NOT use CoverView
CoverView/CoverImagehave known bugs on real devices: invisible, click events don't bubble- Use regular
<View>withposition: fixed; bottom: 0; z-index: 999instead
Active tab state
- Taro creates a new instance of the tabBar component on each page, so
useStateresets on every tab switch - Derive the active tab from
Taro.getCurrentPages()at render time — NOT from component state - Pattern:
const route = Taro.getCurrentPages()[last]?.route; const activeKey = TAB_LIST.find(t => route.includes(t.key))
Tab switching
- Use
Taro.switchTab({ url: pagePath })— this matches native tabBar behavior - The
pagePathformat must match thetabBar.list[].pagePathinapp.config.ts
Center "publish" button
- The publish button is a UI-only element not in
tabBar.list - It triggers a VantUI
<Popup>rendered as a sibling of the tabBar, NOT nested inside it - The popup state can use
useStatesince it's ephemeral and not shared across tabs