Skip to content

Instantly share code, notes, and snippets.

@jcubic
Last active September 3, 2018 08:32
Show Gist options
  • Save jcubic/e19bf38f8c26b726ca2a75a6d3cdb505 to your computer and use it in GitHub Desktop.
Save jcubic/e19bf38f8c26b726ca2a75a6d3cdb505 to your computer and use it in GitHub Desktop.
Module definition function with namespace and dependencies
// -----------------------------------------------------------------------------
// Copyright (c) 2018 Jakub Jankiewicz
// Released under MIT license
//
// generic namespace generator the constructor should declare private functions
// and variables and return public api, the module is created when all dependecies
// are resolved (all modules are created)
//
// @param namespace dot separated namespace that will be added to window object
// @param dependencies array of string (dependencies) can be empty array
// @param constructor function that should return public module API
//
// usage:
// module('app.projects', ['app.helpers'], function(helpers) {
// console.log(app.helpers === helpers);
// helpers.log('hello');
// return {
// foo: function() {
// helpers.log('foo');
// }
// };
// });
// module('app.helpers', [], function() {
// return {
// log: function(msg) {
// console.log(msg);
// }
// };
// });
// -----------------------------------------------------------------------------
var module = (function() {
// to keep track of dependencies, real objects are nested in window
var modules = {};
// ---------------------------------------------------------------------------
function init(module) {
var dependencies = module.dependencies.map(function(name) {
if (!modules[name]) {
throw new Error('Internal Error: module ' + name + ' not defined when' +
' initializing ' + module.name);
}
return modules[name].module;
});
module.loaded = true;
Object.assign(module.module, module.constructor.apply(null, dependencies));
}
// ---------------------------------------------------------------------------
function concat(array) {
array = array.slice()
if (array.length > 1) {
var last = array.pop();
return array.join(', ') + ' and ' + last;
} else {
return array[0];
}
}
// ---------------------------------------------------------------------------
return function module(namespace, dependencies, constructor) {
var names = namespace.split('.');
var current = window;
names.forEach(function(name) {
if (!current[name]) {
current[name] = {};
}
current = current[name];
});
if (modules[namespace]) {
throw new Error('Module ' + namespace + ' already defined');
}
var module = modules[namespace] = {
name: namespace,
module: current,
dependencies: dependencies,
constructor: constructor
};
// if dependencies not resolved
if (dependencies.length) {
// are all dependentant modules loaded?
var foundDepenencies = dependencies.filter(function(dependency) {
return modules[dependency];
});
if (foundDepenencies.length === dependencies.length) {
init(module);
}
} else {
// no depeendecies
init(module);
}
var modulesWithdependencies = Object.keys(modules).filter(function(name) {
var module = modules[name];
// don't process self and modules that don't have dependencies,
// those was already loaded
return Object.keys(module.dependencies).length;
});
modulesWithdependencies.filter(function(name) {
return name !== namespace;
}).forEach(function(name) {
var module = modules[name];
var dependats = module.dependencies;
var resolved = dependats.filter(function(key) {
return modules[key];
});
// init modules that have resolved dependencies
if (resolved.length === dependats.length) {
if (!module.loaded) {
init(module);
}
} else {
// find mutual dependencies
if (dependats.length) {
var mutualDependant = modulesWithdependencies.filter(function(searchName) {
var searchModule = modules[searchName];
return Object.keys(searchModule.dependencies).indexOf(name) !== -1;
});
if (mutualDependant.length) {
var brokenModules = mutualDependant.concat([name]);
// this will show error in toaster and log in server because of window
// error handler in error.js
throw new Error(concat(brokenModules) + ' have mutual dependecy');
}
}
}
});
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment