SystemJS builder provides comprehensive support for compiling all module formats into a single bundle.
It also offers the ability to create statically optimized modules that can run without needing SystemJS present.
Once a bundle has been created, it will be populated with a series of System.register('module-in-bundle', ...
declarations.
We include the bundle generated by SystemJS builder with a script tag after SystemJS, and before importing the module we want to import:
<script src="system.js"></script>
<script src="system-config.js"></script>
<script src="bundle.js"></script>
<script>
SystemJS.import('module-in-bundle');
</script>
When the bundle executes, it declares the bundle modules into the SystemJS loader registry. When importing module-from-bundle
,
it will then use the version defined by the bundle.
Alternatively, we could import the bundle itself via SystemJS.import
, but then need to nest the import statements for the code to work properly:
SystemJS.import('/bundle.js').then(function (m) {
// (the bundle itself is an empty module m)
return SystemJS.import('module-from-bundle');
})
For loading bundles of code on-demand for chunked loading use cases, instead of nesting the SystemJS.import
statements, we can use the bundles
configuration.
The bundles
configuration allows determining which modules to load from which bundle:
// the bundle at build/core.js contains these modules
SystemJS.config({
bundles: {
'build/core': ['jquery', 'app/app', 'app/dep', 'lib/third-party']
}
});
// when we load 'app/app' the bundle extension interrupts the loading process
// and ensures that build/core.js is loaded first
SystemJS.import('app/app');
// this way a request to any one of 'jquery', 'app/app', 'app/dep', 'lib/third-party'
// will delegate to the bundle and only a single request is made
A built file must contain the exact named defines or named System.register
statements for the modules
it contains. Mismatched names will result in separate requests still being made.
Typically we only want the bundles
config for lazy-loaded code.
An alternative to bundling into a single bundle is to leave files as separate for loading in production.
The issue with loading modules as separate files is that dependencies are downloaded as they are discovered, leading
to a load time of latency * module tree depth
.
The depcache extension allows specifying the dependencies of all modules upfront through configuration so that loads can happen in parallel.
SystemJS.config({
depCache: {
'moduleA': ['moduleB'], // moduleA depends on moduleB
'moduleB': ['./moduleC'] // moduleB depends on ./moduleC
}
});
// when we do this import, depCache knows we also need moduleB and moduleC,
// it then directly requests those modules as well as soon as we request moduleA
SystemJS.import('moduleA')
Over HTTP/2 this approach may be preferable as it allows files to be individually cached in the browser meaning bundle optimizations are no longer a concern.