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:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- 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副本问题
- 删除
common目录下的node_modules和锁文件(package-lock.json/yarn.lock),避免依赖重复。 - 如果
common是独立包,在其package.json中添加peerDependencies,强制复用主项目的React版本:// common/package.json "peerDependencies": { "react": "^18.2.0", "react-native": "^0.72.0" // 其他主项目已安装的共享依赖,比如react-native-paper等 } - 确保metro配置中,
common的依赖指向主项目node_modules(当前Proxy配置已覆盖此逻辑)。
修复装饰器未被Babel处理问题
- 安装装饰器相关Babel插件:
npm install --save-dev @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties - 修改
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'], }, }, }; }; - 更新
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
相关产品推荐
相关产品推荐

