Introduction
If you’re starting the development of a new product, you may run in the need of having both a mobile and a web app. In this blog post we are going to discover how to do that efficiently!
The problem
Sharing business logic between your product’s mobile and web app can be a very useful way to improve execution and maintainability. However, sharing business logic between different platforms is not always easy, because it requires careful consideration of different factors (which we are going to talk about later).
In this article we are going to make examples of shared logic between a React app and a React Native mobile app by using the monorepo approach. Also, to better handle our monorepo, we are going to use Nx by Nrwl!
Monorepo approach
In the last few years, monorepos have become a popular choice for managing large code bases. A monorepo is essentially a single repository that contains all the modules of a project and their dependencies. Its adoption is driven by several factors:
- Developers tend to prefer working in one repository over many smaller ones. This approach reduces the overhead of switching contexts between different projects and minimizes conflicts when developers collaborate on changes across multiple repositories at once.
- It’s easier to find files when everything lives together in one place (this can be especially useful if you have large teams with dozens or hundreds of engineers).
- Using a single source control system (e.g. git) means there’s no need for complicated branching strategies or other workarounds to make sure your team doesn’t end up with dozens of copies of the same code base scattered across different repos—your entire codebase lives in one place!
What is Nx?
Nx is a smart, fast and extensible build system with first class monorepo support and powerful integrations.
It has support for Javascript/Typescript environments, providing caching in cloud and fast builds.
All the modules in one single repository? 🤔
Yes, I know it may sound taboo, but let’s analyze the pros for our specific example:
- we have a single package.json file, then Nx will handle shared dependencies between multiple packages.
- we can centralize the linting, building, testing and release process.
- it is convenient to coordinate changes between multiple packages. For example, if we have a package that is dependency of two others, we will just need one command to update both of them, and we won’t have to open 2 pull requests and bother half of the team
In addition, there are several examples of famous monorepo, let’s look at some of them:
- Babel: a popular JavaScript compiler used in web development. A monorepo holds the complete project and all its plug-ins.
- React itself is a monorepo
What are the cons?
One of the biggest drawbacks to this approach is that it can become very hard to organize, as each package in the repo has its own set of issues and pull requests.
The codebase may look a little scarier and the repo is bigger.
In addition, the commit history becomes a soup of commits from each package that is part of the monorepo, thus making it unsearchable!
It’s demo time! 🤓
Vscode integration
I suggest you to install the Nx vscode extension to speed up the development.
ReactJS app
Let’s create a monorepo workspace with Nx:
npx create-nx-workspace@latest --preset=react
Fill in the required informations in order to create an empty ReactJS app and wait until it finishes.
When it’s finished we will find our ReactJS app under apps/react-demo
, by default it also creates E2E tests in apps/react-demo-e2e
.
Please note that node_modules are not created in the project folder (apps/react-demo
), but in the root of the monorepo. This is because Nx manages all the node_modules with one single package.json file at the root level, so all the dependencies has to be specified there. This obviously comes with the downside of always having a single version of every dependency (#309).
React Native app
We should add React Native to our existing workspace:
yarn add @nrwl/react-native --dev
Then we can create a React Native application in our workspace, I’ll do it from Nx console in vscode, but the generated command will be:
yarn nx generate @nrwl/react-native:application react-native-demo --e2eTestRunner=none --no-install --unitTestRunner=none
Now we will also have the react-native-demo project in our workspace, we can find it in apps/react-native-demo
folder.
Shared business logic
To share business logic we can simply create a JS library that we will include in both out apps:
yarn nx generate @nrwl/js:library shared-business-logic --unitTestRunner=none
This is a library, so it won’t be created in the same folder as the apps, indeed we can find it in libs/shared-business-logic
.
Please note that every change to the shared-business-logic library will automatically trigger a refresh of the running apps which depend on it 🪄
To use the generated library in both our projects we can simply import the exported function sharedBusinessLogic
in both the apps.
Using shared business logic in ReactJS
import { sharedBusinessLogic } from '@demo/shared-business-logic';
...
export function App() {
console.log(sharedBusinessLogic());
return (
<StyledApp>
<NxWelcome title="react-demo" />
</StyledApp>
);
}
export default App;
Using shared business logic in React Native
import { sharedBusinessLogic } from '@demo/shared-business-logic';
...
export const App = () => {
const [whatsNextYCoord, setWhatsNextYCoord] = useState<number>(0);
const scrollViewRef = useRef<null | ScrollView>(null);
console.log(sharedBusinessLogic());
...
Done! 🎉
Demo source code
I don’t suggest looking into the source code, because it is mostly autogenerated by Nx, but if you want to take a look at what it generates, this is the repository with the Demo.
Conclusion 🤗
In conclusion, sharing business logic between mobile and web app is a good solution to the problem of having duplicate code in both apps. It’s easy to implement, and it can save you time by not having to write the same code twice. However, there are some drawbacks such as increased organization complexity which might make your application more difficult to maintain over time or impose restrictions on future development plans.