Edit: I updated the JavaScript modules in http://enlargeyourpassword.com to use scope(). You can see the result in the source of the page, and get an idea of the process by looking at the commit history on GitHub.
As a JavaScript developer, I want to write modules in a format that is well supported today and that will still work in five years.
I designed an open-source library to this end, scope or not, with two goals in mind. It should be:
- simple to declare JavaScript modules with dependencies
- simple to implement your own version of the library to customize its behavior
There is a single function named scope()
. This is a null implementation:
function scope(code, needs, name){
return null;
}
The parameter code
is required. It is a function that defines a module. For example:
scope(function(){
var module = {};
// ...
return module;
});
The scope()
function has different implementations with different behaviors: it may create a module in the global scope, in a private scope, synchronously or asynchronously after loading dependencies.
When the scope()
function is synchronous, it returns the module just created, which allows to use scope()
as a direct replacement of the Immediately Invoked Function Expression pattern typically used to declare modules in JavaScript:
var myLib = myLib || scope(function(){
return {
// myLib API
};
});
The last two parameters needs
and name
are optional. The name of a module is a string which identifies the module and allows to reference it in the list of needs of other modules:
scope(function(){
var moduleA = {};
// ...
return moduleA;
},[],"moduleA");
scope(function(context){
// ...
return moduleB;
},["moduleA"],"moduleB");
For each dependency in the array of needs, a property of the same name is set on the context object which is provided as argument to the function:
scope(function(context){
var
moduleA = context.moduleA, // a local alias for "moduleA"
moduleB = {};
// ...
return moduleB;
},["moduleA"],"moduleB");
To use the scope()
function, you can write your own or build it from building blocks available in the scope or not project. The building blocks are sorted in levels. The level 1 provides the bootstrap, it must be loaded first. One building block may be picked from each level. Building blocks from lower levels are expected to be loaded first, but they are all optional.
Building blocks in higher levels use the scope()
function of the bootstrap to define a replacement function "scope", declared as a module. For example:
// from scope-level2-shared.js
scope(function(parentContext){
var
// private field
privateContext = {};
/*
Function: scope(code[,needs[,name]]): any
Run code immediately in a private context, and set the return value,
if any, to a property with given name in the private context
(...)
*/
function scope(code,needs,name){
var result = code(privateContext);
if (typeof name !== "string"){
return result;
}
privateContext[name] = result;
if (name === "scope"){
// replace the current implementation of scope() in parent context
parentContext.scope = result;
}
return result;
}
return scope;
},[],"scope");
When you implement the scope()
API yourself, you may either create a building block on top of the scope bootstrap and other building blocks, or rewrite the scope()
function from scratch, replacing the bootstrap and all building blocks altogether.
In a browser, you can load building blocks with script tags, then load your own modules:
<script src="scopeornot/scope-level1-global.js"></script>
<script src="scopeornot/scope-level2-shared.js"></script>
<script src="moduleA.js"></script>
<script src="moduleB.js"></script>
...
You may later change the building blocks to load your modules asynchronously instead:
<script src="scopeornot/scope-level1-global.js"></script>
<script src="scopeornot/scope-level2-shared.js"></script>
<script src="requirejs/require.js"></script>
<script src="scopeornot/scope-level3-amd.js"></script>
<script src="setup-and-startup-top-level-module-with-require.js"></script>
Please review the usability of this API from the point of view of a developer who uses the API and from the point of view of a developer who implements the API.