Expo 49 Android构建失败:无法解析react-d3-speedometer依赖
解决Expo 49 Android构建时
react-d3-speedometer依赖解析失败问题 问题场景
使用Expo 49执行npx expo构建Android包时,出现打包失败错误:
Android Bundling failed 162ms
Unable to resolve "react-d3-speedometer"
from "screens/BmiResultSpeedometerScreen.web.tsx"
该页面BmiResultSpeedometerScreen.web.tsx仅用于Web端,且已通过代码控制Android端不会跳转到此页面,但构建时仍会尝试解析该依赖。
相关代码与配置
1. Web端页面代码(screens/BmiResultSpeedometerScreen.web.tsx)
import ReactSpeedometer, { Transition } from "react-d3-speedometer"
2. 页面跳转控制代码
const screenToNavigate = Platform.OS === 'android' ? ScreenName.BMI_RESULT : Platform.OS === 'web' ? ScreenName.BMI_RESULT_SPEEDOMETER : ScreenName.BMI_RESULT; // 默认值 navigation.navigate(screenToNavigate, { bmi: Number.parseInt(bmiResult) });
3. package.json配置
{ "name": "bmi-calculator", "version": "1.0.0", "main": "node_modules/expo/AppEntry.js", "scripts": { "start": "expo start", "android": "expo start --android", "web": "expo start --web", "ts:check": "tsc" }, "dependencies": { "@expo/webpack-config": "^19.0.0", "@react-native-community/slider": "4.4.2", "@react-navigation/native-stack": "^6.9.17", "expo": "^49.0.21", "expo-updates": "~0.18.18", "react": "18.2.0", "react-d3-speedometer": "github:palerdot/react-d3-speedometer#master", "react-dom": "^18.2.0", "react-native-web": "^0.19.10" }, "devDependencies": { "@babel/core": "^7.23.6", "@types/react": "~18.2.46", "babel-plugin-react-native-web": "^0.19.10", "typescript": "^5.3.3" }, "private": true }
4. AppNavigator.tsx配置
import { createNativeStackNavigator } from "@react-navigation/native-stack"; import BmiResultScreen from "../screens/BmiResultScreen"; import BmiCalculatorScreen from "../screens/BmiCalculatorScreen"; import { ScreenName } from "../types/ScreenName"; import BmiResultSpeedometerScreen from "../screens/BmiResultSpeedometerScreen.web"; const AppStack = createNativeStackNavigator(); const AppNavigator = ()=>{ return( <AppStack.Navigator> <AppStack.Screen name={ScreenName.BMI_CALCULATOR} component={BmiCalculatorScreen} options={{ title: 'BMI CALCULATOR', headerStyle:{ backgroundColor: "#0A0C21", }, headerTitleStyle:{ color: 'white' } }} /> <AppStack.Screen name={ScreenName.BMI_RESULT} component={BmiResultScreen} options={{ title: 'BMI CALCULATOR', headerStyle:{ backgroundColor: "#0A0C21", }, headerTitleStyle:{ color: 'white' } }} /> <AppStack.Screen name={ScreenName.BMI_RESULT_SPEEDOMETER} component={BmiResultSpeedometerScreen} options={{ title: 'BMI CALCULATOR', headerStyle:{ backgroundColor: "#0A0C21", }, headerTitleStyle:{ color: 'white' } }} /> </AppStack.Navigator> ) } export default AppNavigator;
解决方案
方法1:动态导入+平台条件渲染(推荐)
修改AppNavigator.tsx,仅在Web平台注册Web端路由,并通过动态导入避免Android构建时解析依赖:
import { createNativeStackNavigator } from "@react-navigation/native-stack"; import BmiResultScreen from "../screens/BmiResultScreen"; import BmiCalculatorScreen from "../screens/BmiCalculatorScreen"; import { ScreenName } from "../types/ScreenName"; import { Platform } from "react-native"; const AppStack = createNativeStackNavigator(); const AppNavigator = ()=>{ return( <AppStack.Navigator> <AppStack.Screen name={ScreenName.BMI_CALCULATOR} component={BmiCalculatorScreen} options={{ title: 'BMI CALCULATOR', headerStyle:{ backgroundColor: "#0A0C21", }, headerTitleStyle:{ color: 'white' } }} /> <AppStack.Screen name={ScreenName.BMI_RESULT} component={BmiResultScreen} options={{ title: 'BMI CALCULATOR', headerStyle:{ backgroundColor: "#0A0C21", }, headerTitleStyle:{ color: 'white' } }} /> {/* 仅Web平台注册该路由 */} {Platform.OS === 'web' && ( <AppStack.Screen name={ScreenName.BMI_RESULT_SPEEDOMETER} // 动态导入,避免Android构建加载 component={async () => { const module = await import("../screens/BmiResultSpeedometerScreen.web"); return module.default; }} options={{ title: 'BMI CALCULATOR', headerStyle:{ backgroundColor: "#0A0C21", }, headerTitleStyle:{ color: 'white' } }} /> )} </AppStack.Navigator> ) } export default AppNavigator;
方法2:平台文件自动匹配
利用Expo的平台文件扩展名规则,让Android构建时自动忽略Web端文件:
- 创建
screens/BmiResultSpeedometerScreen.tsx(非Web平台占位组件):
import React from 'react'; import { View, Text } from 'react-native'; const BmiResultSpeedometerScreen = () => { return ( <View> <Text>此页面仅支持Web端</Text> </View> ); }; export default BmiResultSpeedometerScreen;
- 修改
AppNavigator.tsx的导入语句,去掉.web后缀:
// 让Expo自动根据平台选择对应文件 import BmiResultSpeedometerScreen from "../screens/BmiResultSpeedometerScreen";
这样Android构建时会加载.tsx文件,不会解析.web.tsx中的Web专属依赖。
方法3:依赖层面隔离
将react-d3-speedometer标记为Web专属依赖,避免Android构建时尝试安装:
- 安装
expo-build-properties:
npx expo install expo-build-properties
- 修改
package.json:
{ "dependencies": { "@expo/webpack-config": "^19.0.0", "@react-native-community/slider": "4.4.2", "@react-navigation/native-stack": "^6.9.17", "expo": "^49.0.21", "expo-updates": "~0.18.18", "expo-build-properties": "~0.8.3", "react": "18.2.0", "react-dom": "^18.2.0", "react-native-web": "^0.19.10" }, "devDependencies": { "@babel/core": "^7.23.6", "@types/react": "~18.2.46", "babel-plugin-react-native-web": "^0.19.10", "typescript": "^5.3.3", "react-d3-speedometer": "github:palerdot/react-d3-speedometer#master" }, "expo": { "plugins": [ [ "expo-build-properties", { "android": { "extraMavenRepos": [] } } ] ] } }
总结
优先选择方法1,能彻底避免Android构建时加载Web端页面和依赖;方法2适合需要保持路由统一的场景;方法3适合从依赖管理层面隔离Web专属包。
内容的提问来源于stack exchange,提问作者Slazer
相关产品推荐
相关产品推荐

