Skip to content

Commit 5ac0dbe

Browse files
committed
update
1 parent 16cd926 commit 5ac0dbe

File tree

8 files changed

+1609
-2
lines changed

8 files changed

+1609
-2
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# The Codegen CLI
2+
3+
Calling Gradle or manually calling a script might be hard to remember and it requires a lot of cerimony.
4+
5+
To simplify it, we created a CLI tool that can help you running those tasks: the **Codegen** cli.
6+
7+
```shell
8+
npx react-native codegen [--path path] [--platform string] [--outputPath path]
9+
```
10+
11+
This command runs [react-native-codegen](https://www.npmjs.com/package/react-native-codegen) for your project. The following options are available:
12+
13+
- `--path` - Path to `package.json`. The default path is the current working directory.
14+
- `--platform` - Target platform. Supported values: `android`, `ios`, `all`. The default value is `all`.
15+
- `--outputPath` - Output path. The default value is the value defined in `codegenConfig.outputDir`.
16+
17+
## Examples
18+
19+
- Read `package.json` from the current working directory, generate code based on its codegenConfig.
20+
21+
```shell
22+
npx react-native codegen
23+
```
24+
25+
- Read `package.json` from the current working directory, generate iOS code in the location defined in the codegenConfig.
26+
27+
```shell
28+
npx react-native codegen --platform ios
29+
```
30+
31+
- Read `package.json` from `third-party/some-library`, generate Android code in `third-party/some-library/android/generated`.
32+
33+
```shell
34+
npx react-native codegen \
35+
--path third-party/some-library \
36+
--platform android \
37+
--outputPath third-party/some-library/android/generated
38+
```
39+
40+
## Including Generated Code into Libraries
41+
42+
The **Codegen** CLI is a great tool for library developers. It can be used to peek at the generated code to see which interfaces you need to implement. Or you can generate the code if you want to ship it in your library.
43+
44+
This setup has several benefits:
45+
46+
- No need to rely on the app to run **Codegen** for you, the generated code is always there.
47+
- The implementation files are always consistent with the generated interfaces.
48+
- No need to include two sets of files to support both architectures on Android. You can only keep the New Architecture one, and it is guaranteed to be backwards compatible.
49+
- No need to worry about **Codegen** version mismatch between what is used by the app, and what was used during library development.
50+
- Since all native code is there, it is possible to ship the native part of the library as a prebuild.
51+
52+
To enable this setup:
53+
54+
- Add the `includesGeneratedCode` property into your library's `codegenConfig` field in the `package.json` file. Set its value to `true`.
55+
- Run **Codegen** locally with the codegen CLI.
56+
- Update your `package.json` to include the generated code.
57+
- Update your `podspec` to include the generated code.
58+
- Update your `build.Gradle` file to include the generated code.
59+
- Update `cmakeListsPath` in `react-native.config.js` so that Gradle doesn't look for CMakeLists file in the build directory but instead in your outputDir.
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# Create a Library for Your Module
2+
3+
React Native has a florid ecosystem of libraries to solve common problems. We collect React Native libraries in the [reactnative.directory](https://reactnative.directory) website, and this is a great resource to bookmark for every React Native developer.
4+
5+
Sometimes, you might be working on a module that is worth extracting in a separate library for code reuse. This can be a library that you want to reuse in all your apps, a library that you want to distribute to the ecosystem as an open source component, or even a library you'd like to sell.
6+
7+
In this guide, you'll learn:
8+
9+
- how to extract a module into a library
10+
- how to distribute the library using NPM
11+
12+
## Extract the Module into a Library
13+
14+
You can use the [`create-react-native-library`](https://callstack.github.io/react-native-builder-bob/create) tool to create a new library. This tool sets up a new library with all the boilerplate code that is needed: all the configuration files and all files required by the various platforms. It also comes with a nice interactive menu to guide you through the creation of the library.
15+
16+
To extract a module into a separate library, you can follow these steps:
17+
18+
1. Create the new library
19+
2. Move the code from the App to the Library
20+
3. Update the code to reflect the new structure
21+
4. Publish it.
22+
23+
### 1. Create a Library
24+
25+
1. Start the creation process by running the command:
26+
27+
```sh
28+
npx create-react-native-library@latest <Name of Your Library>
29+
```
30+
31+
2. Add a name for your module. It must be a valid npm name, so it should be all lowercase. You can use `-` to separate words.
32+
3. Add a description for the package.
33+
4. Continue filling the form until you reach the question _"What type of library do you want to develop?"_
34+
![What type of Library](/docs/assets/what-library.png)
35+
5. For the sake of this guide, select the _Turbo module_ option. Notice that you can create libraries for both New Architecture and Legacy Architecture.
36+
6. Then, you can choose whether you want a library that access the platform (Kotlin & Objective-C) or a sahred C++ library (C++ for Android and iOS).
37+
7. Finally, select the `Test App` as last option. This option creates the library with a separate app already configured within the library folder.
38+
39+
Once the interactive prompt is done, the tool creates a folder whose structure looks like this in Visual Studio Code:
40+
41+
![C++VisualStudio](/docs/assets/c++visualstudio code)
42+
43+
Feel free to explore the code that has been created for you. However, the most important parts:
44+
45+
- The `android` folder: this is where the Android code lives
46+
- The `cpp` folder: this is where we the c++ code lives
47+
- The `ios` folder: this is where we the iOS code lives
48+
- The `src` forder: this is where the JS code lives.
49+
50+
The `package.json` is already configured with all the information that we provided to the `create-react-native-library` tool, including the name and the description of the package. Notice that the `package.json` is also already configured to run codegen.
51+
52+
```json
53+
"codegenConfig": {
54+
"name": "RN<your module name>Spec",
55+
"type": "all",
56+
"jsSrcsDir": "src",
57+
"outputDir": {
58+
"ios": "ios/generated",
59+
"android": "android/generated"
60+
},
61+
"android": {
62+
"javaPackageName": "com.<name-of-the-module>"
63+
}
64+
},
65+
```
66+
67+
Finally the library contains already all the infrastruction to let the library be linked with iOS and Android.
68+
69+
### 2. Copy the Code over from Your App
70+
71+
The rest of the guide assumes that you have a local Turbo Native Module in your app, created following the guidelines shown in the other guides in the website: platform specific Turbo Native Modules, or [cross-platform Turbo Native Modules](./pure-cxx-modules). But it works also for Components and legacy architecture modules and components. You'll have to adapt the files you need to copy and update.
72+
73+
<!-- TODO: add links for Turbo Native Modules -->
74+
75+
1. **[Not required for legacy architecture modules and components]** Move the code you have in the `specs` folder in your app into the `src` folder created by the `create-react-native-library` folder.
76+
2. Update the `index.ts` file to properly export the Turbo Native Module spec so that it is accessible from the library. For example:
77+
78+
```ts
79+
import NativeSampleModule from './NativeSampleModule';
80+
81+
export default NativeSampleModule;
82+
```
83+
84+
3. Copy the native module over:
85+
86+
- Replace the code in the `android/src/main/java/com/<name-of-the-module>` with the code you wrote in the app for your native module, if any.
87+
- Replace the code in the `ios` folder with the code you wrote in your app for your native module, if any.
88+
- Replace the code in the `cpp` folder with the code you wrote in your app for your native module, if any.
89+
90+
4. **[Not required for legacy architecture modules and components]** Update all the references from the previous spec name to the new spec name, the one that is defined in the `codegenConfig` field of the library's `package.json`. For example, if in the app `package.json` you set `AppSpecs` as `codegenConfig.name` and in the library it is called `RNNativeSampleModuleSpec`, you have to replace every occurrence of `AppSpecs` with `RNNativeSampleModuleSpec`.
91+
92+
That's it! You have moved all the required code out of your app and in a separate library.
93+
94+
## Testing your Library
95+
96+
The `create-react-native-library` comes with an useful example application that is already configured to work properly with the library. This is a great way to test it!
97+
98+
If you look at the `example` folder, you can find the same structure of a new React Native application that you can create from the [`react-native-community/template`](https://github.com/react-native-community/template).
99+
100+
To test your library:
101+
102+
1. Navigate to the `example` folder.
103+
2. Run `yarn install` to install all the dependencies.
104+
3. For iOS only, you need to install CocoaPods: `cd ios && pod install`.
105+
4. Build and run Android with `yarn android` from the `example` folder.
106+
5. Build and run iOS with `yarn ios` from the `example` folder.
107+
108+
## Use your library as a Local Module.
109+
110+
There are some scenario where you might want to reuse your library as a local module for your applications, without publishing it to NPM.
111+
112+
In this case, you might end up in a scenario where you have your library sitting as a sibling of your apps.
113+
114+
```shell
115+
Development
116+
├── App
117+
└── Library
118+
```
119+
120+
You can use the library created with `create-react-native-library` also in this case.
121+
122+
1. add you library to your app by navigating into the `App` folder and running `yarn add ../Library`.
123+
2. For iOS only, navigate in the `App/ios` folder and run `bundle exec pod install` to install your dependencies.
124+
3. Update the `App.tsx` code to import the code in your library. For example:
125+
126+
```tsx
127+
import NativeSampleModule from '../Library/src/index';
128+
```
129+
130+
If you run your app right now, Metro would not find the JS files that it needs to serve to the app. That's because metro will be running starting from the `App` folder and it would not have access to the JS files located in the `Library` folder. To fix this, let's update the `metro.config.js` file as it follows
131+
132+
```diff
133+
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
134+
135+
/**
136+
* Metro configuration
137+
* https://reactnative.dev/docs/metro
138+
*
139+
* @type {import('metro-config').MetroConfig}
140+
*/
141+
+ const path = require('path');
142+
143+
- const config = {}
144+
+ const config = {
145+
+ // Make Metro able to resolve required external dependencies
146+
+ watchFolders: [
147+
+ path.resolve(__dirname, '../Library'),
148+
+ ],
149+
+ resolver: {
150+
+ extraNodeModules: {
151+
+ 'react-native': path.resolve(__dirname, 'node_modules/react-native'),
152+
+ },
153+
+ },
154+
+};
155+
156+
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
157+
```
158+
159+
The `watchFolders` configs tells Metro to watch for files and changes in some additional paths, in this case to the `../Library` path, which contains the `src/index` file you need.
160+
The `resolver`property is required to feed to the library the React Native code used by the app. The library might refer and import code from React Native: without the additional resolver, the imports in the library will fail.
161+
162+
At this point, you can build and run your app as usual:
163+
164+
- Build and run Android with `yarn android` from the `example` folder.
165+
- Build and run iOS with `yarn ios` from the `example` folder.
166+
167+
## Publish the Library on NPM.
168+
169+
The setup to publish everything on NPM is already in place, thanks to `create-react-native-library`.
170+
171+
1. Install the dependencies in your module `yarn install`.
172+
2. Build the library running `yarn prepare`.
173+
3. Release it with `yarn release`.
174+
175+
After a while, you'll find your library on NPM. To verify that, run:
176+
177+
```bash
178+
npm view <package.name>
179+
```
180+
181+
where `package.name` is the `name` you set up in the `package.json` file during the initialization of the library.
182+
183+
Now, you can install the library in your application by running:
184+
185+
```bash
186+
yarn add <package.name>
187+
```
188+
189+
:::note
190+
For iOS only, whenever you install a new module with some native code, you have to reinstall CocoaPods, by running `bundle exec pod install` (recommended) or `pod install` if you are not using Ruby's Bundler (not recommended).
191+
:::
192+
193+
Congratulations! You published your first React Native library.

0 commit comments

Comments
 (0)