Expo 33.0 이상의 버전을 이용하면 React Native Web 이 built-in 되어 있어서 편하게 모바일과 웹 개발을 동시에 할 수 있지만, Expo 를 이용하게 되면 발생되는 Limitation 때문에 Yarn Workspace 를 이용하여 Mono Repo 를 구성하고자 합니다.
이 프로젝트에서는 react 16.12.0, react-native 0.61.5 를 사용합니다.
$ git clone https://github.com/wecanooo/react-native-web-mono-repo.git
$ cd react-native-web-mono-repo
$ yarn
$ cd packages/mobile/ios
$ pod install
$ cd -
$ yarn workspace web start
$ yarn workspace common watch
$ yarn workspace mobile start
$ yarn workspace ios
또는$ yarn workspace android
ios emulator, android emulator 설치에 대한 내용은 여기에서 다루지 않습니다.
아래 Step by Step 섹션은 이 프로젝트를 만들어가는 과정에 대해서 다른 내용입니다.
이 프로젝트에서는 다음과 같은 기술들이 사용됩니다.
-
Mono Repo 프로젝트 생성
- package.json 생성:
$ yarn init -y
- tsconfig.json 생성:
$ tsc --init
- tsconfig.base.json 생성
- react-native 및 typescript 의존성 설정
- package.json 에 workspaces, scripts 설정
- package.json 생성:
-
Package 구성
-
$ rm yarn.lock && rm -rf node_modules
-
$ mkdir -p packages/common/src packages/mobile packages/web
-
-
-
$ gem install cocoapods
-
$ npx react-native init mobile
-
$ rm yarn.lock && rm -rf node_modules
- Project Root 에서
$ yarn
을 실행 - Packages 내의 프로젝트 내부에 있는 node_modules 에 패키지가 설치되는 것이 아니라 Project Root 의 node_modules 에 설치가 되는 것을 확인해야 합니다.
-
$ yarn add -D typescript @types/jest @types/react @types/react-native @types/react-test-renderer
-
-
Mono Repo 구성을 위한 React Native 프로젝트 튜닝 (for iOS)
- 찾기 & 변경 기능을 통해
../../node_modules/react-native/
라고 되어 있는 값들을 모두../../../../node_modules/react-native/
로 변경 -
metro.config.js
파일을 다음과 같이 변경
const path = require("path"); module.exports = { projectRoot: path.resolve(__dirname, "../../"), transformer: { getTransformOptions: async () => ({ transform: { experimentalImportSupport: false, inlineRequires: false } }) } };
-
$ open packages/mobile/ios/mobile.xcodeproj/
수행 후AppDelegate.m
파일의jsBundleURLForBundleRoot:@"index"
파일의index
부분을packages/mobile/index
로 변경 - XCode 의
Build Phases > Bundle React Native code and Images
설정에 다음의 값으로 변경
export NODE_BINARY=node export EXTRA_PACKAGER_ARGS="--entry-file packages/mobile/index.js" ../../../node_modules/react-native/scripts/react-native-xcode.sh
- Podfile 에서
require_relative
항목의 경로를 수정한 뒤pod install
수행 -
$ yarn workspace mobile start
와$ yarn ios
를 통해 모바일에서 실행이 되는지 확인
- 찾기 & 변경 기능을 통해
-
Mono Repo 구성을 위한 React Native 프로젝트 튜닝 (for Android)
-
packages/mobile/android/app/src/main/java/com/myprojectname/MainApplication.java
파일의getJSMainModuleName
함수의 내용을return "index";
에서return "packages/mobile/index";
로 변경 -
packages/mobile/android/app/build.gradle
파일 내의project.ext.react =
부분을 다음의 코드로 변경하고apply from:
부분의 경로를 Project Root 로 설정
project.ext.react = [ entryFile: "packages/mobile/index.js", root: "../../../../" ]
-
settings.gradle
파일의apply from:
항목의 경로를../../../node_modules/~
로 변경 -
$ yarn android
로 실행이 되는지 확인 (Android Studio 다운로드 및 AVD Manager 설정에 대한 설명은 다루지 않습니다.)
-
-
Common Packages 와 코드 공유
- 필요한 패키지 설치
$ yarn add react react-native
,$ yarn add -D typescript @types/react @types/react-native rimraf
- package.json 생성:
$ yarn init -y
{ "name": "@cosmos/common", "version": "0.0.1", "main": "dist/index.js", "license": "MIT", "scripts": { "postinstall": "npm run build", "build": "rimraf dist && tsc", "watch": "tsc --watch" }, "dependencies": { "react": "^16.12.0", "react-native": "^0.61.5" }, "devDependencies": { "@types/react": "^16.9.19", "@types/react-native": "^0.61.15", "rimraf": "^3.0.2", "typescript": "^3.7.5" } }
- tsconfig.json 생성:
$ tsc --init
{ "extends": "../../tsconfig.base.json", "compilerOptions": { "composite": true, "declaration": true, // "emitDeclarationOnly": true, "isolatedModules": false, "module": "commonjs", "outDir": "dist", "rootDir": "src", "experimentalDecorators": true, "jsx": "react", "typeRoots": ["@types", "../../node_modules/@types"] }, "include": ["src/**/*"], "exclude": ["node_modules"] }
- 필요한 패키지 설치
-
React Native Web 프로젝트 생성
- CRA 로 React Project 생성
$ cd packages && npx create-react-app web
- React Native Web 관련 패키지 설치
$ yarn add react-native-web react-art
- Typescript 패키지 설치
$ yarn add -D typescript @types/react-native @types/react @types/react-dom
- tsconfig.json 설정
$ tsc --init
{ "extends": "../../tsconfig.base.json", "compilerOptions": { "forceConsistentCasingInFileNames": true, "noEmit": true, "typeRoots": ["@types", "../../node_modules/@types"] }, "include": ["src"], "references": [ { "path": "../components" } ] }
- package.json 에 common 패키지 추가
{ "dependencies": { ... "@cosmos/common": "0.0.1", ... } }
- src 폴더 재설치
$ rm -rf src
,packages/web/src/index.tsx
파일 생성
import { AppRegistry } from "react-native"; import { App } from "@cosmos/common"; AppRegistry.registerComponent("cosmos", () => App); AppRegistry.runApplication("cosmos", { rootTag: document.getElementById("root") });
-
$ yarn start
실행하면 웹화면을 확인할 수 있음
- CRA 로 React Project 생성
-
Mobx 로 state 관리
React Hook 을 이용하기 위해 mobx-react-lite 를 설치합니다.
- mobx, mobx-react-lite 패키지 설치
$ yarn add mobx mobx-react-lite
- useContext 와 mobx-react-lite 를 연동하여 store 관리
- experimentalDecorators 적용을 위한 설정
- observable, observer, action 연동
- mobx, mobx-react-lite 패키지 설치
-
React Navigation 추가
- Bottom Tab Navigation 연동
- Stack Navigation 연동
-
API 연동
-
UI Template 제작