In this post we will go over the current state of ES6 modularity, by learning how to use the Jspm package manager and its associated SystemJs module loader (the sample code is available here). We will go through the following topics:
- Using ES6 modules today
- The Jspm package manager and how to use it today
- creating a ready to use bundle with Jspm
- The SystemJs module loader
- Jspm vs Bower
- Jspm vs npm
Using ES6 Modules Today
- a single command to install the library
- one single line of code to import the library and use it
Imagine a world where you could install a library with a command like this:
jspm install jquery
And then import the library with a single line of code, and just start using it:
var $ = require('jquery'); $('body').append("I've imported jQuery!");
It turns out that this is actually possible today with Jspm and its associated SystemJs module loader, without any further tooling needed.
Note that the import above can also be done in the ES6 syntax if using a transpiler like Babel:
import $ from 'jquery';
We will see how all this works, and how its really easy to use.
- it encourages the development of small isolated modules with clear interfaces, as opposed to large chunks of monolithic code
- it helps with testability, as modules can be replaced at runtime with mocks that implement the same interface
- it improves code maintainability, as smaller and well isolated modules are easier to understand
Fundamental Problems That Jspm Solves
When projects get to a certain size, they will have to deal sooner or later with the 'dependency hell' problem. This happens when two different versions of the same library are needed at the same time.
Another problem related to dependency management is making sure we always have a valid combination of library versions, meaning that if we require a library that itself has a dependency, that transitive dependency should be downloaded and included transparently for us.
All these problems are handled transparently by Jspm: it allows multiple versions of the same package and it even supports circular dependencies.
The Jspm Package Manager in Action
As we mentioned, in order to install a library we only need one command. Libraries can be installed from multiple sources, for example from github or npm. Let's install a couple of libraries:
jspm install npm:timezone-js jspm install github:pablojim/highcharts-ng
The installation command takes care of downloading the whole dependency tree, and copy it into the file system under the form of a versioned flat tree that looks like this:
firstname.lastname@example.org email@example.com firstname.lastname@example.org
jspm bundle-sfx --minify src/main bundle.min.js
This command creates a self-executing and minified bundle, where the execution entry point is the file
The result is a ready to use bundle that can be used on a web page simply like this:
Notice that we managed to use all our dependencies without even thinking about configuring a module loader.
What About SystemJs?
Did you notice that so far the SystemJs module loader is nowhere to be seen? This is because Jspm knows about SystemJs, and will transparently install it, include it in the self-executing bundle and use it to load the entry point of the application.
This is very powerful: we can use ES6 modules in production today in a transparent way. It all just works, even in a ES5-only project (using the require syntax).
What is the SystemJs Module Loader?
SystemJs is an universal module loader capable of loading modules of different formats: AMD, CommonJs, globals. It works both in node and in the browser.
SystemJs is composed of an ES6 module loader polyfill and a compatibility layer thats allows it to use different module formats. SystemJs can be used independently of Jspm, but the two tools are really best used together.
Using SystemJs independently of Jspm does not provide so many advantages over other solutions like Bower + Browserify or Bower + Webpack. You would still have to download the dependencies using another package manager and configure a build tool to create a bundle. Also you would need to install the module loader and learn how to configure it and use it.
With Jspm, we basically can more or less forget that there is a module loader being used, and simply use the ES6 import syntax (or the ES5 equivalent).
Jspm vs. Bower
Jspm and Bower where built with very different philosophies. Bower is based on the assumption that there can only be one version of a library at the same time in the browser.
Bower will download transitive dependencies into a flat tree, but if two versions of the same library are required it will ask the user which one it should choose. Bower allows to save that decision into
bower.json so that other users can have reproducible builds.
Jspm is designed for a world were developers build many small different frontend modules that get reused a lot, similarly to what happens in the npm world. To handle this, multiple versions of the same module can be loaded independently without conflict, but the user ultimately keeps control on those decisions if he wants to. SystemJs can even handle circular library references!
Jspm vs. Npm
More and more frontend libraries are getting published to npm with meaningful CommonJs exports, but those libraries cannot be used in node as they often require a DOM. The goal is to have a CommonJs module easily installable so that frontend libraries can be for example consumed by browserify, or even SystemJs and used in the browser instead of node. One frontend library that gets published to npm is for example AngularJs.
The npm team is planning to make npm more frontend friendly. The Angular team made or will make npm a concrete proposal for how that could be achieved.
Npm just released version 3 a couple of weeks ago and only in this latest version they implemented a maximally flat dependency tree. This is certainly a good first step to help cover frontend modularity, but Jspm has a huge head start on this and has a lot of momentum behind it.
Jspm allows for ES6 modules to already be used today, even with an ES5 syntax if needed. Although the SystemJs module loader can be used separately, you really get the most benefit if you use it transparently via Jspm.
Conceptually and feature-wise, Jspm and SystemJs are way ahead of other similar tools. Not only Jspm/SystemJs have more features but they are actually much simpler to use, especially in the self-executing bundle scenario presented above.
The following post provides an in-depth comparison of Bower, Jspm and npm - Is Bower dead? What is JSPM? Npm for client-side?
This talk from the creator of Jspm, SystemJs and the ES6 module loader polyfill Guy Bedford provides an in-depth dive into Jspm and SystemJs - Package Management for ES6 Modules
Also, the code in this post can be found here, with running instructions for seeing Jspm in action for the first time.