Modules in JS

  • Module pattern
  • Revealing module pattern
  • CommonJS
  • AMD
  • ES6 modules

var myObjectLiteral = {
 
    propKey: propValue,
 
    functionKey: function functionName() {
      // ...
    }
};

var myModule = {
 
    myProp: 'myValue',
 
    myFunction: function functionName(myParam) {
      if (myParam != undefined)
          this.myProp = myParam
    }
};
var testModule = (function () {
 
  var counter = 0;
 
  return {
 
    incrementCounter: function () {
      return counter++;
    },
 
    resetCounter: function () {
      console.log( "counter value prior to reset: " + counter );
      counter = 0;
    }
  };
 
})();
var testModule = (function () {
 
  var counter = 0;
 
  return {
 
    incrementCounter: function () {
      if (counter > 99)
        resetCounter();
      return counter++;
    },
 
    resetCounter: function () {
      console.log( "counter value prior to reset: " + counter );
      counter = 0;
    },

  };
 
})();
var testModule = (function () {
 
  var counter = 0;
 
  return {
 
    incrementCounter: function () {
      if (counter > 99)
        resetCounter(); // Error!
      return counter++;
    },
 
    resetCounter: function () {
      console.log( "counter value prior to reset: " + counter );
      counter = 0;
    },

  };
 
})();
var testModule = (function () {
 
  var counter = 0;

  function incrementCounter() {
    if (counter > 99)
      resetCounter(); // Good!
    return counter++;
  }

  function resetCounter() {
    console.log( "counter value prior to reset: " + counter );
    counter = 0;
  }
 
  return {
 
    incrementCounter: incrementCounter,
    resetCounter: resetCounter

  };
 
})();
var testModule = (() => {
 
  let counter = 0;

  function incrementCounter() {
    if (counter > 99)
      resetCounter(); // Good!
    return counter++;
  }

  function resetCounter() {
    console.log( "counter value prior to reset: " + counter );
    counter = 0;
  }
 
  return {
 
    incrementCounter,
    resetCounter

  };
 
})();
define([
	'marionette',
	'underscore',
	'hbs!component-calculateur-gain/templates/erreur',
	'component-calculateur-gain/saisie/RecepisseSaisieView',
	'Errmess/messages'
], function (Marionette, _, template, RecepisseSaisieView, messages) {
	'use strict';

	var DEFAULT_MESSAGE_KEY = 'error.turfpari.5101';

	return Marionette.LayoutView.extend({

		template: template,

		regions: {
			saisie: '.saisie-region'
		},

		serializeData: function () {
			var hasServiceError = _.has(this.getOption('error'), 'code');
			return {
				message: hasServiceError
                                         ? messages.getErrorService(this.getOption('error'))
                                         : messages.get(DEFAULT_MESSAGE_KEY)
			};
		},

		onRender: function () {
			this.getRegion('saisie')
                            .show(new RecepisseSaisieView({model: this.model}));
		}
	});
});
require.config({
    baseUrl: '../app',
    paths: {
        accounting: '../bower_components/accounting/accounting',
        backbone: '../bower_components/backbone/backbone',
        Errmess: '../bower_components/Errmess',
        'Errmess/errmess': '../bower_components/Errmess/errmess-offline',
        hbs: '../bower_components/require-handlebars-plugin/hbs',
        IPv6: '../bower_components/urijs/src/IPv6',
        json: '../bower_components/requirejs-plugins/src/json',
        jquery: '../bower_components/jquery/dist/jquery.min',
        libpmu: '../bower_components/libpmu',
        lodash: '../bower_components/lodash/lodash',
        marionette: '../bower_components/backbone.marionette/lib/backbone.marionette',
        moment: '../bower_components/momentjs/moment',
        punycode: '../bower_components/urijs/src/punycode',
        SecondLevelDomains: '../bower_components/urijs/src/SecondLevelDomains',
        sprintf: '../bower_components/sprintf/src/sprintf',
        text: '../bower_components/text/text',
        uri: '../bower_components/urijs/src/URI',
        'vanilla-masker': '../bower_components/vanilla-masker/lib/vanilla-masker',
        // base directory
        'component-calculateur-gain': '../lib/js'
    },
    map: {
        '*': {
            'underscore': 'lodash'
        }
    }
});

AMD

  • Asynchrone
  • Pas vraiment besoin de phase de compilation
  • Peu lisible
  • Beaucoup de cérémonie/boilerplate
'use strict';
var marionette = require('marionette');
var _ = require('underscore');
var template = require('./component-calculateur-gain/templates/erreur');
var RecepisseSaisieView = require('./component-calculateur-gain/saisie/RecepisseSaisieView');
var messages = require('./Errmess/messages');

var DEFAULT_MESSAGE_KEY = 'error.turfpari.5101';

module.exports = Marionette.LayoutView.extend({

	template: template,

	regions: {
            saisie: '.saisie-region'
	},

	serializeData: function () {
            var hasServiceError = _.has(this.getOption('error'), 'code');
            return {
            message: hasServiceError
                     ? messages.getErrorService(this.getOption('error'))
                     : messages.get(DEFAULT_MESSAGE_KEY)
            };
	},

	onRender: function () {
            this.getRegion('saisie')
                .show(new RecepisseSaisieView({model: this.model}));
	}

});

CommonJS

  • Syntax très lisible et compacte
  • Peu de cérémonie
  • Synchrone
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}

export function diag(x, y) {
    return sqrt(square(x) + square(y));
}
    
//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

Harmony modules

  • Syntaxe compacte, comme CommonJS
  • Support du chargement asynchrone, comme AMD

Modules in JS

By Stanislas Ormières

Modules in JS

  • 451