-
Notifications
You must be signed in to change notification settings - Fork 24k
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
Apennine Architecture - add support for multiple bundle on a single JSContext #25518
Conversation
* Add preloading of env and load bundle in preloaded env * rename BundleEnv
…ndleRegistryLoad` (#7)
Thank you for working on this. This is really massive. I unfortunately don't think it'll be possible to both review and land a change this large that affects many core pieces of React Native. I would suggest splitting this up into as many small pull requests as possible that can all be reviewed in isolation. |
@cpojer
Right now I have couple of ideas how to do that in mind:
|
ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoaderDelegate.java
Outdated
Show resolved
Hide resolved
|
||
mDevBundlesContainer = new DevBundlesContainer(bundleURL); | ||
// DOWNLOAD INITIAL BUNDLE | ||
downloadBundle(new DownloadListener() { |
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.
can the method here be renamed to downloadInitialBundle so that the comment can be removed?
ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java
Outdated
Show resolved
Hide resolved
@cpojer |
I think there is no agreement yet on the RN team whether we'll want to support this large change to React Native itself and whether now is a good time for this. cc @fkgozali |
NSString *const RCTFileBundleLoaderErrorDomain = @"RCTFileBundleLoaderErrorDomain"; | ||
static const int32_t JSNoBytecodeFileFormatVersion = -1; | ||
|
||
//TODO FIGURE HOW TO THROW ERRORS HERE |
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.
Does this comment need to be resolved before merging?
Please check out my comment on the RFC that goes into details on how we could move forward: react-native-community/discussions-and-proposals#127 (comment) Based on this, I will close this PR and hope we can move forward with smaller changes. |
Summary
This PR is a implementation of multi-bundle support in a single
JSContext
, which is described here - react-native-community/discussions-and-proposals#127It's a joint effort of me and @dratwas.
Target audience
The multi-bundle mode is targeted mainly at corporate/large companies, where smaller teams are responsible for each piece of functionality - a mini app. More info about motivation can be found in the RFC.
Smaller teams or developers creating small/medium sized apps, should stick to the single-bundle mode, which is what React Native and Metro support currently. Because of that, multi-bundle is a opt-in feature.
Backwards compatibility
The new architecture is fully compatible with Metro. The plan JS bundles as well as Indexed RAM bundle, File RAM Bundle and Delta Bundle are working as expected. Remote debugging in Chrome is working properly.
It's more difficult to account for 3rd party libraries, which are going to break, but it's likely that
react-native-code-push
will stop working and will require some work.JavaScript API
To allow to request new bundle from JS,
BundleRegistry
JS module is now available publicly. The additional bundles can request to be loaded either synchronously or asynchronously. Only the initial bundle is automatically loaded from the native side.New architecture
In order to add maintainable and scalable support for multi-bundle we had to modify the core of React Native's logic for loading and evaluating the JS bundles. We've laid a ground work for adding support to have other bundles running on different
JSContext
es and threads.Each bundle type has it's own C++ class:
BasicBundle
- plain JS bundle, where JS code is stored asJSBigString
IndexedRAMBundle
- single-file RAM bundle (CxxReact
)FileRAMBundle
- multi-file RAM bundle (ReactAndroid
)DeltaBundle
- delta bundle for development (CxxReact
)All of those bundles derive from abstract
Bundle
class inCxxReact
.Since the new bundles can requested on-demand, instead of taking a single bundle in
RCTCxxBridge
orCatalystInstance
it takes a loader, which has enough information to load initial bundle and additional bundles:RCTDevBundleLoader
- loader for bundles served from packager server (React
)RCTFileBundleLoader
- loader for bundles stored in filesystem (React
)AssetBundleLoader
- loader for bundles stored as assets (ReactAndroid
)FileBundleLoader
- loader for bundles stored in filesystem (ReactAndroid
)DeltaBundleLoader
- loader for bundles stored in aDeltaBundleClient
instance (ReactAndroid
)All loaders derive from abstract
BundleLoader
class inCxxReact
.The flow of logic can be described as:
RCTCxxBridge
/CatalystInstance
.Instance
->BundleRegistry
inCxxReact
.Instance::runApplication
(orInstance::runApplicationInRemoteDebugger
when debugging - previouslysetSourceURl
).BundleRegistry
.BundleRegistry
.Notable changes
NativeToJsBridge
is no longer a holder of RAM bundle registry. This responsibility was transferred toBundleRegistry
inmakeGetModuleLambda
.nativeRequire
implementation was transferred toBundleRegistry::makeGetModuleLambda
.bundleRegistryLoad
property in JS was added to allow to request bundles to be loaded either synchronously or asynchronously - checkBundleRegistry::makeLoadBundleLambda
.registerSegment
API was removed -BundleRegistry
could be exposed to user space as a replacement.jsQueue
(MessageQueueThread
) andNativeToJsBridge
are stored in aBundleExecutionEnvironment
struct alongside a pointer toinitialBundle
- this is part of the ground work to allow multipleJSContex
es (as well as multipleNativeToJsBridge
/MessageQueueThread
). Currently there's only 1BundleExecutionEnvironment
created and it's identified in the code asdefault
.Example of typical use-case
A example project can be found here: https://github.com/zamotany/react-native-apennine-example
Bundler support
Multi-bundle mode is now only supported in Haul by using Webpack's DLL functionality.
Source maps support
When running in single-bundle mode, the source maps as handled as they were before and working as expected.
When running in multi-bundle mode:
app0_5.js:10:5
- bundlers which want to support multi-bundle will have to account for that when creating source maps (Haul already does), so by matching the bundle name they can switching between appropriate Index Source Maps.Missing parts
BundleRegistry
JS API documentation - Add BundleRegistry docs react-native-website#1084Changelog
Test Plan
Since the changes were made to core of React Native's code, it's crucial to ensure the application can be run, not crash and display correct content. RNTester by itself can ensure that requirement.
As other functionalities, manual test were done to ensure that:
cc: @matthargett @joeblynch @grabbou