pods
Version:
Tiny managers for module definition and dependency management.
188 lines (135 loc) • 6.91 kB
Markdown
# Pods.js
Pods.js is a tiny synchronous module definition and dependency management library, built around a familiar define/require interface. Pods are designed to provide a light-weight manager for organizing collections of related module components. Pods are a great way to break up a large compiled application codebase into managed modules. The synchronous nature of Pods also makes their benefits orthogonal to that of an AMD system such as RequireJS; it can still be useful to break down large AMD application modules into locally-scoped component clusters.
The `Pod` API has three methods: `define`, `declare`, and `require`. Pods may be instanced, each instance will manage its own collection of modules. Modules may also be managed through the static `Pod` interface.
```javascript
// Manage using constructed pod instances:
var p = new Pod();
p.define("module", {});
p.declare("jquery", $);
p.require("module");
// Manage through the static library instance:
Pod.define("module", {});
Pod.declare("jquery", $);
Pod.require("module");
```
Note that all `Pod` instances and the static `Pod` object will each manage their own unique module collections. A module defined in one Pod instance will not be available to other Pods.
## define()
The `define` method creates a module definition.
```javascript
Pod.define( "moduleId", [dependencies]?, exports );
```
- `"moduleId"` : *Required*. Unique string identifier for this module.
- `[dependencies]?` : *Optional*. Array of dependency module ids to be required and injected into the module's scope.
- `exports` : *Required*. An export object for the module, or a factory function used to build the module export. A factory function should receive arguments mapped to the module's dependencies.
The complete usage of `define` allows:
```javascript
var p = new Pod();
// 1) Define a module with a plain exports object.
p.define("module", {});
// 2) Define a module with a factory function.
p.define("module1", function() {
return {};
});
// 3) Define a module with a single dependency and factory function.
p.define("module2", ["module1"], function( mod1 ) {
return {};
});
// 4) Define a module with multiple dependencies and a factory function.
p.define("main", ["module1", "module2"], function( mod1, mod2 ) {
return {};
});
// Require a module to load it...
p.require("main");
```
While listing module dependencies, you may include `"pod"` as an identifier to have the managing Pod instance provide a reference to itself:
```javascript
var p = new Pod();
p.require(["pod"], function( pod ) {
console.log(pod === p); // true
});
```
Modules may be defined in any order, however, all `define` calls should precede your first `require` call. A good practice is to define a `"main"` module for launching your application, and then require `"main"` as your final line of code. For example, here's a simple modular application pattern:
```javascript
// 1) Create an application scope and pod instance...
(function() {
var p = new Pod();
// 2) Define all application modules...
p.define("module1", function() {
return {};
});
p.define("module2", function() {
return {};
});
// 3) Define a "main" module used to launch your app...
p.define("main", ["module1", "module2"], function( mod1, mod2 ) {
// Launch application!
});
// 4) Require "main"...
p.require("main");
}());
```
## declare()
The `declare` method is a convenient way to quickly define one or more object literals. When using `declare`, functions will be treated as export objects rather than as factory functions. Use this method to safely declare third-party libraries as managed modules.
```javascript
Pod.declare( "moduleId", exports );
// OR:
Pod.declare( exportsMap );
```
- `"moduleId"` : Unique string identifier for the declared module.
- `exports` : An export object for the module. The provided object will be set as the module's definitive export value; if a function is provided as the export, it will be preserved rather than being used as the module's factory.
- `exportsMap` : An object with key-value pairs mapping multiple module ids to their related exports.
The complete usage of `declare` allows:
```javascript
var p = new Pod();
// 1) Safely declare any object type (including functions/libraries) as module exports.
// (note that the root jQuery object is a *function*...)
p.declare("jquery", $);
// 2) Declare multiple exports as a map of key-value pairs.
p.declare({
"backbone": Backbone,
"jquery": $,
"underscore": _
});
```
Why `declare` third-party libraries rather than using `define`? jQuery is a great example: the root jQuery object is actually a function. In order to define jQuery, we'd need to wrap it in a factory function to safely export it. The `declare` method does this for us, like so:
```javascript
Pod.define("jquery", function() {
return $;
});
// is identical to...
Pod.declare("jquery", $);
```
## require()
The `require` method builds/accesses a module or collection of modules. Modules and their dependencies are built the first time they are required. Built modules are returned by the `require` method, *and* injected into an optional callback.
```javascript
var module = Pod.require( ["moduleId"], callbackFunction? );
```
- `["moduleId"]` : *Required*. The string identifier of a single module, *or* an array of module ids.
- `callbackFunction?` : *Optional*. Callback function into which the required modules are injected. Provide mapped arguments.
- `return` : A single module is returned when a single id string is required; an array of modules is returned when an array of module ids are required.
The complete usage of `require` allows:
```javascript
var p = new Pod();
p.define('module1', {});
p.define('module2', {});
// 1) Return a single module by direct id reference.
var module = p.require('module1');
// 2) Inject a single module as an argument of a callback function.
p.require('module1', function( mod1 ) {
// do stuff.
});
// 3) Return an array of modules mapped to a list of required ids.
var moduleArray = p.require(['module1', 'module2']);
// 4) Inject a collection of modules as arguments of a callback function.
p.require(['module1', 'module2'], function( mod1, mod2 ) {
// do stuff.
});
// 5) OR, do all of the above... return AND inject one or more modules with a single require call.
var moduleArray = p.require(['module1', 'module2'], function( mod1, mod2 ) {
// do stuff.
});
```
Which came first, the chicken or the egg? Pods do not care to figure it out, so they'll throw an exception when a circular reference is required. Avoid circular references; you should be rethinking your organization anyway if you encounter this problem.
## Notes
- Support for elevating MMD/Pods methods to global scope has been officially deprecated as of version 2. Pods are specifically intended to be used as instances.
- Happy building, and have fun!