Tamagui monorepo中Expo部分部署方案及EAS构建问题排查
基于Tamagui Starter-Free Monorepo(集成Solito)的Expo部署方案
1. EAS Build 原生构建(正式/测试包)
- 基础命令:
eas build --profile production --platform android/ios,适配monorepo需确保eas.json在项目根或apps/expo目录配置正确,指定工作区依赖解析规则 - OTA更新:通过
eas update推送增量更新,需在eas.json中配置多环境profile,同步共享包版本避免依赖不兼容 - 本地构建:执行
eas build --local,适合自定义原生配置场景,需提前安装Android Studio/Xcode等平台工具
2. Expo Go 开发预览
- 在
apps/expo目录执行npx expo start,通过二维码/本地连接快速验证共享组件(如packages中的认证屏幕) - 限制:共享包内原生模块需兼容Expo Go,自定义原生代码需切换至Dev Client
3. 自定义Dev Client构建
- 命令:
eas build --profile development --platform android/ios,生成带开发工具的自定义客户端,支持原生模块与自定义配置,解决Expo Go不兼容的原生依赖问题 - monorepo适配:确保
metro.config.js正确配置watchFolders与nodeModulesPaths,让Dev Client能解析packages目录的共享代码
4. 静态Web部署(结合Solito)
- 执行
npx expo export在apps/expo目录生成静态文件,上传至Vercel/Netlify等平台托管 - 注意:共享组件中的原生API(如AsyncStorage)需做Web兼容,例如替换为
localStorage或使用@react-native-async-storage/async-storage的Web适配层
部署注意事项(Solito路由、原生依赖)
Solito路由相关
- 确保共享路由(
packages/app/navigation)在Expo与Next.js中配置一致,Expo端需正确导入共享路由并使用SolitoRouter - 认证路由逻辑:EAS构建包中避免依赖Expo Go专属环境变量,使用
process.env.EXPO_PUBLIC_*定义全局环境变量 - 深层链接测试:构建后需验证深层路由跳转,确保Solito路由解析在原生包中正常工作
原生依赖相关
- 共享包中的原生模块(如AsyncStorage)需统一在根目录或
apps/expo安装,避免子项目重复安装导致依赖冲突 - SDK版本兼容:Expo SDK 51需搭配对应版本的原生依赖,例如
@react-native-async-storage/async-storage需安装^1.23.1及以上版本 - 缓存清理:构建前执行
npx expo prebuild --clean清理原生缓存,避免模块链接失败 - 平台区分:共享包中需通过
Platform.OS判断环境,避免直接导入原生代码导致Web端打包错误
EAS构建APK错误排查
问题1:NativeModule: AsyncStorage is null
原因
- 共享组件导入AsyncStorage的方式未适配EAS构建环境,Expo Go会自动处理原生模块链接,但自定义构建包需手动确保依赖解析正确
- monorepo依赖解析异常:
metro.config.js配置问题导致共享包无法找到AsyncStorage的原生实现
解决方案
- 统一依赖安装:在项目根目录执行
yarn add @react-native-async-storage/async-storage,确保所有子项目共享同一依赖 - 修正导入方式:使用Expo推荐的导入路径
import AsyncStorage from '@react-native-async-storage/async-storage'; - 清理构建缓存:
- 在
apps/expo目录执行npx expo prebuild --clean - 删除
apps/expo/android目录,重新执行eas build --profile development --platform android
- 在
- 验证metro配置:确保
resolver.nodeModulesPaths包含根目录node_modules,让共享包能正确解析依赖
问题2:初始认证路由不匹配
原因
- 初始路由逻辑依赖开发环境变量或Expo Go专属配置,EAS构建包中环境变量未正确注入
- Solito路由初始化顺序错误,导致认证路由未被加载
解决方案
- 环境变量配置:在
eas.json对应profile中配置认证相关的EXPO_PUBLIC_*变量,或通过npx expo secrets管理 - 调整路由初始化逻辑:在Expo入口文件(
apps/expo/app/_layout.tsx)中确保SolitoRouter优先初始化import { SolitoRouter } from 'solito/router'; import { routes } from '@your-packages/app/navigation'; export default function Layout() { return <SolitoRouter routes={routes} initialRouteName="auth" />; } - 预测试:使用自定义Dev Client测试路由跳转,确保非Expo Go环境下正常工作
- 检查共享路由:确保packages中的路由配置无Web专属规则,需同时适配原生与Web环境
附:相关配置文件参考
apps/expo/tsconfig.json
{ "extends": "../../tsconfig.base", "include": [ "app/**/*.ts", "app/**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts", "declarations.d.ts" ], "compilerOptions": { "composite": true, "jsx": "react-jsx" }, "references": [] }
apps/expo/metro.config.js
const { getDefaultConfig } = require('@expo/metro-config') const path = require('node:path') const projectRoot = __dirname const workspaceRoot = path.resolve(projectRoot, '../..') const config = getDefaultConfig(projectRoot) // 监听monorepo所有文件 config.watchFolders = [workspaceRoot] // 指定依赖解析顺序 config.resolver.nodeModulesPaths = [ path.resolve(projectRoot, 'node_modules'), path.resolve(workspaceRoot, 'node_modules'), ] // 禁用层级依赖查找 config.resolver.disableHierarchicalLookup = true config.transformer = { ...config.transformer, unstable_allowRequireContext: true } config.transformer.minifierPath = require.resolve('metro-minify-terser') // 支持svg转换 const { transformer, resolver } = config config.transformer = { ...transformer, unstable_allowRequireContext: true, minifierPath: require.resolve('metro-minify-terser'), babelTransformerPath: require.resolve('react-native-svg-transformer/expo'), } config.resolver = { ...resolver, assetExts: resolver.assetExts.filter((ext) => ext !== 'svg'), sourceExts: [...resolver.sourceExts, 'svg'], } module.exports = config
内容的提问来源于stack exchange,提问作者ColstonBod-oy
相关产品推荐
相关产品推荐

