By Oleksii Rudenko June 25, 2015 9:25 PM
Optimizing default JSPM workflow with Gulp and Nginx

The Problem

When their apps becomes bigger, many JSPM users experience slowness of their default development workflows. Typically users choose JSPM because they want to use the new ES6/7/typescript/whatever syntax and to get rid of build tools. And JSPM gives them what they want — in-browser ES6 transpilation for users’ ES6 modules by default and a variety of loader plugins to move their build tools into the browser. This works fine for small apps but when the app grows and gets more dependencies, the initial page load becomes very slow.

For one of my apps the initial page load with the default workflow could take ~40s.

The Causes

It’s possible to speed up things but unfortunately it requires some build tools. To improve the workflow, one has to identify the causes of the slowness. The most likely the causes are:

  1. In-browser transpilation because all files are re-transpiled on each page load. Not-only the transpilation of the JS files is slow, in-browser compilation of templates (if you have some templates) is slow too.
  2. The number of requests JSPM/SystemJS makes to load files makes the app slow in development because neither the browsers nor the most of development http servers handle the big number of requests well.

The Solution

There are several solutions for these bottlenecks:

  1. Move transpilation of app JS files and compilation of templates to a build tool. The tool must cache the result of compilation and re-compile only what was changed.
  2. Use JSPM bundles to build dependencies of the app.

The difference between improvements #1 and #2 is that #1 results in a transpiled/compiled copy of application files whereas #2 results in a single, possibly minified, file. So JSPM loads application js files and templates as usual but w/o using the transpiler or loaders plugins. Also the bundle can be rebuilt once in a while — when dependencies change. And app files needs to be rebuilt as they change.

  1. use a faster web server that supports modern HTTP protocols

For example, the commonly used browser-sync is quite slow compared to, say, nginx when serving many requests.

The Example

I have created a demo of my optimized development workflow here: https://github.com/OrKoN/jspm-ember-playground Although it uses the Ember framework I think it may be re-used with some modifications for other frameworks too.

It uses nginx as a development server, so it needs to be installed first. Also it requires the realpath command to be installed. Most likely the demo works only on Linux-like systems.

To get it running once you installed nginx and realpath:

  git clone https://github.com/OrKoN/jspm-ember-playground
  cd jspm-ember-playground
  npm install
  gulp
  sudo ./bin/start.sh

and open https://127.0.0.1:8080 for the development version or run:

  gulp build

and open https://127.0.0.1:8081 for the production version of the app. Most likely the browser will warn you of an unverified ssl certificate but just continue.

Important notes about the structure of the app

Apart from the dependencies and overrides jspm has the following config:

  "directories": {
    "baseURL": "build"
  },
  "configFile": "jspm.config.js"

To avoid confusion the config file is renamed to jspm.config.js and the baseURL is set to the build folder because nginx will serve files from the build. The build folder is the root of the compiled development version of the app.

The other folders are:

  • app - the source folder of the application
  • bin - the folder containing start.sh and stop.sh to start/stop the nginx
  • build - as said previously, the root of the web server that contains the built development version of the app
  • conf - nginx configration
  • logs - nginx logs
  • pids - nginx pid
  • vcl - config for the css framework that we use

Important files are the following:

  • gulpfile.js - where all gulp tasks are defined
  • jspm.config.js - the config for jspm/systemjs. It’s symlinked to the build/jspm.config.js by a gulp task
  • main-bundle.js - the bundled app dependencies. It’s symlinked to the build/main-bundle.js by a gulp task

Important gulp tasks:

  • gulp - the default task that rebuilds the development version of the app completely
  • gulp build - builds the production version of the app and places it to the dist folder
  • gulp watch - watches the app folder for changes and re-compiles stuff that changed. In the demo, gulp watch actually rebuilds everything but it’s easy to rebuild only what changed using gulp-changed or other tool

This is how the app looks like:

Results

This is a development version (which means your can edit app files, hit the refresh button and see the update) and it takes 164ms to start. Of course, this app has few dependencies and it’s quite simple itself. But from my experience this setup scales good for bigger apps too.

Thanks for reading. Share your JSPM setups. I am eager to learn from others!