React-native: How to separate js bundle

Created on 19 Jan 2016  Â·  41Comments  Â·  Source: facebook/react-native

How to separate js bundle to frameworkBundle and appBundle?

js bundle is more 500k+, but business code is less then 10%

Stale

Most helpful comment

Hi @martinbigio, @corbt,

Our guys have been develop APPs with RN Integration for a long time. And we think bundle-splitting is also usefull in these scenarios (maybe not limited to Integration).

  • Decrease initial time (Run base codes previously)
    If we could split some initial and definition codes to a _base.jsbundle_ and run it in JSContext previously before users really enter React Native partition, it can decrease user's waiting time .
  • Update partially
    Just like @Creemli said. If we just use a lock version RN(or update infrequently) , the most of changes and updates is about our business codes. We can also separate some framework code (i.e. React, RN Components, APIs, and even with some other framework) into a base bundle, but business codes in business bundle. So we can fetch business bundle standalone from network and get smaller size with download to hot update. Even without diff it's not too bad. I mean, maybe it's easier to implement than integrate a diff algorithm to the entire work flow.
  • Share common modules between multiple bundle
    If we had the _base.jsbundle_ like the above mentioned, we also can make multiple bundle share it as a common library (it's Just like DllPlugin usecase in webpack). Suppose we have two ReactRootView in our App, currently we should bundle out two _jsbundle_ files both independent and overall with base codes, it includes many duplicated.

Let me generalize my opinion through this picture:

(In order to save space, I omit the --platform, .ios, .android here)

image

This simple way seems like the DllPlugin in webpack:

  1. Compile-time

Build _base.jsbundle_. Meanwhile records it's dependecies list and save it, for example, named by _base.manifest.json_ (output to --manifest-output by cli).

Build _index1.jsbundle_ with the _base.manifest.json_ passed through --manifest-file. When resolve modules, use their id from _base.manifest.json_ and skip their definition if they has recorded in the manifest. So a clear business bundle has done!

Build antoher business bundle like the above (We can set a --id-prefix for module id to prevent override).

  1. Run-time

Run _base.jsbundle_ in JSContext at a good time (e.g. Native App launch done, enter to a parent Activity/Controller ).

Run _index1.jsbundle_ when user click/open and will enter to this React Native partition.

Run _index2.jsbundle_ or other when user will enter to another React Native partition.

Update business bundle from CDN if needed.

How do you think ? 😄

All 41 comments

@satya164

Hey Richard-Cao, thanks for reporting this issue!

React Native, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.

  • If you don't know how to do something or something is not working as you expect but not sure it's a bug, please ask on StackOverflow with the tag react-native or for more real time interactions, ask on Discord in the #react-native channel.
  • If this is a feature request or a bug that you would like to be fixed, please report it on Product Pains. It has a ranking feature that lets us focus on the most important issues the community is experiencing.
  • We welcome clear issues and PRs that are ready for in-depth discussion. Please provide screenshots where appropriate and always mention the version of React Native you're using. Thank you for your contributions!

Wow, I just wanna fix this issue, and have tried https://github.com/mjohnston/react-native-webpack-server/ but failed.

Also I tried to get a dev version bundle and copy the framework code as framework.jsbundle, but when I package the business code, I cannot analysis the correct dependencies.

Looking forward this solutions~~~~

@Richard-Cao IOS also have this issue~~

@Creemli Looking forward……

@Richard-Cao Help to remove the [Android] tag and then more people can search this issue.

@Creemli ok

What's the purpose of splitting the bundle? Is it just to make incremental app updates lighter weight, or is there some runtime goal you're trying to accomplish?

both @corbt

To help me understand the scope of this, what are the use cases for this beyond just making lighter-weight app updates (which I get)?

@corbt Yeah, this can make user download less code when updating.
And if we can separate them, we maybe not have to bundle the whole codes, we can combine any business project with the framework code, it's lighter, I think.

I think @martinbigio was looking into this.

Yeah, we were looking into this mostly to help on TTI but decided to pursue another approach, namely unbundling. To make code downloading faster it's not actually necessary to have multiple bundles but to use a "more clever" protocol (i.e.: one that could send diffs only).

@martinbigio cool

If the main use case for this is just to have smaller updates, then I don't think bundle-splitting is the best solution. There should just be some library that manages updating the JS bundle file using versioned diffs. Such a solution would perform strictly better than bundle-splitting in the size of the updates it would need to send, and would also require less user intervention (in deciding where to split the bundle) to get right.

This would probably make more sense in something like Code Push than in React Native core.

Another possible use is to lazy load parts of a (bigger) app at runtime to reduce startup time. Or is that unlikely to make a difference?

I can give an example of what is being talked about here.

I have a tabbed UI app that already has a bunch of native code already written (iOS and Android). React Native tabs exist side by side with other webview and native tabs. For this scenario, I am having to load all of the app code (core + tab 1 + tab 2 + tab 3) for each tab. Splitting the bundle would mean that:

  • the app kicks off tabs faster (TTI?)
  • some functionality that is rarely used can be directly loaded from a server without having to be pre-cached all the time
  • updating a tab doesn't mean I have to send few megs down the network each time (I understand some diffing protocol was suggested up in the thread)

Also, what is unbundling?

ref #570

any solution?

any updates?

any progress?

looking forward to updates

Looking forward...and...what is unbundling?

@Creemli moles-packer only resolve the propblem separate js bundle, but how to load them in native module?

Hi @martinbigio, @corbt,

Our guys have been develop APPs with RN Integration for a long time. And we think bundle-splitting is also usefull in these scenarios (maybe not limited to Integration).

  • Decrease initial time (Run base codes previously)
    If we could split some initial and definition codes to a _base.jsbundle_ and run it in JSContext previously before users really enter React Native partition, it can decrease user's waiting time .
  • Update partially
    Just like @Creemli said. If we just use a lock version RN(or update infrequently) , the most of changes and updates is about our business codes. We can also separate some framework code (i.e. React, RN Components, APIs, and even with some other framework) into a base bundle, but business codes in business bundle. So we can fetch business bundle standalone from network and get smaller size with download to hot update. Even without diff it's not too bad. I mean, maybe it's easier to implement than integrate a diff algorithm to the entire work flow.
  • Share common modules between multiple bundle
    If we had the _base.jsbundle_ like the above mentioned, we also can make multiple bundle share it as a common library (it's Just like DllPlugin usecase in webpack). Suppose we have two ReactRootView in our App, currently we should bundle out two _jsbundle_ files both independent and overall with base codes, it includes many duplicated.

Let me generalize my opinion through this picture:

(In order to save space, I omit the --platform, .ios, .android here)

image

This simple way seems like the DllPlugin in webpack:

  1. Compile-time

Build _base.jsbundle_. Meanwhile records it's dependecies list and save it, for example, named by _base.manifest.json_ (output to --manifest-output by cli).

Build _index1.jsbundle_ with the _base.manifest.json_ passed through --manifest-file. When resolve modules, use their id from _base.manifest.json_ and skip their definition if they has recorded in the manifest. So a clear business bundle has done!

Build antoher business bundle like the above (We can set a --id-prefix for module id to prevent override).

  1. Run-time

Run _base.jsbundle_ in JSContext at a good time (e.g. Native App launch done, enter to a parent Activity/Controller ).

Run _index1.jsbundle_ when user click/open and will enter to this React Native partition.

Run _index2.jsbundle_ or other when user will enter to another React Native partition.

Update business bundle from CDN if needed.

How do you think ? 😄

android can try unbundle. this will separate mian.jsbundle into pieces of js files。

code like:
react-native unbundle --platform android --dev false --entry-file index.ios.js --bundle-output main.jsbundle

@njafei unbundle is not a good design, too many small files in output bundles.
it's very easy to split main.jsbundle to base.bundle.js and business.bundle.js, but you need modify the native code for RN to load different parts.

@mc-zone Amazing!

@jimzhao2012 I don't is a good idea to modify RN code. Mybe could eval business.bundle.js at base.bundle.js?

I hava package react-native code using webpack,https://github.com/yoution/rn-pack ;also support hot load; and split code using commonChunk plugin,also can fix module id in chunk; but I do not know how to load the splited bundle

We are trying to load base bundle & business bundle in IOS, Android. I will update this when succeed using in production.

@jimzhao2012 is there any resource to look deeper into it?
Also, how could we use and pack with unbundle? I can produce the unbundle files, but I don't know yet how to install and run the unbundle result and I don't find many resources on how to do it.

For those who wants to try out unbundle, there's a PR documenting it:
https://github.com/facebook/react-native/pull/15317/files

I'm working on an existing app rewrite, to separate js bundles and hot reload are two important feature for me to investigate, reasons are:

  1. We are running agile approach, so would like delivery our artifact for each sprint, but deliver through app store/google play too often definitely is not good for commercial app. So we would like to deliver major version by store, minor version by hot deploy.
  2. splitting bundle is because inside the app, there are different modules developed under different project, and some function is not used quite often, for example help & service. to have separate bundle will reduce the dependency and decrease project risk, since we can deliver and replace modules separately

Beyond that, we are also interested in bundle encryption/decryption, and file patching, which makes it more useful for commercial app.

+1 mark

Also that can speed up ci/server-side builds. Most of builds has same versions of libs, only code of app changes. We can --reset-cache for app bundle only.

For example: we have project with 1200 npm packages. android ci build takes about 3m, ios 5. 80% of build time takes building of bunde.js

Also we can bundle it with two package processes to speed up.

Would this be the equivalent to webpack DDL plugin? I made the following question in stackoverflow about the unbundle speed for rebuilds and I am interested in finding a guide to follow the same strategy for react-native.

Maybe it won't be possible for code-push updates or faster app initialization, but I am interested in improving the DX.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. If you think this issue should definitely remain open, please let us know why. Thank you for your contributions.

I never saw a resolution of this issue. it's a very important question and a valuable use-case. unbundling is not a solution and not the same thing as splitting the framework from app. is anyone working on this?

Was anybody able to use unbundling in combination with CodePush?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jlongster picture jlongster  Â·  3Comments

axelg12 picture axelg12  Â·  3Comments

aniss picture aniss  Â·  3Comments

anchetaWern picture anchetaWern  Â·  3Comments

arunabha picture arunabha  Â·  3Comments