Monorepo share library with CRA, React Native with Lerna 101
July 16, 2020
This is a simple step-by-step manual on how to share logic between a React app created by CRA and a React Native app. In order to do this, we are going to use a tool for managing multiple JavaScript packages called Lerna.
1- Install the Lerna 2.0 package globally
$ npm install --global lerna
2- Create a project repository
$ git init lerna-react-repo && cd lerna-react-repo
3- Set this folder as a Lerna workspace
$ lerna init
We should have this structure in the folder:
>packages
lerna.json
package.json
4- Create the web app in the package folder (we need create-react-app installed globally)
$ cd package && npx create-react-app web-app
5- Install dependencies.
You have to run the command "yarn" in the root file, Lerna will install all the dependencies for the project in the folder packages
$ cd .. && yarn
6- Create the React Native app (if you don’t know how to start working with React Native, you can check out this post)
$ cd package && npx react-native init NativeApp
$ cd .. && yarn
$ cd packages && cd NativeApp && cd ios && pod install
7- To test if the installation works, run this in the root folder
To test in web:
$ lerna --scope=web-app run start
To test mobile app in Android:
$ lerna --scope=NativeApp run android
To test mobile app in iOS:
$ lerna --scope=NativeApp run ios
8- Create my shared library - this is the package where the project’s shared code lives
lerna create library
9- Setup Babel in my library
$ lerna add babel-loader packages/library —-dev
$ lerna add @babel/core packages/library —-dev
$ lerna add @babel/cli packages/library —- dev
$ lerna add @babel/preset-env packages/library —- dev
$ lerna add @babel/preset-react packages/library —- dev
10- Add a name to my shared library in the package.json
In this example, my shared library is going to be referenced by the name "@root/shared"
{
"name": "@root/shared",
"version": "0.0.0",
"description": "shared library",
"keywords": [
"test"
],
"author": "Gabriel Rodriguez <grodriguez@vairix.com>",
"homepage": "https://www.vairix.com/",
"license": "ISC",
"main": "lib/library.js",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib"
],
"scripts": {
"test": "echo \"Error: run tests from root\" && exit 1"
},
"dependencies": {
"@babel/cli": "^7.10.4",
"@babel/core": "^7.10.4",
"@babel/preset-env": "^7.10.4",
"@babel/preset-react": "^7.10.4",
"babel-loader": "^8.1.0"
}
}
11- Sharing my library with my web and mobile app
To do this, I have to add this dependency in the "package.json"
"@root/shared": "*"
12- Link my local package to to the dependencies using Lerna Bootstrap
$ lerna bootstrap
13- Adding metro configuration for React Native. We have to update the Watch Folder in the file metro.config.js to include packages directory
Create "packages/NativeApp/metro.config.js" with the following contents:
/**
* Metro configuration for React Native
* https://github.com/facebook/react-native
*
* @format
*/
const path = require('path');
const watchFolders = [
//Relative path to packages directory
path.resolve(__dirname + '/..'),
];
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
watchFolders,
};