moving to modules
@mize
hi!
@mize
“moving to
modules”?
modules:
how do they work?
a unit of code…
…with an encapsulated definition
…that explicitly declares its dependencies
…whose instances can be mapped to different
identifiers that expose its interface
benefits
• Clean(er) global namespace
• Eases dependency management
• Reusability
• Testability
should i wait for
harmony?
—Sean Mize
“nope.”
goals of harmony
• Obviate need for globals
• Orthogonality from existing features
• Smooth refactoring from global code to modular code
• Smooth interoperability with existing JS module systems like AMD, CommonJS,
and Node.js
• Fast compilation
• Simplicity and usability
• Standardized protocol for sharing libraries
• Compatibility with browser and non-browser environments
• Easy asynchronous external loading
goals of harmony
• Obviate need for globals
• Orthogonality from existing features
• Smooth refactoring from global code to modular code
• Smooth interoperability with existing JS module
systems like AMD, CommonJS, and Node.js
• Fast compilation
• Simplicity and usability
• Standardized protocol for sharing libraries
• Compatibility with browser and non-browser environments
• Easy asynchronous external loading
no technical
excuse not to
migrate now
where do i start?
pick your poison
what do i need?
format and loader
node.js
/* makeItAwesome.js */!
var multiplier = require('multiplier').awesome;!
!
function makeItAwesome(value) {!
return value * multiplier;!
}!
!
exports = module.exports = makeItAwesome;
node.js
/* makeItAwesome.js */!
var multiplier = require('multiplier').awesome;!
!
function makeItAwesome(value) {!
return value * multiplier;!
}!
!
exports = module.exports = makeItAwesome;!
!
!
!
/* app.js */!
var makeItAwesome = require('makeItAwesome');!
var everything = require('status').good;!
!
everything = makeItAwesome(everything);
exports = module.exports = ?
/* makeItAwesome.js */!
var multiplier = require('multiplier').awesome;!
!
function makeItAwesome(value) {!
return value * multiplier;!
}!
!
exports = module.exports = makeItAwesome;!
!
!
!
/* Imagine this require() implementation */!
function (module, exports) {!
exports = some_func;!
// re-assigns exports, exports is no longer a shortcut,!
// and nothing is exported.!
module.exports = some_other_func;!
} (module, module.exports);
AMD
/* makeItAwesome.js */!
define(['multiplier/awesome'], function (multiplier) {!
function makeItAwesome(value) {!
return value * multiplier;!
};!
!
return makeItAwesome;!
});
AMD
/* makeItAwesome.js */!
define(['multiplier/awesome'], function (multiplier) {!
function makeItAwesome(value) {!
return value * multiplier;!
};!
!
return makeItAwesome;!
});!
!
!
!
/* app.js */!
define(['makeItAwesome', 'status/good'], function (makeItAwesome,
everything) {!
everything = makeItAwesome(everything);!
});
which?
Moving to Node?
☛ Node variant of CommonJS
Primarily in the browser?
☛ AMD + RequireJS, curl.js or similar
Need to share logic across both?
☛ You’ll need help.
ok, but what
about…
1. shave fewer yaks
2. choose approach
3. apply consistently
& clearly
pick your battles
useful questions
• What are your goals? What would be most
useful for your near-term needs?
• How quickly/completely can/do you need to
convert?
• F/E benefits or code reuse across stack?
• Are there other consumers of your libs?
migrate!
migrate!
1. Map your dependencies
migrate!
1. Map your dependencies
2. Load all of your files via loader
RequireJS shim
requirejs.config({!
baseUrl: '/src/js',!
paths: {!
'foo': 'legacy/foo'!
},!
shim: {!
'foo': {!
deps: ['bar'],!
exports: 'Foo',!
init: function (bar) {!
return this.Foo.noConflict();!
}!
}!
}!
});
migrate!
1. Map your dependencies
2. Load all of your files via loader
3. Walk your dependencies, wrapping or
converting as you go
[ interlude ]
possible sticking points
code sequence
/* Old - app.js */!
Foo.init();!
Bar.init(); // Bar depends on globals created during Foo.init()
code sequence
/* Old - app.js */!
Foo.init();!
Bar.init(); // Bar depends on globals created during Foo.init()!
!
!
!
/* Transitional - app.js */!
define(['foo', 'bar'], function (Foo, Bar) {!
Foo.init();!
Bar.init();!
});
code sequence
/* Old - app.js */!
Foo.init();!
Bar.init(); // Bar depends on globals created during Foo.init()!
!
!
!
/* Transitional - app.js */!
define(['foo', 'bar'], function (Foo, Bar) {!
Foo.init();!
Bar.init();!
});!
!
!
!
/* Final form - bar.js */!
define(['foo']), function (Foo) {!
// Former Foo.init logic is now part of Foo's module definition!
// so just do Bar stuff!
}
globals
You're using AMD, but others depending 

on your lib don't (yet).
globals
You're using AMD, but others depending 

on your lib don't (yet).
!
!
(function (root, factory) {!
if (typeof define === 'function' && define.amd) {!
// AMD. Register as an anonymous module.!
define(['b'], factory);!
} else {!
// Browser globals!
root.amdWeb = factory(root.b);!
}!
}(this, function (b) {!
// use b in some fashion.!
// ...!
return amdWeb;!
}));
migrate!
1. Map your dependencies
2. Load all of your files via loader
3. Walk your dependencies, wrapping or
converting as you go
4. Profit!
clean up
clean up
• Package management
• Optimize
• Great time to incorporate grunt (or gulp!) 

w/ linting/validation into your workflow
• Add tests!
don’t wait for
harmony.
!
write better
code now.
thank you!
@mize

Moving to modules

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
    a unit ofcode… …with an encapsulated definition …that explicitly declares its dependencies …whose instances can be mapped to different identifiers that expose its interface
  • 6.
    benefits • Clean(er) globalnamespace • Eases dependency management • Reusability • Testability
  • 7.
    should i waitfor harmony?
  • 8.
  • 9.
    goals of harmony •Obviate need for globals • Orthogonality from existing features • Smooth refactoring from global code to modular code • Smooth interoperability with existing JS module systems like AMD, CommonJS, and Node.js • Fast compilation • Simplicity and usability • Standardized protocol for sharing libraries • Compatibility with browser and non-browser environments • Easy asynchronous external loading
  • 10.
    goals of harmony •Obviate need for globals • Orthogonality from existing features • Smooth refactoring from global code to modular code • Smooth interoperability with existing JS module systems like AMD, CommonJS, and Node.js • Fast compilation • Simplicity and usability • Standardized protocol for sharing libraries • Compatibility with browser and non-browser environments • Easy asynchronous external loading
  • 11.
  • 12.
    where do istart?
  • 13.
  • 14.
    what do ineed? format and loader
  • 15.
    node.js /* makeItAwesome.js */! varmultiplier = require('multiplier').awesome;! ! function makeItAwesome(value) {! return value * multiplier;! }! ! exports = module.exports = makeItAwesome;
  • 16.
    node.js /* makeItAwesome.js */! varmultiplier = require('multiplier').awesome;! ! function makeItAwesome(value) {! return value * multiplier;! }! ! exports = module.exports = makeItAwesome;! ! ! ! /* app.js */! var makeItAwesome = require('makeItAwesome');! var everything = require('status').good;! ! everything = makeItAwesome(everything);
  • 17.
    exports = module.exports= ? /* makeItAwesome.js */! var multiplier = require('multiplier').awesome;! ! function makeItAwesome(value) {! return value * multiplier;! }! ! exports = module.exports = makeItAwesome;! ! ! ! /* Imagine this require() implementation */! function (module, exports) {! exports = some_func;! // re-assigns exports, exports is no longer a shortcut,! // and nothing is exported.! module.exports = some_other_func;! } (module, module.exports);
  • 18.
    AMD /* makeItAwesome.js */! define(['multiplier/awesome'],function (multiplier) {! function makeItAwesome(value) {! return value * multiplier;! };! ! return makeItAwesome;! });
  • 19.
    AMD /* makeItAwesome.js */! define(['multiplier/awesome'],function (multiplier) {! function makeItAwesome(value) {! return value * multiplier;! };! ! return makeItAwesome;! });! ! ! ! /* app.js */! define(['makeItAwesome', 'status/good'], function (makeItAwesome, everything) {! everything = makeItAwesome(everything);! });
  • 20.
    which? Moving to Node? ☛Node variant of CommonJS Primarily in the browser? ☛ AMD + RequireJS, curl.js or similar Need to share logic across both? ☛ You’ll need help.
  • 21.
  • 22.
    1. shave feweryaks 2. choose approach 3. apply consistently & clearly
  • 23.
  • 24.
    useful questions • Whatare your goals? What would be most useful for your near-term needs? • How quickly/completely can/do you need to convert? • F/E benefits or code reuse across stack? • Are there other consumers of your libs?
  • 25.
  • 26.
  • 27.
    migrate! 1. Map yourdependencies 2. Load all of your files via loader
  • 28.
    RequireJS shim requirejs.config({! baseUrl: '/src/js',! paths:{! 'foo': 'legacy/foo'! },! shim: {! 'foo': {! deps: ['bar'],! exports: 'Foo',! init: function (bar) {! return this.Foo.noConflict();! }! }! }! });
  • 29.
    migrate! 1. Map yourdependencies 2. Load all of your files via loader 3. Walk your dependencies, wrapping or converting as you go
  • 30.
    [ interlude ] possiblesticking points
  • 31.
    code sequence /* Old- app.js */! Foo.init();! Bar.init(); // Bar depends on globals created during Foo.init()
  • 32.
    code sequence /* Old- app.js */! Foo.init();! Bar.init(); // Bar depends on globals created during Foo.init()! ! ! ! /* Transitional - app.js */! define(['foo', 'bar'], function (Foo, Bar) {! Foo.init();! Bar.init();! });
  • 33.
    code sequence /* Old- app.js */! Foo.init();! Bar.init(); // Bar depends on globals created during Foo.init()! ! ! ! /* Transitional - app.js */! define(['foo', 'bar'], function (Foo, Bar) {! Foo.init();! Bar.init();! });! ! ! ! /* Final form - bar.js */! define(['foo']), function (Foo) {! // Former Foo.init logic is now part of Foo's module definition! // so just do Bar stuff! }
  • 34.
    globals You're using AMD,but others depending 
 on your lib don't (yet).
  • 35.
    globals You're using AMD,but others depending 
 on your lib don't (yet). ! ! (function (root, factory) {! if (typeof define === 'function' && define.amd) {! // AMD. Register as an anonymous module.! define(['b'], factory);! } else {! // Browser globals! root.amdWeb = factory(root.b);! }! }(this, function (b) {! // use b in some fashion.! // ...! return amdWeb;! }));
  • 36.
    migrate! 1. Map yourdependencies 2. Load all of your files via loader 3. Walk your dependencies, wrapping or converting as you go 4. Profit!
  • 37.
  • 38.
    clean up • Packagemanagement • Optimize • Great time to incorporate grunt (or gulp!) 
 w/ linting/validation into your workflow • Add tests!
  • 39.
  • 40.