React与React Native代码共享Monorepo搭建及路径解析问题
嘿,我之前在做React Native + Web跨端项目时,也碰到过一模一样的路径解析问题,后来搭了Monorepo才彻底理顺,给你分享下具体的解决办法:
一、先搞定Shared文件夹的路径解析问题
你的项目结构是MyApp/mobile、MyApp/web、MyApp/shared,核心问题是web端(基于react-native-web)没法正确识别shared目录的导入路径,这本质是模块解析规则的配置问题,分两端来处理:
1. Web端配置(以Create React App为例)
如果你的web项目是用CRA初始化的,默认不能直接修改webpack配置,推荐用craco来扩展配置:
- 先安装craco:
npm install @craco/craco --save-dev或者yarn add @craco/craco -D - 在web项目根目录创建
craco.config.js文件,添加路径别名:
const path = require('path'); module.exports = { webpack: { alias: { '@shared': path.resolve(__dirname, '../shared'), }, }, };
- 修改web项目
package.json里的启动/构建命令,把react-scripts替换成craco:"scripts": { "start": "craco start", "build": "craco build", "test": "craco test" } - 之后你就可以用
import LoginForm from '@shared/components/LoginForm'这种方式导入共享组件了。
如果是自定义webpack配置的web项目,直接在resolve.alias里添加同样的路径映射即可。
2. React Native端配置
在mobile项目根目录的metro.config.js中添加路径别名配置:
const path = require('path'); const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); const customConfig = { resolver: { alias: { '@shared': path.resolve(__dirname, '../shared'), }, }, }; module.exports = mergeConfig(getDefaultConfig(__dirname), customConfig);
配置完成后,RN端就能正常识别shared目录的导入路径了。
二、搭建支持跨端代码共享的Monorepo
如果想长期维护跨端项目,Monorepo是更规范、可扩展的方案,这里推荐用Yarn Workspaces(轻量)或Nx(功能强大)来搭建,先讲Yarn Workspaces的基础步骤:
1. 初始化Monorepo结构
- 在
MyApp根目录创建package.json,配置workspaces字段:
{ "name": "myapp-monorepo", "private": true, "workspaces": [ "mobile", "web", "shared" ] }
- 确保每个子项目(mobile、web、shared)的
package.json都设置了合理的名称,比如shared的package.json可以这样写:
{ "name": "@myapp/shared", "version": "1.0.0", "main": "index.js", "peerDependencies": { "react": "*", "react-native": "*", "react-native-web": "*" } }
(peerDependencies用来声明共享组件依赖的宿主库,避免重复安装)
2. 配置依赖与组件引用
- 在根目录执行
yarn install,Yarn会自动将所有依赖安装到根目录的node_modules,同时为每个workspace创建软链接,让子项目可以互相引用。 - 之后在mobile或web项目中,直接用
import { LoginForm } from '@myapp/shared'就能导入共享组件,不需要再配置路径别名(当然也可以保留别名简化写法)。
3. 跨端组件适配技巧
在shared目录写组件时,要处理RN和Web的平台差异:
- 后缀区分实现:如果某个组件在两端有不同的实现,可以创建
Component.native.js(RN用)和Component.web.js(Web用),Metro和Webpack会自动根据平台加载对应文件。 - Platform判断:用RN的
PlatformAPI做样式或逻辑的差异化处理:
import { Platform, StyleSheet } from 'react-native'; const styles = StyleSheet.create({ loginButton: { padding: 12, ...Platform.select({ web: { cursor: 'pointer', borderRadius: 4 }, ios: { borderRadius: 8 }, android: { borderRadius: 2 }, }), }, });
- 优先用RN兼容API:react-native-web已经兼容了大部分RN核心组件,尽量用RN的组件(比如
View、Text、TouchableOpacity)代替Web原生组件,减少适配成本。
4. 可选:用Nx增强Monorepo能力
如果你的项目复杂度较高,需要增量构建、缓存、代码生成、依赖分析等功能,推荐用Nx。它对React和React Native的支持非常完善,可以一键生成跨端项目模板,还能帮你自动化处理很多重复工作,上手成本也不高。
最后提醒下:shared目录里的代码尽量只依赖RN和react-native-web都兼容的API,避免引入平台专属的模块(比如RN的Alert和Web的window.alert可以封装成统一的工具函数),不然会导致某一端编译报错。
内容的提问来源于stack exchange,提问作者shubham choudhary

