Rspack supports tree shaking, a terminology widely used within the JavaScript ecosystem defined as the removal of unused code, commonly referred to as "dead code." Dead code arises when certain exports from a module are not used and they lack side effects, allowing such pieces to be safely deleted to reduce the final output size.
You can imagine your application as a tree. The source code and libraries you actually use represent the green, living leaves of the tree. Dead code represents the brown, dead leaves of the tree that are consumed by autumn. In order to get rid of the dead leaves, you have to shake the tree, causing them to fall.
Note that Rspack does not directly remove dead code but labels unused exports as potential "dead code". These labels can then be recognized and processed by subsequent compression tools. As such, if minimize features are disabled, no actual code removal will be observable.
Dead code refers to a piece of code that is no longer executed, typically due to refactoring, optimization, or logical errors. These codes may be remnants of previous versions or codes that will never be executed under certain conditions.
To effectively leverage tree shaking, you need to:
production
to enable related optimizations.
mode
defaults to production
.import
and export
).
modules
option to false
.When the mode is set to production
, Rspack enables a series of optimizations related to tree shaking, including:
Below are examples to illustrate how these configuration options function. For the sake of clarity, we will use pseudocode to demonstrate the effects of code removal.
Let's understand this mechanism better through an example, assuming src/main.js
as the project's entry point:
In this example, bar
from util.js
is unused. In production
mode, Rspack defaults to enabling the usedExports optimization, detecting which exports are actively used. Unused exports, like bar
, are safely removed. The final output would resemble:
In production
mode, Rspack also typically analyzes modules for the presence of side effects. If all exports from a module are unused and the module is devoid of side effects, then the entire module can be deleted. Let's modify the previous example a bit:
In this case, none of the exports from util.js
are used, and it’s analyzed as having no side effects, permitting the entire deletion of util.js
.
You may manually indicate whether a module retains side effects through package.json
or module.rules
. To to do so, you should enable optimization.sideEffects.
In package.json
, you can use true
or false
to mark whether all modules under the current package contain side effects.
The above package.json
indicates that all modules under this package are considered side-effect-free.
You can also use glob patterns or string matching to specify specific modules. Unmatched modules will automatically be treated as side-effect-free. Therefore, if manually marking side effects, you must ensure that all unmarked modules are truly free of side effects.
Above package.json
indicates that only ./src/main.js
and all .css
files are considered to have side effects, while all other modules are treated as side-effect-free.
Re-exports are common in development. However, a module might pull in numerous other modules while typically only a fraction of those are needed. Rspack optimizes this situation by ensuring that the referring party can access the actual exported modules directly. Consider this example involving re-exports:
Rspack defaults to enable providedExports, which can analyze all exports from a re-exporting module and identify their respective origins.
If src/re-exports.js
contains no side effects, Rspack can convert the import in src/main.js
from src/re-exports.js
directly into imports from src/value.js
, effectively:
This approach benefits by entirely ignoring the src/re-exports.js
module.
With an ability to analyze all re-exports in src/re-exports.js
, it is determined that foo
from src/value.js
is not used and will be removed in the final output.
In some cases, even though exports are accessed, they might not actually be used. For example:
In the scenario above, even though the log
function and the variable bar
depend on foo
, since neither is used, foo
can still be considered dead code and be deleted.
After enabling innerGraph optimization (enabled by default for production
mode), for complex cross-module situations, Rspack maintains the ability to track variable usage, thereby achieving precise code optimization.
In this context, because value
is eventually used, the foo
it depends on is retained.
Using the /*#__PURE__*/
annotation to tell Rspack that a function call is side-effect-free (pure) . It can be put in front of function calls to mark them as side-effect-free.
When the initial value in a variable declaration of an unused variable is considered as side-effect-free (pure), it is getting marked as dead code, not executed and dropped by the minimizer.