[react-native-web 모노레포] - 공통 앱 작성, 모바일 빌드 환경 구성

hclee·2020년 12월 4일
2
post-thumbnail

웹과 모바일에서 동일한 사용자 경험을 제공하기 위해 단일 React-Native 앱을 작성하고 모바일과 웹 모두 빌드할 수 있는 모노 레포지토리를 구성해보자.

github 레포지토리

주요 패키지 버전

  • react : 16.13.1
  • react-native : 0.63.3
  • react-native-web : 0.14.8
  • styled-components : 5.2.1
  • nextjs : 10.0.3
  • typescript : 4.1.2
  • @babel/core : 7.12.1
  • yarn : 1.22.10

1. yarn workspace 설정

워크 스페이스 생성

mkdir -p ~/nextjs-rn-monorepo/packages
cd ~/nextjs-rn-monorepo
yarn init

package.json에 워크 스페이스 설정 추가

워크 스페이스의 로컬 패키지 경로를 package.json에 추가한다.

// ~/nextjs-rn-monorepo/package.json 

{
  ...
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*"
    ]
  },
  ...
}

2. @nextjs-rn-monorepo/app 패키지 설정

mkdir -p ~/nextjs-rn-monorepo/packages/app
cd ~/nextjs-rn-monorepo/packages/app
yarn init -y

app/package.json 수정

// ~/nextjs-rn-monorepo/packages/app/package.json

{
  "name": "@nextjs-rn-monorepo/app",
  "version": "0.0.1",
  "private": true,
  "main": "./src/index.ts",
  "license": "MIT",
  "devDependencies": {
    "@types/react": "16.14.0",
    "@types/react-native": "0.63.3",
    "@types/styled-components": "5.1.4"
  },
  "peerDependencies": {
    "react": "^16.13.1",
    "react-native": "^0.63.3",
    "styled-components" : "^5.2.1"
  }
}

React-Native 앱 작성

화면에 REACT-NATIVE-WEB과 앱이 동작되는 Platform(ios, android, web)을 출력하는 간단한 앱을 작성한다.

app/src 파일

src ➜ tree
.
├── App.tsx
├── SubTitle
│   ├── SubTitle.native.tsx
│   ├── SubTitle.web.tsx
│   └── index.ts
└── index.ts
// ~/nextjs-rn-monorepo/packages/app/src/App.tsx

import React from 'react';
import { Platform  } from 'react-native';
import Styled from 'styled-components/native';

import SubTitle from './SubTitle';

const Container = Styled.View`
  display: flex;
  justify-content: center;
  align-items: center;
  background: #4B7EFF;
  height: 100%;
  width: 100%;
`;

const Title = Styled.Text`
  color: white;
  font-size: 32px;
  font-weight: 900;
`;


export const App = () => {
  console.log(Platform.OS);
  return (
    <Container>
      <Title>REACT NATIVE WEB</Title>
      <SubTitle />
    </Container>
  )
}
// ~/nextjs-rn-monorepo/packages/app/src/index.ts

export { App } from './src/App';
// ~/nextjs-rn-monorepo/packages/app/src/Subtitle.native.tsx

import React from 'react';
import { Platform } from 'react-native';
import Styled from 'styled-components/native';

const Text = Styled.Text`
  color: white;
  font-size: 24px;
  font-weight: bold;
`;

export default function SubTitle() {
  return <Text>{`On ${Platform.OS.toUpperCase()}`}</Text>
}
// ~/nextjs-rn-monorepo/packages/app/src/Subtitle.web.tsx

import React from 'react';
import Styled from 'styled-components/native';

const Text = Styled.Text`
  color: white;
  font-size: 24px;
  font-weight: bold;
`;

export default function SubTitle() {
  return <Text>On WEB</Text>
}
// ~/nextjs-rn-monorepo/packages/app/src/SubTitle/index.ts

import SubTitle from './SubTitle.native';

export default SubTitle;

3. @nextjs-rn-monorepo/mobile 로컬 패키지 설정 (react-native)

react-native 앱을 빌드하기 위한 로컬 패키지를 설정한다.

@nextjs-rn-monorepo/mobile 패키지 생성

cd ~/nextjs-rn-monorepo/packages
npx react-native init mobile --version 0.63.3 --template react-native-template-typescript

의존성 패키지 설치 에러가 발생하지만 무시

패키지가 생성되었다면 패키지명을 수정한다.

// ~/nextjs-rn-monorepo/packages/mobile/package.json

{
  "name": "@nextjs-rn-monorepo/mobile", 
  ...
}

의존성 패키지를 루트 node_modules로 이동

모든 로컬 패키지의 의존성 패키지들을 제거하고 루트 경로에 재설치한다. ios/andriod 원활할 빌드를 위해 로컬 경로가 아닌 루트 경로의 node_modules로 모든 의존성 패키지를 이동한다.

  • 주의 - 로컬 패키지 간에 의존성 버전 충돌이 있는 경우 루트 node_modules로 이동되지 않음
cd ~/nextjs-rn-monorepo
rm -rf node_modules packages/*/node_modules
yarn install --check-file

metro 번들러 설정 변경

metro 번들러가 모바일 빌드시 다른 로컬 패키지나 루트 node_modules의 의존성 패키지를 참조할 수 있도록 워크 스페이스의 루트 경로를 추가한다.

// ~/nextjs-rn-monorepo/packages/mobile/metro.config.js

const path = require('path')

module.exports = {
  watchFolders: [path.resolve(__dirname, '../..')],
  ...
}

react-native.config.js 생성

ios의 pod 패키지 설치 시 참조하기 위한 react-native 의존성 패키지 경로를 설정한다.

// ~/nextjs-rn-monorepo/packages/mobile/react-native.config.js 

module.exports = {
  reactNativePath: '../../node_modules/react-native',
}

ios 빌드 설정 변경

mobile의 모든 의존성 패키지들이 루트 경로로 이동했기 때문에 ios 빌드 관련 파일들 내 node_modules의 경로도 루트 node_modules로 수정해야 한다.

대상 파일

  • mobile/ios/Podfile
  • mobile/ios/mobile.xcodeproj/project.pbxproj

node_modules 수정 내역

경로를 모두 수정하였다면 pod 패키지를 모두 설치하고 ios 빌드 설정을 마무리한다.

cd ~/nextjs-rn-monorepo/packages/mobile/ios
pod install

android 빌드 설정 변경

ios 빌드 설정처럼 android 빌드 관련 파일 내 node_moduels의 경로도 루트 node_modules로 수정해야 한다.

대상 파일

  • mobile/android/build.gradle
  • mobile/android/settings.gradle
  • mobile/android/app/build.gradle

node_modules 수정 내역

경로를 모두 수정하였다면 android 빌드에 필요한 패키지들이 자동 설치될 수 있게 mobile/android 프로젝트를 안드로이드 스튜디오에서 열어 주자.

mobile에 App 추가

기존 App.tsx를 삭제하고 @nextjs-rn-monorepo/app에서 작성한 앱을 index.js에 추가한다.

cd ~/nextjs-rn-monorepo/packages/mobile
rm -f App.tsx
yarn add styled-components@5.2.1
yarn workspace @nextjs-rn-monorepo/mobile add @next-rn-monorepo/app@0.0.1
// ~/nextjs-rn-monorepo/packages/mobile/index.js

import { AppRegistry } from 'react-native';
import { App } from '@nextjs-rn-monorepo/app';
import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => App);

ios/android npm 스크립트 수정

기본 npm 빌드 스크립트로 ios나 anroid를 실행하는 경우 빌드 실패가 발생하는데 이 문제를 우회하기 위해 package.json을 수정한다.

yarn add --dev concurrently
// ~/nextjs-rn-monorepo/packages/mobile/package.json


  "scripts": {
    "android": "concurrently \"yarn start\" \"react-native run-android --no-packager\"",
    "ios": "concurrently \"yarn start\" \"react-native run-ios --no-packager\"",  
    ...

ios / android 빌드 확인

yarn run ios

yarn run android


2개의 댓글

comment-user-thumbnail
2021년 4월 7일

fastlane ios beta 같은 작업들도 monorepo 환경에서 잘 동작하셨었나요??

답글 달기
comment-user-thumbnail
2021년 4월 22일

진짜 정말 감사합니다. 도움 많이 됐습니다.

@types/react-native/index.d.ts 파일에
// reference path="react-native.d.ts" /> // 댓글에 태그 에러 나가지구 < 붙혀야합니다.
이 부분도 추가를 해줘야 타입 에러가 발생하지 않더라구요.

답글 달기