Skip to content

Instantly share code, notes, and snippets.

@Gozala
Forked from gordonbrander/derp-modules.js
Created October 11, 2012 08:56
Show Gist options
  • Save Gozala/3871097 to your computer and use it in GitHub Desktop.
Save Gozala/3871097 to your computer and use it in GitHub Desktop.
Simple, tiny, dumb JavaScript Modules
(function(exports) {
// Simple, tiny, dumb module definitions for Browser JavaScript.
//
// What it does:
//
// * Tiny enough to include anywhere. Intended as a shim for delivering
// browser builds of your library to folks who don't want to use script loaders.
// * Exports modules to `__modules__`, a namespace on the global object.
// This is an improvement over typical browser code, which pollutes the
// global object.
// * Prettier and more robust than the
// [IIFE module pattern](http://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript),
// and if you have multiple modules, it's really no bigger.
// * It's a compatible sub-set of AMD, so if you switch to a script loader,
// it will "just work".
// * Lets you know if your dependencies are awry.
// * Passes you a syncronous require, making this an option for wrapping
// Node libraries that don't require server features
// (e.g. wrap it with a Makefile or somesuch).
// * Helpful for development. Syncronous `require` means you can easily test
// code live in REPLs like the Console or Scratchpad:
//
// >> require('foo').bar()
// >> 3
//
// What it doesn't:
//
// * Does not handle script loading. You order your script tags yourself.
// BUT, it does throw helpful exceptions, letting you know if you've
// loaded your scripts out of order.
// * Does not do path mapping. Module IDs are absolute.
// * No AMD plugin/loader support, but could support inlined loader plugin
// resources like 'text!...' ones. A reasonable tradeoff for size.
// * Does not support the second AMD form `define(['a', 'b'], function (a, b) {})`.
// YAGNI.
//
// Motivation: make `define`/`require`/`exports` wrappers a practical module
// format for distributing libraries to folks, whether or not they use an
// AMD script loader.
// Create a hash to store our modules.
var modules = {};
// Create a hash of module factories.
var factories = {};
// Require a module at an id. Returns `module.exports` for the required
// module scope. `require` looks for defined modules and throws an
// exception when if modules are missing.
function require(id) {
// If there in no module factory defined yet for the given id,
// throw an exception!
if (!(id in factories)) throw Error(id + ' module is not defined')
// If module module has not being created from the factor yet,
// create one. Lazy factory calls allow unordered definitions,
// also may improve memory footprint.
if (!(id in modules)) {
var module = { id: id, exports: {} }
modules[id] = module
factories[id](require, module.exports, module)
// Freeze exports if possible to guard from mistakes.
if (Object.freeze) Object.freeze(module.exports)
}
// Return `module.exports`, this add's support form node's
// `module.exports = foo` convention.
return modules[id].exports
}
// Expose module and factory cache as properties of
// require to ease debugging.
require.modules = modules
require.factories = factories
exports.require = require
// Create an `define` function that implements minimal subset of AMD
// (see http://requirejs.org/docs/commonjs.html#manualconversion).
// This function takes module `id` and a `factory` function that is
// invoked on demand with `require`, `exports` and `module` free
// variables also available in nodejs module scopes. Resulting
// `module.exports` are cached for further requirements.
//
// * The `id` can be any valid key. Usually the name / url of your module.
// Module exports will be cached by that `id`.
// * The `factory` function is responsible for constructing a module and
// exporting it's values. It given `require` function, an `exports`
// object and a `module` object.
// This allows one to just wrap nodejs / commonjs modules into define
// calls to make them consumable in the browser.
function define(id, factory) {
var factories = define.factories
// Throw an exception if the module already exists.
if (id in factories) throw new Error(id + ' module is already defined')
define.factories[id] = factory
}
exports.define = define
})(this)
// You can have your modules in separate files, or in a single file.
define('jquery', function (require, exports, module) {
// jQuery stuff...
module.exports = jQuery;
});
define('underscore', function (require, exports, module) {
// Underscore stuff...
module.exports = _;
});
define('backbone', function (require, exports, module) {
var _ = require('underscore');
// Backbone stuff...
module.exports = Backbone;
});
@Raynos
Copy link

Raynos commented Oct 18, 2012

@Gozala

Object.freeze ruins any plugins.

Plugin modules require modules and monkey patch them

It also murders performance.

@jacobsandlund
Copy link

This gist is similar to what I am doing with Vaccine. I made the shim configurable, though. A user inputs their library's settings and it adjusts the shim to work with the minimum amount of code needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment