The specific implementation of Code Splitting in your application can be different and should account for your project's specific needs, requirements and limitations.
In general, we can identify 3 main categories of implementation. All of those approaches are based on the same underlying mechanism: Re.Pack's ChunkManager API
and the native module for it.
Because Code Splitting support is based on the native module, you need to be able to compile the native code in your project, meaning you cannot use it with Expo.
It might be possible to use it in an ejected Expo app, but that scenario is not officially supported.
Use Glossary of terms to better understand the content of this documentation.
On a high-level, all functionalities that enable to use Webpack's Code Splitting, are powered by
Re.Pack's ChunkManager
.
This APIs consists of the JavaScript part and the native part.
The ChunkManager
has function which allows to:
loadChunk
preloadChunk
resolveChunk
invalidateChunks
In order to provide this functionalities ChunkManager
has to be configured to be able to resolve remote chunks/scripts/containers:
If the storage
is provided, the returned url
from resolveRemoteChunk
will be used for
cache management. You can read more about it in Caching and Versioning.
Despite the name, ChunkManager
is also used when
loading scripts and containers from Module Federation.
Under the hood, the process could be summarized as follows:
ChunkManager.loadChunk(...)
gets called, either:
import(...)
function handled by Webpack, when using Async chunks approachChunkManager.loadChunk(...)
is called chunkId
and parentChunkId
arguments, which are either provided by:
webpackChunkName
ChunkManager.loadChunk(...)
resolves the chunk location using ChunkManager.resolveChunk(...)
.forceRemoteChunkResolution
is set to true
.resolveRemoteChunk
and compares the
returned url
value with the one stored in storage
(if provided):
storage
was not provided,
or the chunk was never downloaded before: the native module will download a chunk and execute
itPromise
returned by ChunkManager.loadChunk(...)
gets
resolved.ChunkManager.preloadChunk(...)
follows
the same behavior except for #5, where it downloads the file but doesn't execute it.
There are generally 3 approaches to Code Splitting with Webpack and Re.Pack. Keep in mind that the actual code you will have to create might be slightly different, depending on your project's requirements, needs and limitations.
Those approaches should be used as a base for your Code Splitting implementation.
It's recommended to read Generic usage first, to understand it on a high-level and get the necessary context.
Async chunks (or asynchronous chunks) are the easiest Code Splitting approach. They are usually
created by using dynamic import(...)
function, which makes them extremely easy to introduce it
into the codebase.
The async chunks are created alongside the main bundle as part of a single Webpack compilation, making it a great choice for a modular applications where all the code is developed in-house.
The usage of async chunks essentially boils down to calling import(...)
in your code, for example:
Async chunks created by dynamic import(...)
function can be nicely integrated using React.lazy
and React.Suspense
:
For each file in the dynamic import(...)
function a new chunk will be created - those chunks will
be a remote chunks by default and they will be copied to <projectRoot>/build/<platform>/remote
by
default. All chunks in this directory should be uploaded to the remote server or a CDN.
You can change this directory using
remoteChunksOutput
in OutputPlugin
configuration.
To learn more or use async chunks in your project, check out our dedicated Async chunks guide.
To see import(...)
, React.lazy
and React.Suspense
in action, check out
Re.Pack's TesterApp
.
For production, don't forget to configure Re.Pack's ChunkManager
.
This approach allows to execute arbitrary code in your React Native application.
It's a similar concept as adding a new <script>
element to a Web page.
Those scripts can be written in-house or externally, bundled using Webpack or a different bundler. This also means that scripts can be created as part of separate Webpack compilations, or separate build pipelines, from separate codebases and repositories.
Scripts should only be used by advanced users with deep Webpack knowledge and experience.
Scripts give a lot of flexibility but it also means the support for them is only limited the
ChunkManager
API. It's not possible for Re.Pack's
contributors to support all potential setups using this approach.
Beware, with dynamic scripts there's no dependency sharing by default. If you want your scripts to reuse existing dependencies from the main bundle, it's up to you to figure out how to do it. A good starting point would be:
Loading a script is as simple as running a single function:
And configuring the ChunkManager
to resolve your
scripts:
The Module Federation approach allows to create micro frontends, which are built using separate/dedicated Webpack compilations from the same (monorepo) or different codebases.
Each micro frontend can be developed in isolation as a standalone application, but in production all of them will work together and act as a single entity.
To get more information and better understand what Module Federation is, use the following resources:
Given the nature of React Native environment, which needs to be initialized at the very beginning to
be usable, Module Federation gets limited to only a few scenarios. The best one showcasing how it
could work in React Native is
dynamic-system-host
.
The support for Module Federation in Re.Pack is still work in progress and not official yet.
Initial investigation yielded promising results. Feel free to experiment with it using this example: https://github.com/zamotany/module-federation-repack.