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

Expo项目中如何对同级目录文件应用Babel转换?

Expo项目引用同级通用代码的问题解决

问题现象

测试阶段报错

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app
    See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

推测原因:common目录自带node_modules,其中包含React,导致项目存在多份React副本。

运行npx expo start后浏览器端报错

Uncaught Error: Module parse failed: Unexpected character '@' (24:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.

推测原因:使用@autobind装饰器的通用代码文件未被Babel正确处理。

已尝试的配置

metro.config.js

const path = require('path');
const { getDefaultConfig } = require('expo/metro-config');

const config = getDefaultConfig(__dirname);

const commonDir = path.resolve(__dirname + '/../common');
const extraNodeModules = {
  'common': commonDir,
};
config.resolver.extraNodeModules = new Proxy(extraNodeModules, {
  get: (target, name) =>
    //redirects dependencies referenced from common/ to local node_modules
    name in target ? target[name] : path.join(process.cwd(), `node_modules/${name}`),
});
config.watchFolders.push(commonDir);
module.exports = config;

tsconfig.json

{
  "extends": "expo/tsconfig.base",
  "compilerOptions": {
    "allowJs": true,
    "strict": true
  },
  "include": [
    ".*.js",
    "*.js",
    "**/*.js",
    "*.ts",
    "**/*.ts",
    "*.tsx",
    "**/*.tsx",
    "../common/*.ts",
    "../common/**/*.ts",
    "../common/*.tsx",
    "../common/**/*.tsx"
  ],
  "exclude": [
    "coverage/",
    "node_modules/",
    "web-build/",
  ]
}

babel.config.js

module.exports = function (api) {
    api.cache(true);
    return {
        presets: ['babel-preset-expo'],
        plugins: [
            ['module-resolver', {
                alias: {
                    kidneykeeper: './src',
                    common: '../common',
                },
            }],
            ['transform-inline-environment-variables', {
                include: [
                    'NGROK_HOST',
                ],
            }],
            'react-native-reanimated/plugin',
        ],
        env: {
            production: {
                plugins: ['react-native-paper/babel'],
            },
            test: {
                plugins: ['react-native-paper/babel', 'dynamic-import-node'],
            },
        },
    };
};

解决方案

修复多份React副本问题

  1. 删除common目录下的node_modules和锁文件(package-lock.json/yarn.lock),避免依赖重复。
  2. 如果common是独立包,在其package.json中添加peerDependencies,强制复用主项目的React版本:
    // common/package.json
    "peerDependencies": {
      "react": "^18.2.0",
      "react-native": "^0.72.0"
      // 其他主项目已安装的共享依赖,比如react-native-paper等
    }
    
  3. 确保metro配置中,common的依赖指向主项目node_modules(当前Proxy配置已覆盖此逻辑)。

修复装饰器未被Babel处理问题

  1. 安装装饰器相关Babel插件:
    npm install --save-dev @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties
    
  2. 修改babel.config.js,添加装饰器插件(注意顺序,decorators需在class-properties之前):
    module.exports = function (api) {
        api.cache(true);
        return {
            presets: ['babel-preset-expo'],
            plugins: [
                ['@babel/plugin-proposal-decorators', { legacy: true }],
                ['@babel/plugin-proposal-class-properties', { loose: true }],
                ['module-resolver', {
                    alias: {
                        kidneykeeper: './src',
                        common: '../common',
                    },
                }],
                ['transform-inline-environment-variables', {
                    include: [
                        'NGROK_HOST',
                    ],
                }],
                'react-native-reanimated/plugin',
            ],
            env: {
                production: {
                    plugins: ['react-native-paper/babel'],
                },
                test: {
                    plugins: ['react-native-paper/babel', 'dynamic-import-node'],
                },
            },
        };
    };
    
  3. 更新tsconfig.json的compilerOptions,启用装饰器支持:
    "compilerOptions": {
      "allowJs": true,
      "strict": true,
      "experimentalDecorators": true,
      "emitDecoratorMetadata": true
    }
    

额外操作

修改配置后,清除metro缓存再重启项目:

npx expo start --clear

避免使用npm install --save ../common安装本地包,直接通过别名引用即可,防止符号链接引发依赖问题。

内容的提问来源于stack exchange,提问作者Seán Hayes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:25:23