Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Last active December 13, 2015 17:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dfkaye/4947847 to your computer and use it in GitHub Desktop.
Save dfkaye/4947847 to your computer and use it in GitHub Desktop.
namespace API proposal - an argument with myself - still in progres...

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.

Modules

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.

Context-switching is bad

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.

Namespace API

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 NPM 'node_modules' solution (package aliasing)

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?"

Yes I know about RequireJS

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?"

Yes, I know E6 is on the case

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?"

Main benefits again?

  • 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.

Final thoughts?

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.

Others

Ruben Verborgh

Tom Dale

This is a work in progress

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