Patterns for ES6 JavaScript modules - Part 3

In Part 1 and Part 2 of this series, I described a couple of my favorite ES6 module patterns. In Part 3, I am going to show you a pattern that is a variation on these two patterns - the self-executing function pattern. You have almost certainly seen this pattern before. For an example, I will return to the LacesIDE in browser editor. The code below comes from app.auth.js in the root of the /client/js folder. I have redacted most of the logic in the module for brevity.

import {a7} from '/lib/altseven/dist/a7.js';
import {ui} from '/js/app.ui.js';
import {main} from '/js/app.main.js';

export var auth = (function() {
  "use strict";

  var _authenticate = function() {
    var promise = new Promise(function(resolve, reject) {
      // check whether user is authenticated
      a7.security.isAuthenticated(resolve, reject);
    });

    promise.then(function(secure) {
        // do a bunch of auth stuff
        _somePrivateFunction( secure );
    });
  };

  var _logout;

  return {
    authenticate: _authenticate,
    loginHandler: function(json) {
      let user = a7.model.get( "user" );
      if( json.success ){

        a7.ui.views['header'].setState( { user: user } );
      }
      main.run( user );
    }
  };
})();

Like the module in Part 2, this module contains a single exported function. However, this function is automatically executed when the module loads. Notice the format:

export var auth = (function() {

///

})();

By encapsulating the function in parens and including parens after, you create an encapsulating function that is self-executing. Remember that in Part 2, once you import the module, you still need to execute the function for it to do anything:

import {authEvents} from '/events/auth.js';

authEvents();

With the self-executing module, you don’t need to do that. You just import the module and the return value of the function is assigned to the imported variable:

import {auth} from '/app.auth.js';

auth.authenticate();

I use all three of these patterns on a consistent basis. Which one I choose for a particular module depends on my goals. None of this is particularly complex or sophisticated. I have always felt like we as software engineers and architects should do our best to make our code easy to understand and maintain. Yes, sometimes code is complex by necessity, but the complexity of the code should be related to the complexity of the task, not the complexity of the code for its own sake. By using a consistent set of patterns for organizing my modules, I make the code easy to read and understand- not just for others, but for myself as well.

I have another pattern I use for remote interaction modules on the client side, next time I will share that pattern.