Optimizing React Native Bundle Size with Dynamic Loading

The article proposes reducing React Native app bundle size by generating separate base and business JS bundles, then dynamically loading the latter at runtime via the bridge’s enqueueApplicationScript method and a custom ReactView, detailing bundler parameter tweaks, module filtering, and bridge delegate customization.

Tencent Music Tech Team
Tencent Music Tech Team
Tencent Music Tech Team
Optimizing React Native Bundle Size with Dynamic Loading

For many developers using React Native, a common challenge arises when the application's functionality expands, causing the generated JS bundle file to grow significantly. This becomes particularly problematic when deploying the app internally or updating the bundle via HTTP requests. To address this, we propose a solution that involves splitting the bundle and dynamically loading modules.

Our approach allows us to package the base files internally while requesting the business bundle separately. After initializing React Native, any new business modules can be loaded using the bridge's enqueueApplicationScript method to inject the code into the JavaScript context and then run the application module.

Here's a breakdown of the implementation details:

JS Bundle Generation

During finalization, the generated bundle inserts execution code based on parameters, allowing us to obtain the final bundle file.

2. Splitting JS Bundle

By understanding this process, we can extend the existing setup. When dependencies are obtained (onResolutionResponse), we can filter based on parameters to include only base modules or exclude them, generating the required files.

<code style="padding: 14px; border: 1px solid rgb(0, 0, 0); font-size: 14px; max-width: initial; display: block; color: rgb(248, 248, 242); font-family: Consolas, Monaco, monospace">/<span style="color: rgb(174, 129, 255)">/react-native/packager</span><span style="color: rgb(174, 129, 255)">/react-packager</span><span style="color: rgb(174, 129, 255)">/src</span><span style="color: rgb(174, 129, 255)">/Bundler/index</span>.js <span style="line-height: 18.2px">onResolutionResponse</span><br/><span style="color: rgb(249, 38, 114)">if</span> (withoutSource) {<br/>    response.dependencies = response.dependencies.filter(<span><span style="color: rgb(249, 38, 114)">module</span> =></span><br/>        !~<span style="color: rgb(249, 38, 114)">module</span>.path.indexOf(<span style="color: rgb(230, 219, 116)">'react-native'</span>)<br/>    );<br/>  }<span style="color: rgb(249, 38, 114)">else</span> <span style="color: rgb(249, 38, 114)">if</span> (sourceOnly) {<br/>    response.dependencies = moduleSystemDeps.concat(response.dependencies.filter(<span><span style="color: rgb(249, 38, 114)">module</span> =></span><br/>        ~<span style="color: rgb(249, 38, 114)">module</span>.path.indexOf(<span style="color: rgb(230, 219, 116)">'react-native'</span>)<br/>    ));<br/>  }</code>

In the server, we need to pass the corresponding parameters to the Bundler. This should also be reflected in the local-cli/bundle command by adding withoutSource and sourceOnly parameters.

In actual business scenarios, we can extend the filtering logic as needed.

3. React Native File Loading

After splitting the files, we can use a custom ReactView to load the bundle. This involves extending RCTBridgeDelegate to customize the loadSourceForBridge method.

<code style="padding: 14px; border: 1px solid rgb(0, 0, 0); font-size: 14px; max-width: initial; display: block; color: rgb(248, 248, 242); font-family: Consolas, Monaco, monospace"><span style="color: rgb(117, 113, 94)">//</span><span style="color: rgb(117, 113, 94)">//  ReactView.h<br/></span><span>#import <span><UIKit/UIKit.h><br/></span></span>@<span><span style="color: rgb(249, 38, 114)">interface</span> <span>ReactView</span> : <span>UIView<br/></span></span>- (instancetype)initWithFrame:(<span style="color: rgb(230, 219, 116)">CGRect</span>)frame module:(<span style="color: rgb(230, 219, 116)">NSString</span>*)module;<br/>@<span style="color: rgb(249, 38, 114)">end</span><br/></code>
<code style="padding: 14px; border: 1px solid rgb(0, 0, 0); font-size: 14px; max-width: initial; display: block; color: rgb(248, 248, 242); font-family: Consolas, Monaco, monospace"><span style="color: rgb(117, 113, 94)">//  ReactView.m<br/></span><span>#import <span></span></span></code>
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Tencent Music Tech Team
Written by

Tencent Music Tech Team

Public account of Tencent Music's development team, focusing on technology sharing and communication.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.