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 installember.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.