Upgrade to Pro — share decks privately, control downloads, hide ads and more …

require.js

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 require.js

Avatar for Jason Lotito

Jason Lotito

March 28, 2013
Tweet

More Decks by Jason Lotito

Other Decks in Technology

Transcript

  1. why do I need it? • Web sites are turning

    into Web apps Wednesday, March 27, 13
  2. why do I need it? • Web sites are turning

    into Web apps • Code complexity grows as the site gets bigger Wednesday, March 27, 13
  3. why do I need it? • Web sites are turning

    into Web apps • Code complexity grows as the site gets bigger • Assembly gets harder Wednesday, March 27, 13
  4. why do I need it? • Web sites are turning

    into Web apps • Code complexity grows as the site gets bigger • Assembly gets harder • Developer wants discrete JS files/modules Wednesday, March 27, 13
  5. why do I need it? • Web sites are turning

    into Web apps • Code complexity grows as the site gets bigger • Assembly gets harder • Developer wants discrete JS files/modules • Deployment wants optimized code in just one or a few HTTP calls Wednesday, March 27, 13
  6. how does it solve this? • Some sort of #include/import/require

    • ability to load nested dependencies Wednesday, March 27, 13
  7. how does it solve this? • Some sort of #include/import/require

    • ability to load nested dependencies • ease of use for developer but then backed by an optimization tool that helps deployment Wednesday, March 27, 13
  8. how do I use require.js? // index.html <script data-main="scripts/main" src="scripts/require.js"></script>

    // scripts/main.js require(["loc/module"], function(module) { //This function is called when scripts/loc/module.js is loaded. //If module.js calls define(), then this function is not fired until //util's dependencies have loaded, and the util argument will hold //the module value for "helper/util". }); Wednesday, March 27, 13
  9. how do I use require.js? // index.html <script data-main="scripts/main" src="scripts/require.js"></script>

    // scripts/main.js require(["loc/module"], function(module) { //This function is called when scripts/loc/module.js is loaded. //If module.js calls define(), then this function is not fired until //util's dependencies have loaded, and the util argument will hold //the module value for "helper/util". }); Wednesday, March 27, 13
  10. how do I use require.js? // index.html <script data-main="scripts/main" src="scripts/require.js"></script>

    // scripts/main.js require(["loc/module"], function(module) { //This function is called when scripts/loc/module.js is loaded. //If module.js calls define(), then this function is not fired until //util's dependencies have loaded, and the util argument will hold //the module value for "helper/util". }); Wednesday, March 27, 13
  11. writing a module, today (function ($) { function Foo() {

    // do stuff here! } new Foo(); }(jQuery)); Wednesday, March 27, 13
  12. writing a module, today var $ = require('jquery'); exports.myExample =

    function () { // do stuff here! }; Wednesday, March 27, 13
  13. writing a module, today++: AMD define('mod',function(){ return function() { this.boom

    = function () { alert( 'Boom' ); }; } } ); Wednesday, March 27, 13
  14. why is this good? • Uses the CommonJS practice of

    string IDs for dependencies • IDs can be mapped to different paths. • Encapsulates the module definition. • Clear path to defining the module value. • Allows setting a function as a return value. Useful for constructor functions. • Defines a way to include multiple modules in one file. Wednesday, March 27, 13
  15. why is this good? • Easy to test, because modules

    are compartmentalized • Dependency Injection Wednesday, March 27, 13
  16. require still supports normal javascript require(["some/script.js"], function() { //This function

    is called after some/script.js has loaded. }); Wednesday, March 27, 13
  17. Optimization! • We can compile all requirements into one file

    • We can minimize CSS and JavaScript using Closure Compiler (or UglifyJS) • We aren’t worried about CSS today Wednesday, March 27, 13
  18. Can run... • In the browser • In Node •

    In Rhino Wednesday, March 27, 13
  19. Using Closure Compiler • Means uses Java • Means using

    Rhino • r.js Wednesday, March 27, 13
  20. What’s app.build.js ({ appDir: "../", baseUrl: "scripts/", dir: "../../webapp-build", optimize:

    "closure", paths: { "jquery": "empty:" }, modules: [ //Optimize the application files. jQuery is not //included since it is already in require-jquery.js { name: "main" } ], closure: { CompilerOptions: {}, CompilationLevel: 'SIMPLE_OPTIMIZATIONS', loggingLevel: 'WARNING' }, generateSourceMaps: true, preserveLicenseComments: false }) Wednesday, March 27, 13
  21. Alright stop... Let’s make sense of all these options by

    establishing our surroundings, namely, our project structure Wednesday, March 27, 13
  22. Our sample directory structure • r.js • webapp/ • app.html

    • scripts/ • app.build.js Wednesday, March 27, 13
  23. Our sample directory structure • r.js • webapp/ • app.html

    • scripts/ • app.build.js • app.build.dev.js Wednesday, March 27, 13
  24. Our sample directory structure • r.js • webapp/ • app.html

    • scripts/ • app.build.js • app.build.dev.js • main.js Wednesday, March 27, 13
  25. Our sample directory structure • r.js • webapp/ • app.html

    • scripts/ • app.build.js • app.build.dev.js • main.js • mod.js Wednesday, March 27, 13
  26. the app require( ["jquery", "mod"], function ( $, mod )

    { var mod = new mod(); setTimeout( function () { mod.boom(); $( 'h1' ).text( 'Hey you guys!' ); }, 2000 ); setTimeout( function () { mod.boom(); $( 'h1' ).text( 'Baby, ruth?' ); }, 4000 ); setTimeout( function () { mod.boom(); $( 'h1' ).text( 'Truffle Shuffle' ); }, 6000 ); } ); Wednesday, March 27, 13
  27. the module define('mod',function(){ return function() { this.boom = function ()

    { alert( 'Boom' ); }; } } ); Wednesday, March 27, 13
  28. modules can include other modules define('mod',['member/photos'],function(photos){ return function() { this.boom

    = function () { alert( 'Boom' ); photos.boom(); }; } } ); Wednesday, March 27, 13
  29. Compiled and minified via Closure Compiler (function(){define("mod",[],function(){return function(){this.boom=function() {alert("Boom")}}});require(["jquery","mod"],function(b,a){a=new a;setTimeout(function(){a.boom();b("h1").text("Hey

    you guys!")}, 2E3);setTimeout(function(){a.boom();b("h1").text("Baby, ruth?")}, 4E3);setTimeout(function(){a.boom();b("h1").text("Truffle Shuffle")}, 6E3)});define("main",function(){})})(); //@ sourceMappingURL=main.js.map Wednesday, March 27, 13
  30. Compiled with Source Maps closure: { CompilerOptions: {}, CompilationLevel: 'SIMPLE_OPTIMIZATIONS',

    loggingLevel: 'WARNING' }, generateSourceMaps: true, preserveLicenseComments: false Wednesday, March 27, 13
  31. .map file {"version":3, "file":"main.js", "lineCount":1, "mappings":"AAAC,SAAA,GACDA,MAAA,UAAgB,QAAA,SACP,SAAA,GACLC, SADK,CACOC,QAAAA,GAEVC,KAAA,QAFUD,CADP,CADO,CAAhB,CASA E,QAAA,kBAA4B,QAAA,CAAWC,CAAX,CAAcC,CAAd,EAEtBA,CAFsB,CAE hB,IAAIA,CAEdC,WAAA,CAAY,QAAA,GAEVD,CAAAL,KAAA,EACAI,EAAA, MAAAG,KAAA,iBAHU,CAAZ,KAMAD,WAAA,CAAY,QAAA,GAEVD,CAAAL,

    KAAA,EACAI,EAAA,MAAAG,KAAA,eAHU,CAAZ,KAMAD,WAAA,CAAY,QA AA,GAEVD,CAAAL,KAAA,EACAI,EAAA,MAAAG,KAAA,mBAHU,CAAZ,KAh B0B,CAA5B,CAwBAR,OAAA,QAAe,QAAA,IAAf,CAlCC,EAAA;", "sources":["main.js.src"], "names": ["define","boom","this.boom","alert","require","$","mod","setTimeout","text"]} Wednesday, March 27, 13
  32. testing define( 'mod', ['Profile'], function ( Profile ) { function

    mod() { this.boom = function () { return (new Profile()).mockTrueLol(); }; } return mod; } ); Wednesday, March 27, 13
  33. JSTestDriver # tests.jstd load: - r.js - webapp/tests/app.build.test.js # This

    let’s JSTestRunner serve up all the scripts for require serve: - webapp/scripts/*.js # Could also just do - webapp/tests/*.js test: - webapp/tests/GangTest.js - webapp/tests/LandTest.js - webapp/tests/ProfileTest.js - webapp/tests/TestJSTestDriver.js Wednesday, March 27, 13
  34. JSTestRunner # tests.jstd load: - r.js - webapp/tests/app.build.test.js # This

    let’s JSTestRunner serve up all the scripts for require serve: - webapp/scripts/*.js # Could also just do - webapp/tests/*.js test: - webapp/tests/GangTest.js - webapp/tests/LandTest.js - webapp/tests/ProfileTest.js - webapp/tests/TestJSTestDriver.js Wednesday, March 27, 13
  35. JSTestRunner # tests.jstd load: - r.js - webapp/tests/app.build.test.js # This

    let’s JSTestRunner serve up all the scripts for require serve: - webapp/scripts/*.js # Could also just do - webapp/tests/*.js test: - webapp/tests/GangTest.js - webapp/tests/LandTest.js - webapp/tests/ProfileTest.js - webapp/tests/TestJSTestDriver.js Wednesday, March 27, 13
  36. JSTestRunner # tests.jstd load: - r.js - webapp/tests/app.build.test.js # This

    let’s JSTestRunner serve up all the scripts for require serve: - webapp/scripts/*.js # Could also just do - webapp/tests/*.js test: - webapp/tests/GangTest.js - webapp/tests/LandTest.js - webapp/tests/ProfileTest.js - webapp/tests/TestJSTestDriver.js Wednesday, March 27, 13
  37. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { setUp: function

    ( queue ){ queue.call( function ( callbacks ){ require.undef( 'Profile' ); define( 'Profile', function (){ function Profile() {} Profile.prototype.mockTrueLol = function() { return true; }; return Profile; } ); require( [ 'mod' ], callbacks.add( function ( m ){ Mod = new m(); } ) ); } ); }, // tests here } ); })(); Wednesday, March 27, 13
  38. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { setUp: function

    ( queue ){ queue.call( function ( callbacks ){ require.undef( 'Profile' ); define( 'Profile', function (){ function Profile() {} Profile.prototype.mockTrueLol = function() { return true; }; return Profile; } ); require( [ 'mod' ], callbacks.add( function ( m ){ Mod = new m(); } ) ); } ); }, // tests here } ); })(); Wednesday, March 27, 13
  39. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { setUp: function

    ( queue ){ queue.call( function ( callbacks ){ require.undef( 'Profile' ); define( 'Profile', function (){ function Profile() {} Profile.prototype.mockTrueLol = function() { return true; }; return Profile; } ); require( [ 'mod' ], callbacks.add( function ( m ){ Mod = new m(); } ) ); } ); }, // tests here } ); })(); Wednesday, March 27, 13
  40. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { setUp: function

    ( queue ){ queue.call( function ( callbacks ){ require.undef( 'Profile' ); define( 'Profile', function (){ function Profile() {} Profile.prototype.mockTrueLol = function() { return true; }; return Profile; } ); require( [ 'mod' ], callbacks.add( function ( m ){ Mod = new m(); } ) ); } ); }, // tests here } ); })(); Wednesday, March 27, 13
  41. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { setUp: function

    ( queue ){ queue.call( function ( callbacks ){ require.undef( 'Profile' ); define( 'Profile', function (){ function Profile() {} Profile.prototype.mockTrueLol = function() { return true; }; return Profile; } ); require( [ 'mod' ], callbacks.add( function ( m ){ Mod = new m(); } ) ); } ); }, // tests here } ); })(); Wednesday, March 27, 13
  42. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { setUp: function

    ( queue ){ queue.call( function ( callbacks ){ require.undef( 'Profile' ); define( 'Profile', function (){ function Profile() {} Profile.prototype.mockTrueLol = function() { return true; }; return Profile; } ); require( [ 'mod' ], callbacks.add( function ( m ){ Mod = new m(); } ) ); } ); }, // tests here } ); })(); Wednesday, March 27, 13
  43. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { setUp: function

    ( queue ){ queue.call( function ( callbacks ){ require.undef( 'Profile' ); define( 'Profile', function (){ function Profile() {} Profile.prototype.mockTrueLol = function() { return true; }; return Profile; } ); require( [ 'mod' ], callbacks.add( function ( m ){ Mod = new m(); } ) ); } ); }, // tests here } ); })(); Wednesday, March 27, 13
  44. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { // setUp

    here tearDown: function (){ Mod = null; }, "test Mod is setup": function (){ assertTrue( Mod.hasOwnProperty( 'boom' ) ); assertTrue( Mod.boom() ); } } ); })(); Wednesday, March 27, 13
  45. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { // setUp

    here tearDown: function (){ Mod = null; }, "test Mod is setup": function (){ assertTrue( Mod.hasOwnProperty( 'boom' ) ); assertTrue( Mod.boom() ); } } ); })(); Wednesday, March 27, 13
  46. TestJSTestDriver (function (){ var Mod; AsyncTestCase( "TestJSTestDriver", { // setUp

    here tearDown: function (){ Mod = null; }, "test Mod is setup": function (){ assertTrue( Mod.hasOwnProperty( 'boom' ) ); assertTrue( Mod.boom() ); } } ); })(); // From Mod this.boom = function () { return (new Profile()).mockTrueLol(); }; Wednesday, March 27, 13