In here I am going to add a mobile application project, which will be using some of the libraries we have in our mono repository. In this case, I will be creating a React Native Application, as an example.
Create React Native Application #
Here I am going to create a react-native application with the typescript template. It should be as easy as:
cd packagesnpx react-native init mobile --template react-native-template-typescriptHowever, after this you will see some problems on the ios application. It is not able to install dependencies on ios application.
It happens due to the way workspaces store dependencies, saving the common dependencies on the root node_modules and not in each package.
For ios application the configurations for dependencies expect a relative path for node_modules folder, something like:
require_relative '../node_modules/react-native/scripts/react_native_pods'
After digging a while I found it is a solved problem, with a simple solution. We need to configure react-native dependencies to not be hoisted by our workspace and be stored in the local node_modules. This article, explains it very well..
I changed the worksapces property in our root package.json to:
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/react-native",
"**/react-native/**"
]
}
And try to create the react nartive application again. After a while it is created and we should be ready to start our new mobile application.
I just update packages/mobile/package.json name:
"name": "@mr/mobile",For now I am going to run it directly on packages/mobile:
yarn iosI can see the boilerplate application. I am now going to add our types and utils libraries to show our books information as we did in our web application here:
yarn lerna add @mr/utils --scope=@mr/mobileFollowed by
yarn lerna add @mr/types --scope=@mr/mobileAfter that my application stops working while trying to auto reload, when I change some application code. It happens due to watchman not being able to reload linked libraries with yarn, done by lerna when application are installed or bootstrap command is executed:
error: Error: Unable to resolve module `@babel/runtime/helpers/interopRequireDefault` from `App.tsx`: @babel/runtime/helpers/interopRequireDefault could not be found within the project.
If you are sure the module exists, try these steps:
1. Clear watchman watches: watchman watch-del-all
2. Delete node_modules: rm -rf node_modules and run yarn install
3. Reset Metro's cache: yarn start --reset-cache
4. Remove the cache: rm -rf /tmp/metro-*
at ModuleResolver.resolveDependency (/Users/nb24696/Experiments/my-mono-repo/packages/mobile/node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js:186:15)
at ResolutionRequest.resolveDependency (/Users/nb24696/Experiments/my-mono-repo/packages/mobile/node_modules/metro/src/node-haste/DependencyGraph/ResolutionRequest.js:52:18)
at DependencyGraph.resolveDependency (/Users/nb24696/Experiments/my-mono-repo/packages/mobile/node_modules/metro/src/node-haste/DependencyGraph.js:287:16)
at Object.resolve (/Users/nb24696/Experiments/my-mono-repo/packages/mobile/node_modules/metro/src/lib/transformHelpers.js:267:42)
at /Users/nb24696/Experiments/my-mono-repo/packages/mobile/node_modules/metro/src/DeltaBundler/traverseDependencies.js:434:31
at Array.map ()
at resolveDependencies (/Users/nb24696/Experiments/my-mono-repo/packages/mobile/node_modules/metro/src/DeltaBundler/traverseDependencies.js:431:18)
at /Users/nb24696/Experiments/my-mono-repo/packages/mobile/node_modules/metro/src/DeltaBundler/traverseDependencies.js:275:33
at Generator.next ()
at asyncGeneratorStep (/Users/nb24696/Experiments/my-mono-repo/packages/mobile/node_modules/metro/src/DeltaBundler/traverseDependencies.js:87:24)
I was expecting this problem, because It has happened to me in a project I am working on. There, I am using WML to solve the problem, and it works very well. However, it requires some setup and an external tool:
wml add packages/utils packages/mobile/node_modules/@mr/utilswml add packages/utils packages/mobile/node_modules/@mr/typeswml startFor this case, I found another solution, that I think it is a better automation here, and improve the developer experience. This solution is easier to mantain.
The solution is to tell watchman to watch for our packages. We can do it updating metro.config.js:
/**
* 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,
};
I have got this ideia here. We will need to restart the application for metro to get those configuration.
After having the application started again, I have changed the packages/mobile/src/App.tsx to use our @mr/utils and @mr/types packages. The application has reloaded with those modifications well:
import React from "react";
import { SafeAreaView, ScrollView, View, Text, StatusBar } from "react-native";
import { allBooks } from "@mr/utils";
import { IBook } from "@mr/types";
const App = () => {
const books = allBooks();
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<ScrollView contentInsetAdjustmentBehavior="automatic">
{allBooks().map(function renderBook(book: IBook): JSX.Element {
return (
<View key={book.id}>
<Text>{book.title}</Text>
<Text>{book.author}</Text>
<Text>{book.tag}</Text>
</View>
);
})}
</ScrollView>
</SafeAreaView>
</>
);
};
export default App;
We are now able to update our packages and having it reload immediately. We just need to remember to rebuild packages after our changes.
SPA Build Fix #
After adding the react-native application I have also found some conflicts on dependency versions in different packages, in this case, in our spa in regard to babel-jest, when we try to build it. Due to the way create-react-app works I am not able to change the version of babel-jest, directly, without ejecting it. To solve it, I have added babel-jest to not be hoisted. I have also removed all node_modules and manually executed yarn.
I have changed the worksapces property in our root package.json to:
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/react-native",
"**/react-native/**",
"**/babel-jest"
]
}
Published