Code-splitting in general requires apps to be structured a little differently yes. You basically just delay requiring something until you actually need it. So in the case of react-native you’d use the appraoch described in the performance docs and apply that directly to the CLJS setup you use.
In there example a require
is executed when a button is clicked which then initializes the component that is later used in render
.
didPress = () => {
if (VeryExpensive == null) {
VeryExpensive = require('./VeryExpensive').default;
}
this.setState(() => ({
needsExpensive: true,
}));
};
The same thing can now be done in shadow-cljs via a bit of extra config.
{:target :react-native
:init-fn demo.rn/init
:chunks {:foo demo.rn-foo/component}
:output-dir "app"}
Note the extra :chunks
config which will create a app/foo.js
in additional to the normal app/index.js
. So you :init-fn
will be executed normally on startup and you can dynamically (js/require "./foo.js")
in the code which will return whatever the qualified symbol refered to.
(ns demo.rn-foo)
(defn component [] ...)
So in the above example you’d get the component
fn returned by the js/require
. You can return anything here (eg. a map via (def component {:whatever true})
).
Code-splitting is kinda hard to describe in a general way since it is usually very specific to each app and there is no generic “best” approach that works for everything. The idea I guess for react-native would be to “delay” loading specific screens of an app until they are actually needed. I can’t say how much of a benefit this actually is since I only did the JS side of things and didn’t investigate the whole RN “RAM-bundle” further yet. But according to their docs this should work.
I wrote more about code-splitting in the browser here. You just use js/require
instead of the described shadow.lazy
stuff.