The content of this section is derived from the content of the following links and is subject to the CC BY 4.0 license.
The following contents can be assumed to be the result of modifications and deletions based on the original contents if not specifically stated.
Rspack supports code splitting, which allows splitting the code into other chunks. You have the full control about size and number of generated assets, which allow you to gain performance improvements in loading time.
Here we introduce a concept called Chunk, representing a resource that a browser needs to load.
Rspack use the import() syntax that conforms to the ECMAScript proposal for dynamic imports.
In index.js
, we dynamically import two modules through import()
, thereby separating into a new chunk.
Now we build this project, we get 3 chunks, src_bar_js.js
, src_foo_js.js
and main.js
, if you see them, you will find shared.js
exist in both src_bar_js.js
and src_foo_js.js
, we will remove duplicated modules in later chapters.
Refer to Module Methods - Dynamic import() for the detailed dynamic import API, as well as how to use dynamic expressions and magic comments in dynamic import.
Though shared.js
exist in 2 chunks, but it is executed only once, you don't have to worry about issue of multiple instance.
This is the simplest and most intuitive way to split the code. However, this approach requires us to manually configure the Rspack. Let's start by looking at how to split multiple Chunks from multiple entry points.
This will yield the following build result:
Similarly, if you examine them, you will find that they all include the repetitive shared.js
.
The code segmentation mentioned above is quite intuitive, but most modern browsers support concurrent network requests. If we divide each page of a SPA application into a single Chunk, and when users switch pages, they request a larger Chunk, this obviously does not make good use of the browser's ability to handle concurrent network requests. Therefore, we can break down the Chunk into smaller ones. When we need to request this Chunk, we change to request these smaller Chunks simultaneously, which will make the browser's requests more efficient.
Rspack defaults to splitting files in the node_modules
directory and duplicate modules, extracting these modules from their original Chunk into a separate new Chunk. So why does shared.js
still appear repeatedly in multiple Chunks in our example above? This is because the shared.js
in our example is very small in size. If a very small module is split into a separate Chunk for the browser to load, it might actually slow down the loading process.
We can configure the minimum split size to 0 to allow shared.js
to be extracted on its own.
When rebuild, you will find that shared.js
has been extracted separately, and there is an additional Chunk in the product that contains shared.js
.
We can specify certain modules to be forcibly grouped into a single Chunk, for example, the following configuration:
With the above configuration, all files that include the some-lib
directory in their path can be extracted into a single Chunk named lib
. If the modules in some-lib
are rarely changed, this Chunk will consistently hit the user's browser cache, thus a well-considered configuration like this can increase the cache hit rate.
However, separating some-lib
into an independent Chunk can also have downsides. Suppose a Chunk only depends on a very small file within some-lib
, but since all files of some-lib
are split into a single Chunk, this Chunk has to rely on the entire some-lib
Chunk, resulting in a larger load volume. Therefore, when using cacheGroups.{cacheGroup}.name, careful consideration is needed.
Here is an example show the effect of the name
configuration of cacheGroup.
Using these inline directives while declaring your imports allows Rspack to output “Resource Hint” which tells the browser that for:
An example of this is having a HomePage
component, which renders a LoginButton
component which then on demand loads a LoginModal
component after being clicked.
This will result in <link rel="prefetch" href="login-modal-chunk.js">
being appended in the head of the page, which will instruct the browser to prefetch in idle time the login-modal-chunk.js
file.
Rspack will add the prefetch hint once the parent chunk has been loaded.
Preload directive has a bunch of differences compared to prefetch:
An example of this can be having a Component
which always depends on a big library that should be in a separate chunk.
Let's imagine a component ChartComponent
which needs a huge ChartingLibrary
. It displays a LoadingIndicator
when rendered and instantly does an on demand import of ChartingLibrary
:
When a page which uses the ChartComponent
is requested, the charting-library-chunk is also requested via <link rel="preload">
. Assuming the page-chunk is smaller and finishes faster, the page will be displayed with a LoadingIndicator
, until the already requested charting-library-chunk
finishes. This will give a little load time boost since it only needs one round-trip instead of two. Especially in high-latency environments.
Using webpackPreload incorrectly can actually hurt performance, so be careful when using it.
Sometimes you need to have your own control over preload. For example, preload of any dynamic import can be done via async script. This can be useful in case of streaming server side rendering.
If the script loading will fail before Rspack starts loading of that script by itself (Rspack creates a script tag to load its code, if that script is not on a page), that catch handler won't start till chunkLoadTimeout is not passed. This behavior can be unexpected. But it's explainable — Rspack can not throw any error, cause Rspack doesn't know, that script failed. Rspack will add onerror handler to the script right after the error has happen.
To prevent such problem you can add your own onerror handler, which removes the script in case of any error:
In that case, errored script will be removed. Rspack will create its own script and any error will be processed without any timeouts.