You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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端文件:

  1. 创建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;
  1. 修改AppNavigator.tsx的导入语句,去掉.web后缀:
// 让Expo自动根据平台选择对应文件
import BmiResultSpeedometerScreen from "../screens/BmiResultSpeedometerScreen";

这样Android构建时会加载.tsx文件,不会解析.web.tsx中的Web专属依赖。

方法3:依赖层面隔离

将react-d3-speedometer标记为Web专属依赖,避免Android构建时尝试安装:

  1. 安装expo-build-properties:
npx expo install expo-build-properties
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 11:30:16