Shepherd is a polyfill to manage Javascript modules and dependencies with an ECMAScript:Harmony-compliant syntax.

Stop wrapping your code with functions to build a module, your files are your modules. Period.


Shepherd allows you to take advantage of the features of the upcoming ECMAScript:Harmony within today's engines.

Overview A quick example to see at a glance what Shepherd basically does.

A classical JS file (yes, it's ugly code. Whatever.)










var _min = 0;
var _max = 1000;
var _lte = function (a, b) { return a <= b;};
var setMin = function (newMin) {
  if (_lte(newMin, max)) { min = newMin; }
};
var setMax = function (newMax) {
  if(_lte(min, newMax)) { max = newMax; }
};
var random = function () {
  return Math.round(Math.random() * (max - min)) + min;
};
      

Add sugar, let Shepherd operate: it's now a module!

//s6d
module randomRange {
  export setMin;    
  export setMax;    
  export random;    
}                   
//-s6d


var _min = 0;
var _max = 1000;
var _lte = function (a, b) { return a <= b;};
var setMin = function (newMin) {
  if (_lte(newMin, max)) { min = newMin; }
};
var setMax = function (newMax) {
  if(_lte(min, newMax)) { max = newMax; }
};
var random = function () {
  return Math.round(Math.random() * (max - min)) + min;
};
      
global is polluted by 6 variables, available all over the app.
global is not polluted at all, some vars are hidden, only useful elements are exposed to modules importing randomRange.

Features

Shepherd provides:

a syntax compliant with ECMAScript:Harmony
which means that when Harmony is implemented in modern JS engines, you will already use the new module syntax and features. And for older engines, there's Shepherd.
a clutter-free module definition
This is more about the decisions made at ECMA than it is about Shepherd, but this module syntax is really clean, flexible and readable. Stop using wrapper functions: Start writing at column 1!
a way to modularize external libraries as well
As you cannot force external dependencies to integrate the Harmony syntax, Shepherd provides facilities to depollute global and to modularize even the files you don't own.

How to use

Just include the following line to your header:

<script type="text/javascript" src="lib/shepherd.dev.js"></script>

Then include all the files you want Shepherd to handle like the following:

<script type="harmony" data-src="path/to/my/file.js"></script>

An in-depth documentation on the syntax will very soon (I promise) be made available.

Optimizer/Minifier

Once you're ready for production, Shepherd comes with an optimizer that will concatenate all your Javascript files into a single file. Obviously, as bandwidth is precious, the generated file is minified with UglifyJS.

Examples Let's see how it works!

Import a module from its URI
file.js:
//s6d
  module myModule at 'path/to/my/awesome/module.js'
//-s6d

console.log(myModule); // Displays myModule to the console
myModule is not available anywhere else in your application (unless you repeat the declaration in another module)
Import a module by its name
Declaring a named module (myNamedModule.js):
//s6d
  module myNamedModule {
    export doSomething;
}
//-s6d

var doSomething = function () {/* ... */};
Using the named module (myApp.js):
//s6d
  module myNamedModule;
//-s6d
// The above declaration specifies we want to use the module 'myNamedModule'

myNamedModule.doSomething();
Export variables
File1.js : Defining a module
//s6d
  export myExportedVar;
  export myExportedFn;
//-s6d

var a = 'This variable is private';
var b = function () {
  return 'This function is private too';
};

var myExportedVar = 'This variable is publicly available';
var myExportedFn = function () {
  return 'This function is publicly available';
}
File2.js : Importing a portion of the module
//s6d
  import myExportedVar from 'File1.js';
//-s6d

console.log(a); //undefined
console.log(b); //undefined
console.log(myExportedFn); //undefined
console.log(myExportedVar); //"This variable is publicly available"
File2a.js : Importing the whole module
//s6d
  module 'File1.js';
//-s6d

console.log(a); //undefined
console.log(b); //undefined
console.log(myExportedFn()); //"This function is publicly available"
console.log(myExportedVar); //"This variable is publicly available"
Turn your existing files into modules.
//s6d
module myModule {
  import imp1 from '/path/to/import.js';
  import imp2 from namedImportedModule; 
  module mod1 from '/path/to/module.js';
  module mod2 from myImportedModule;    
  export expA;                          
  export expB;                          
}                                       
//-s6d

/** Here after goes the code of your module **/

var expA = "This is an exported string";
var expB = ['This', 'is', 'an', 'exported', 'array'];
imp2 and mod2 are available via a reference name because they belong to/are (respectively) a module that has been given a name, just as in this example where myModule is the reference name for the module)
Use external libraries as modules.
Let's say you included jQuery from a CDN, such as
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
If you want to remove jQuery from the global space and make it available as a module in Shepherd, just add the following in your header:
<script type="text/shepherd-js">
  {
    modularize: '$',
    noGlobal: ['jQuery', '$']
  }
</script>
Using jQuery in a module (myModule.js):
//s6d
module $ from jQuery;
//-s6d

$.ajax(/*...*/);
Check out the live examples or the source code of this page too!
What about SSJS ?
Bootstrap your app like the following:
require('../../build/shepherd.server.js').call(this, 'app.js');
(where app.js is the main entry point of your app)
You can now use Shepherd in your app.
Note: You can keep using the commonJS syntax for your external modules.
Live examples
Check out the tests!

About

"Why on Earth would I learn yet another syntax..."

"...while I already know CommonJS and/or AMD which I love?" Because with Shepherd, you're not learning a new custom syntax, you're learning to use the future versions of Javascript as ECMA designed it.

Why such a name "Shepherd" ?

The idea came as a souvenir of a my hiking holidays during the summer 2011: a shepherd always looks after his sheep and takes care they are well grouped and graze in the right place.

What about Licensing ?

"Hmmm... let me guess. it's on GitHub, it's Javascript, there's +90% probability it's MIT."
You're right, Shepherd is licensed under the MIT license.

Never heard of you... Who are you ?

My name is Xavier Cambar, I've been a developer since the age of... Hmmm, let's say I've always been a developer, ok ?
I currently live in Paris, where I left all my previous develoment and management activities to focus on Javascript.

Of course, you can leave me a message here at GitHub or on Twitter @xcambar.
And if you want to send me an E-mail, surely you will find my address with ease.

tl;dr

Encapsulation through modules is a key factor to efficient/beautiful Javascript code.
Both AMD and CommonJS have proven very efficient, but they are hardly compatible.
ECMA made a proposal for the future versions of Javascript for native modules.
⇒ Waiting for the day the proposal will be integrated into the runtimes, a library allows you to use them: Shepherd.

"