React Native does a lot with its project initialization using the following command:
1react-native init AwesomeProject
It creates a basic setup for the iOS and Android projects, as well as giving a simple structure how the code is organized. This is very nice for smaller projects, or when you just need to get into creating apps straight-away.
As soon as you work on a larger projects, you will need to:
- split up the project into multiple projects
- allow proper code sharing between the projects
This seem like a simple task for any dependency management tool, and indeed using npm, you can easily do this. The thing is, you also want to develop in all the projects in parallel. For this, you usually use:
1npm link
Unfortunately, the React Packager at the moment does not resolve symlinks properly and having this kind of setup is not easily possible. There is a Product Pain already for this, so give it a bit of up-vote please.
Developer experience in React Native is really awesome.
… so it was at upmost importance to have the same in any kind of setup we choose. Weather you work in a sub-project or a target-project, it should not matter. You change something and you want the refresh to work.
Solution
The solution we came is based on the following:
- Git Submodules for the core projects
- Custom configuration for React Packager delivered viarn-cli-config Using git submodules is straightforward. You create your sub-projects as any other project. In your top-most target project, where you want to use the sub-projects, you reference them as git submodules.
Lets go with an example. We have a main project named awesome-project; and a sub-project named awesome-components. To include awesome-components into awesome-project, in awesome-project you do:
1git submodule add <git-repo-awesome-components>2cd awesome-components3git fetch4git pull origin master
In case you have multiple projects, and you want to move them to one folder (example modules), than you can do this with:
1mkdir modules2git mv awesome-components modules/awesome-components
Next on the list is using awesome-components into awesome-projects. Many suggestions out there are just using something like the following in the main project:
1require (../../../modules/awesome-components/play.js);
To solve this, you can put a custom configuration in the main project, like the following:
1// rn-cli.config.js23'use strict';45var path = require('path');67var config = {8 getProjectRoots() {9 return getRoots();10 },1112 getAssetRoots() {13 return getRoots();14 },1516};1718function getRoots() {19 return [20 __dirname,21 path.resolve(__dirname, 'modules/awesome-components'),22 path.resolve(__dirname, 'modules/awesome-core')23 ];24}2526module.exports = config;
With this, you can have the previous require written like you usually do for any dependent library you use:
1require (awesome-components/play.js);
Conclusion
This setup was made with several considerations in mind:
- Larger code-base split up in multiple projects that share code.
- Larger development team that can work on multiple projects.
- Great developer experience, same as the one you have with the vanilla React Native setup.
While every non-trivial project can easily fall into this category, there are several drawbacks to this approach that are worth considering:
- Using git submodules will have an impact on your workflow. We believe that the default behavior of git in this kind of setup is pretty good and did not had any hurdles. Still, you need to understand how git is tracking the commits in relation to the pointers of the sub-modules.
- The relations and impact of the transitive dependencies still needs to be explored and checked. In our setups we sticked to having all the dependencies in the main (top-most) project.
Hope this setup will help you bring better structure to your React Native projects.