moving to modules
DESCRIPTION
You believe in the power of JavaScript modules, but you have an existing app, stack or platform infrastructure to keep running. Between maintenance and new features, where do you carve out time to switch over? After a brief overview of modules and why they're great, we'll dig into how to actually migrate a code base, from plotting your approach to implementation tips. Video: http://youtu.be/FbdcdC8mqwE?t=50m51s (watch the entire video from the beginning for other great talks about shadow DOM and competing task runners) Talk from February 19, 2014 NYCHTML5 Meetup: http://www.meetup.com/nychtml5/events/160684962/TRANSCRIPT
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 shimrequirejs.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!}
globalsYou're using AMD, but others depending on your lib don't (yet).
globalsYou'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