Globals are bad
Globals are discouraged as bad practice.
Globals are what we have
Without globals, there is no way to expose your module to other modules, i.e., scripts have to be declared in a specific order so that dependant scripts can use them, and the variables that point to them have to be global.
We see examples of dot.delimited.namespaces all the time - those work in the browser and perform lookups reasonably well. But they are really just big structures whose parts can be clobbered (or mocked - yay).
The problems start with the declaration and re-declaration of the same namespace structure. The solution to this is a function that takes a string and tokenizes it to namespace parts and visits or builds on an existing structure non-destructively. The frameworks have all done this.
But that's where the problem really lies - each framework checks for its existence in the global namespace (var APP = !('APP' in window || window.APP) || {}
) or variation. So in order to use just part of someone else's codebase, we have to include that project's god object to import the rest.
And that check for itself in the global space can be confounded by A Subtle Difference Between Window Properties and Global Variables
It would be nice in browser-side JavaScript to have one reliable way to declare and import modules without having to download the framework that loads them for us.
CommonJS on Node.JS and AMD on the browser attempt to manage dependencies via sandboxing, but neither truly supports namespacing per se. The API for each is just different enough that editing files to work in each environment requires either more boilerplate (such as Addy Osmani's UMD proposals) or just context-switching.
Intelligent people can and do disagree, but I want to be productive. Don't make me switch from one context to another in order to edit code in the same language - JavaScript.
I'd like to see a common API for all environments:
In a 'dialogUser.js' file:
importScripts('dojo/dialog.js'); // yes I use semi-colons
namespace(function (module) {
var dialog = module.require('dojo/dialog.js');
module.exports = dialogUser;
function dialogUser(dialog) {
// use dialog to do something
};
});
The function inside the namespace()
call would be scoped (this) to the module's exports property.
PRIOR ART HERE ~ Stoyan Stefanov's discussion of sandboxing in YUI and his JavaScript Patterns book.
However...
The module passed in should be a copy of the actual module code.
That would make it harder to clobber shared code, easier to 'mock' dependencies in tests, etc. In Node.js, you can modify an imported module directly - its modified self is then available to all other modules.
The confusion on display in this Twitter conversation from Feb 27, 2013 - pathnames in the require() function - makes clear that CommonJS does not solve the problem; hence, Node.JS adopts the 'node_modules' solution for top-level packages.
tl;dr ~ put modules in a special directory along with an NPM configuration file (package.json).
As Crockford asked in JavaScript: The Good Parts, "have we really improved anything?"
RequireJS offers the AMD syntax which differs enough from CommonJS that YET ANOTHER BOILERPLATE is necessary to get it working on Node.JS and browsers.
`define(maybe a name?, [maybe an array of dependency strings]?, maybe a 'factory' function?);...`
Repeating Crockford, "have we really improved anything?"
The ES6 spec so far adds a lot of features (classes? Loader? module? import?). I'm interested in as simplified an API as possible today.
Crockford again - "Have we really improved anything?"
-
load only those parts of a module or whatever that we're interested in.
-
allow Dojo, YUI and the rest to stop declaring themselves on the global namespace.
-
allow everyone to get out of the business of managing/exposing/ensuring our own globals don't collide with others' - and get out of the browser-mainly
dot.delimited.object.tree
style of managing packages.
We already have accidental globals, we have "use strict"; we have some Object creation sugar, but we still do not have real MATH.
Let's at least fix namespaced modules and dependencies and get this over with. Classes, modules and loaders will not work as advertised (at least not right away) and that will delay the arrival of browser package modules.
This is a work in progress