-
Notifications
You must be signed in to change notification settings - Fork 129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC 0702]: Autolinking local modules #702
[RFC 0702]: Autolinking local modules #702
Conversation
3b1b147
to
677e505
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really appreciate your time for drafting this one @szymonrybczak 👍 I've left some comments for you
## Detailed design | ||
|
||
To automate the process of creating native modules or views we need to implement a few things. | ||
First we need to introduce a new feature to the `create-react-native-library` package to create local modules. `create-react-native-library` will detect if the command has been run under React Native project if yes, it will create a local module under `local_modules` directory. CRNL will contain templates for creating native modules and views, also templates for turbo modules and fabric views. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: What's the difference from this approach from just using create-react-native-library
inside the packages/
folder and yarn add
-ing it?
Wouldn't it make it easier to open-source actually, as you're creating a proper NPM package?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other word: do we need this? What problem is this solving that CRNL isn't solving already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cortinico right now, the code generated by create-react-native-library
includes an example
folder which isn't necessary for local modules, additional dependencies in the package.json
, build scripts for publishing etc. that need to be maintained separately. the idea with local_modules
is that we remove the additional unnecessary stuff to give a smaller amount of stuff to maintain. It's harder to open source than a regular lib, but easier to mainatin.
yarn add
ing an repo like this also has other issues. it doesn't behave exactly like installing a package from npm
, it could result in duplicate dependencies etc. due to the additional node_modules
which could cause issues.
The other issue is that every time there's a change in the package, user will need to yarn add
, which is not good DX.
Yarn also caches packages by their version, so for every change, users will need to update the version number as well or get the cached package, which is another DX issue. yarnpkg/yarn#2165
## Alternatives | ||
|
||
- [react-native-coco-loco](https://github.com/jamonholmgren/react-native-colo-loco), it's a great solution - but it integrates with native code, proposed solution will autolink local modules and won't touch native code at all - which makes upgrades simpler and faster. | ||
- [Expo Local Modules](https://docs.expo.dev/modules/get-started/#creating-the-local-expo-module) Expo has a similar autolinking directive for modules that are using Expo Modules API. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you mentioned, this approach looks inspired from Local Expo Modules.
Can we get someone from Expo to chime in here and help design this solution? (example: the fact that the folder on Expo is called modules
and on your proposal is called local_modules
is an unnecessary misalignment, to name one thing).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wanted to clarify that I had no idea that about expo modules before we came up with the proposal. But yeah, we could align the naming if they behave similarly, e.g. expo modules would work with auto-linking in the CLI.
1. The new modules become part of the `android` and `ios` source code—which means upgrading the project to a newer React Native version is harder as it also needs to consider those changes, | ||
2. The module boilerplate is written manually, that's the place where users can make mistakes and it takes a lot of time to write one, | ||
3. The code for registering the modules is additional boilerplate which is not required for third party packages (because they're automatically linked), | ||
4. The workflow for creating new architecture modules without creating packages is not streamlined, | ||
5. It's challenging to open-source the local module, as it requires creating a dedicated library setup that adds extra friction to the process. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I may be missing something because I'm struggling to understand the scenarios this is supposed to address. I have some questions for each of your numbered points:
- How does having local native modules work around the fact that you need to deal with React Native upgrades? If your modules are written as Turbo/Native Modules, you still need to consider changes in React Native?
- If the generated modules don't have a
package.json
, what's the difference between this vs. putting the files directly in your project?
- If the generated modules don't have a
- I can see the benefit of having the modules automatically generated, but isn't this already resolved by TurboModule generation?
- On iOS/macOS, modules are statically linked when you define them. There is no registration boilerplate. On Android, we do need to register them manually. Is this what you're trying to solve?
- Is this true? Doesn't codegen address this? If codegen is missing anything, I think it makes more sense to address those gaps instead. @cortinico?
- I'm struggling to see how this is better. See comments on point 1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't codegen address this? If codegen is missing anything, I think it makes more sense to address those gaps instead. @cortinico?
Practically codegen can consume local modules already. You'll have to define at the app level where they're placed and they will be consumed, so I don't see any significant gaps.
I would refrain from extending codegen to search also into local_modules
as that will complicate the infra, and I would just re-use the infra that we already have (i.e. let the module pass through node_modules
or via the app project).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would refrain from extending codegen to search also into
local_modules
as that will complicate the infra, and I would just re-use the infra that we already have (i.e. let the module pass throughnode_modules
or via the app project).
Agreed. If codegen is already addressing these needs, I am not sure why having local_modules
is beneficial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does having local native modules work around the fact that you need to deal with React Native upgrades? If your modules are written as Turbo/Native Modules, you still need to consider changes in React Native?
It's not about upgrading the modules, it's about upgrading the app. If your custom native code is outside of android/ios folders, you can just recreate android/ios folders of your app as you don't need to account for other changes related to your custom native code and carefully review the diff.
I can see the benefit of having the modules automatically generated, but isn't this already resolved by TurboModule generation
Not sure what you mean here. Do you mean codegen? The point is about the initial boilerplate that we write manually before we start working on the module.
Is this true? Doesn't codegen address this? If codegen is missing anything, I think it makes more sense to address those gaps instead.
It's more about polishing the workflow. In this case, having same setup as a library means we can have the same workflow and any improvements would apply in both cases.
reactwg/react-native-new-architecture#142 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- The main point that local modules are solving is when it comes to upgrades we have less custom code to take into account, because the most common scenario is that users put modules code under
ios/
orandroid/
directories. - What I described in this point is not role of codegen. What we're trying to achieve with CRNL is that it will contain templates for all kinds of local modules, so we'll automate process of creating modules from scratch. So user will be able to create module with just one command, not as right now there's need to create all files manually (that's where people make mistakes).
- Yes, exactly. With dependencies logic, that we'll reuse for autolinking we don't need to integrate with code under
android
directory at all. - So right now this is doable, but it isn't documented anywhere. (Usage of Turbo Native Modules within existing iOS and Android apps reactwg/react-native-new-architecture#142 (comment)) To do so you need specify path to local modules in
react-native.config.js
underdependencies
field. And codegen will take into account these dependencies, because of this logic. What we would like to do is to CLI look underlocal_modules
directory and automatically under the hood link modules asdependencies
. But the only thing that we need to implement is to codegen look also underlocal_modules
directory, because if not we loose the whole point of autolinking modules (because then we would need to manually specify them underdependencies
field inreact-native.config.js
). I think it wouldn't complicate logic behind the codegen. I don't quite understand how would it work with "let the module pass throughnode_modules
or via the app project" 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for answering my questions folks. ❤️
You're talking about "the app", but it's not to clear to me whether you mean the user's app or the library's example app. If you mean the latter and all of this is to remove the need to keep an example app up-to-date, why is local modules better than just putting your modules directly in the project? I think you can still streamline this (e.g. with code generation) without introducing the concept of local modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but it's not to clear to me whether you mean the user's app or the library's example app
the local modules are for using in the user's app. there won't be a separate example app here as the user would be using the library in their app. the modifications to CRNL would consist of removing the example app and any other library specific stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
… why is local modules better than just putting your modules directly in the project? I think you can still streamline this (e.g. with code generation) without introducing the concept of local modules.
What about this? I think if CRNL can just output those files directly into your project, you've already solved a pain point. I don't see why the concept of local modules is necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
### Summary Currently, when we have local native modules and views, they become part of the `android` & `ios` source code, this makes upgrading the project to a newer React Native version harder as we also need to consider those changes. This change lets us create a local library which is not part of the android & ios folders, but a separate directory in the repo, making it self contained. It also adds a new `--no-example` flag to generate the project without example. More details in this RFC: react-native-community/discussions-and-proposals#702 ### How it works - If we detect a `package.json` in the current folder, we ask user whether they want to create a local library - If the project is a react-native project, we add entries to `package.json` based on the package manager to link the native library (which creates a symlink in `node_modules`) - If the project is not a react-native project, we don't modify package.json, but ask user to link based on the project setup - this is relevant for monorepo scenario ### Test plan - Create a new project with `npx react-native init` - Run `create-react-native-library` in the project to create a local library - Import the library in `App.tsx` and use the exported method to verify functionality - Install dependencies and pods, then run the app on Android & iOS to verify that it works https://github.com/callstack/react-native-builder-bob/assets/1174278/d1da73f7-8a57-4911-9200-07c937d3b940
Support for creating local library is now available in latest version of |
As @satya164 mentioned
After running command, user will need to rebuild app and local module is ready to use. To make it possible there's no need for changes in Core or CLI. So I think we can close this PR. 💡 One thing that I'm thinking of is to mention this technique in docs, so when it comes to creating modules users will now that CRNL has templates for that and with just one command they can create the module. cc. @kelset @cortinico |
That's amazing news 👍 |
This RFC proposes a new feature to React Native CLI where we can create a folder containing local native modules and views and have them linked automatically. Proposed solution will simplify the space of creating local native modules and views and using them later in the app.
Rendered RFC can be found here.