What is systemjs?
SystemJS is a dynamic module loader that can load ES modules, AMD, CommonJS, and global scripts in the browser and Node.js. It provides a way to load modules asynchronously and supports various module formats, making it a versatile tool for managing dependencies and module loading in JavaScript applications.
What are systemjs's main functionalities?
Loading ES Modules
SystemJS can dynamically import ES modules. The code sample demonstrates how to load an ES module asynchronously and handle the loaded module.
System.import('/path/to/module.js').then(function(module) {
console.log(module);
});
Loading CommonJS Modules
SystemJS can also load CommonJS modules. The code sample shows how to load a CommonJS module asynchronously.
System.import('/path/to/commonjs-module.js').then(function(module) {
console.log(module);
});
Loading AMD Modules
SystemJS supports loading AMD modules. The code sample demonstrates how to load an AMD module asynchronously.
System.import('/path/to/amd-module.js').then(function(module) {
console.log(module);
});
Loading Global Scripts
SystemJS can load global scripts that do not export any modules. The code sample shows how to load a global script asynchronously.
System.import('/path/to/global-script.js').then(function() {
console.log('Global script loaded');
});
Configuring SystemJS
SystemJS allows configuration for module loading. The code sample demonstrates how to configure the base URL, paths, and module mappings.
System.config({
baseURL: '/base/url',
paths: {
'npm:': 'https://unpkg.com/'
},
map: {
'jquery': 'npm:jquery@3.5.1/dist/jquery.js'
}
});
Other packages similar to systemjs
requirejs
RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, such as Rhino and Node. Compared to SystemJS, RequireJS primarily focuses on AMD modules and does not support as many module formats.
webpack
Webpack is a module bundler that takes modules with dependencies and generates static assets representing those modules. Unlike SystemJS, which is a dynamic module loader, Webpack bundles modules at build time, which can result in better performance for production applications.
browserify
Browserify allows you to use Node.js-style require() to organize your browser code and load modules. It transforms Node.js modules into a format that can be used in the browser. Compared to SystemJS, Browserify focuses on CommonJS modules and does not support as many module formats.
es-module-loader
ES Module Loader is a polyfill for the ES Module Loader specification. It provides a way to load ES modules in environments that do not natively support them. Compared to SystemJS, ES Module Loader is more focused on ES modules and does not support other module formats.
SystemJS
Configurable module loader enabling backwards compatibility workflows for ES modules in browsers. If you're interested in modern workflows for ES module compatible browsers only, see ES Module Shims.
Read the SystemJS 2.0 announcement post
For the previous release see the SystemJS 0.21.x branch
SystemJS is currently sponsored by Canopy Tax.
SystemJS provides two hookable base builds:
1. s.js minimal loader
The minimal 1.5KB s.js loader provides a workflow where code written for production workflows of native ES modules in browsers (like Rollup code-splitting builds), can be transpiled to the System.register module format to work in older browsers that don't supporting native modules, including IE11++.
Since the ES module semantics such as live bindings, circular references, contextual metadata, dynamic import and top-level await can all be fully supported this way, while supporting CSP and cross-origin support, this workflow can be relied upon as a polyfill-like path.
- Loads and resolves modules as URLs, throwing for bare specifier names (eg
import 'lodash'
) like the native module loader. - Loads System.register modules.
- Core hookable extensible loader supporting custom extensions.
2. system.js loader
The 3KB system.js loader loader builds on the s.js core and adds support for upcoming module specifications (currently import maps and WASM integration with module loading) as well as development and convenience features.
- Support for loading bare specifier names through import maps (formerly package maps, formerly map configuration), loaded via
<script type="system-importmap">
(requires a fetch
polyfill for eg IE11). - Includes the global loading extra for loading global scripts, useful for loading library dependencies traditionally loaded with script tags.
- Tracing hooks and registry deletion API for reloading workflows
- Supports loading WASM based on the
.wasm
file extension
The following pluggable extras are provided which can be dropped in with either the s.js or system.js loader:
- AMD loading support (through
Window.define
which is created). - Global loading support for loading global scripts and detecting the defined global as the default export. Useful for loading common library scripts from CDN like
System.import('//unpkg.com/lodash')
. (Already included in the system.js loader build). - Named exports convenience extension support for global and AMD module formats (
import { x } from './global.js'
instead of import G from './global.js'; G.x
) - Named register supports
System.register('name', ...)
named bundles which can then be imported as System.import('name')
(as well as AMD named define support) - Transform loader support, using fetch and eval, supporting a hookable
loader.transform
Since all loader features are hookable, custom extensions can be easily made following the same approach as the bundled extras. See the hooks documentation for more information.
For discussion, join the Gitter Room.
Installation
npm install systemjs
Documentation
Example Usage
Loading a System.register module
<script src="system.js"></script>
<script>
System.import('/js/main.js');
</script>
where main.js
is a module available in the System.register module format.
Bundling workflow
For an example of a bundling workflow, see the Rollup Code Splitting starter project - https://github.com/rollup/rollup-starter-code-splitting.
Import Maps
Say main.js
depends on loading 'lodash'
, then we can define an import map:
<script type="systemjs-importmap">
{
"imports": {
"lodash": "https://unpkg.com/lodash@4.17.10/lodash.js"
}
}
</script>
<script src="system.js"></script>
<script>
System.import('/js/main.js');
</script>
Browser transpilation
To load ES modules directly in older browsers with SystemJS we can install and use the Babel plugin:
<script src="system.js"></script>
<script src="extras/transform.js"></script>
<script src="plugin-babel/dist/babel-transform.js"></script>
<script>
System.import('/js/main.js');
</script>
Compatibility with Webpack
Code-splitting builds on top of native ES modules, like Rollup offers, are an alternative to the Webpack-style chunking approach - offering a way to utilize the native module loader for loading shared and dynamic chunks instead of using a custom registry and loader as Webpack bundles include. Scope-level optimizations can be performed on ES modules when they are combined, while ensuring no duplicate code is loaded through dynamic loading and code-sharing in the module registry, using the features of the native module loader and its dynamic runtime nature.
There is currently no support for SystemJS in Webpack. If building code using the System
global in Webpack, the following config is needed to avoid rewriting:
{
module: {
rules: [
{ parser: { system: false } }
]
}
}
Polyfills for Older Browsers
Promises
Both builds of SystemJS need Promises in the environment to work, which aren't supported in older browsers like IE11.
Promises can be conditionally polyfilled using, for example, Bluebird (generally the fastest Promise polyfill):
<script>
if (typeof Promise === 'undefined')
document.write('<script src="node_modules/bluebird/js/browser/bluebird.core.js"><\/script>');
</script>
Generally document.write
is not recommended when writing web applications, but for this use case
it works really well and will only apply in older browsers anyway.
Fetch
To support import maps in the system.js build, a fetch polyfill is need. The GitHub polyfill is recommended:
<script>
if (typeof fetch === 'undefined')
document.write('<script src="node_modules/whatwg-fetch/fetch.js"><\/script>');
</script>
Loader Extensions
This list can be extended to include third-party loader extensions. Feel free to post a PR to share your work.
How is SystemJS related to jspm.io?
SystemJS was initially developed as a universal module loader alongside jspm which provides a package manager and ES module CDN exploring native ES module workflows. SystemJS was the core loader enabling this experimentation of workflows from unbuilt development loading in browsers to production and CDN loading of ES modules.
SystemJS is now used as the legacy loader for backwards compatibility in older browsers for jspm.io. All npm packages are available for loading in SystemJS through https://system-dev.jspm.io/[packagename]
and https://system-unsafe-production.jspm.io/[packagename]
where they are transformed from CommonJS into the System module format with their package resolutions inlined for usage in all browsers. This CDN can be useful in sandboxes or dev workflows, but note it is not optimized for production loading.
Contributing to SystemJS
Project bug fixes and changes are welcome for discussion, provided the project footprint remains minimal.
To run the tests:
npm run build && npm run test
Changes
For the changelog, see CHANGELOG.md.
License
MIT