By Oleksii Rudenko May 5, 2015 7:55 PM
How to Use SystemJS hooks for building a Production Version of Your App

I use Ember.js and JSPM to build apps. Ember releases usually contain several files: ember.prod.js, ember.debug.js, ember.min.js etc. Ember.debug.js is handy for development and contains some extra code that enables better development process. And ember.prod.js is the version specifically made for production use.

In my code, I access Ember in the following way:

import Ember from 'ember';

This does not define which version of Ember I use and in order to supply the version I add a JSPM override which looks like this:

"github:components/ember@1.12.0-beta.1": {
  "main": "ember.debug", // I am using debug version here
  "files": [
    "ember.debug.js"
  ],
  "dependencies": {
    "jquery": "github:components/jquery@^2.0.3"
  },
  "shim": {
    "ember.debug": {
      "deps": [
        "jquery"
      ],
      "exports": "Ember"
    }
  }
}

This works well for development. But in order to make a production build I need to change this override and install the prod build instead. I didn’t like that and I was looking for a better solution. Today I have finally found it (thanks for Guy Bedford).

The first part of the solution is to change the override and add ember.prod.js to the list of files:

"github:components/ember@1.12.0-beta.1": {
  "main": "ember.debug",
  "files": [
    "ember.debug.js", "ember.prod.js"
  ],
  "dependencies": {
    "jquery": "github:components/jquery@^2.0.3"
  },
  "shim": {
    "ember.debug": {
      "deps": [
        "jquery"
      ],
      "exports": "Ember"
    }
  }
}

The main file remains unchanged. It’s still ember.debug but now two files will be installed to jspm_packages folder when you run jspm install — ember.debug.js and ember.prod.js.

The next step is to modify the gulp task (or its equivalent if you don’t use gulp) that builds the production version using jspm bundle or jspm bundle-sfx/static:

** UPDATE for JSPM 0.16.0**

gulp.task('jspm', function() {
  var builder = new jspm.Builder();

  function production(builder) {
    var systemNormalize = builder.loader.normalize;
    builder.loader.normalize = function(name, parentName, parentAddress) {
      if (name === 'ember') name = 'ember/ember.prod';
      if (name === './env.dev') name = './env.prod';

      return systemNormalize.call(this, name, parentName, parentAddress);
    };
  }

  production(builder);

  return builder.loadConfig('./config.js')
    .then(function() {
      return builder.buildStatic('app/main', 'dist/app.min.js', { sourceMaps: false, minify: false, mangle: false});
    });
});

** OLD JSPM VERSION BELOW **

Actually, JSPM is not needed for this task now. You’ll need to install SystemJS instead:

gulp.task('jspm', function() {
  var builder = new jspm.Builder();
  var System = require('systemjs');

  // extends default System
  function addProductionVersionOfEmber(System) {
    System._extensions.push(customExtensionName);
    var systemNormalize = System.normalize;

    // extends the normalize function
    System.normalize = function(name, parentName) {

      // if module name is ember use ember/ember.prod instead
      if (name === 'ember') name = 'ember/ember.prod';
      return systemNormalize.call(this, name, parentName);
    }
  }

  addProductionVersionOfEmber(System);

  builder.reset(System);

  return builder.loadConfig('./app/config.js') // jspm's config js
    .then(function() {
      builder.config({ // additional config
        baseURL: 'app',
        lib: 'app'
      });

      // building a self executing build
      return builder.buildSFX('main', 'dist/app.min.js', 
      { sourceMaps: false, minify: true, mangle: false});
    });
});

Now I can do production builds w/o modifying my code or package.json.

I hope you found this post useful and thanks for reading.