A Javascript module loader

by Henrique Filho @ Avenue Code
hfilho@avenuecode.com 

Jan 14th, 2014

AGENDA


  • Prerequisites
  • The Web Today
  • CommonJS
  • AMD
  • RequireJS
  • Question
  • Differences between Define and Require

      _____________________________________________
       A javascript module loader with Require.js

      AGENDA

      • How to Struct a project with RequireJS
        • BaseURL and Paths
        • Maps
        • Shims
        • Config
        • Structure example
      • Conclusion
      • Learn More
      • Assignment - Building a Require JS structure
        _____________________________________________
         A javascript module loader with Require.js

        PRerequisites





        Javascript intermediate/advanced

        The Web Today

        • Immediately executed factory function
          (function () {
              var $ = this.jQuery;
          
              this.myExample = function () {};
          }()); 
        • The dependencies are very weakly stated:
          • The developer needs to know the right dependency order 
          • Not scalable 
          • Can generate cyclic definitions
        _____________________________________________
         A javascript module loader with Require.js

        Common JS

        • Common JS: Javascript not just for browsers anymore
          • Javascript Standard Library

        • Develop using Common JS API's and then run the application across different JavaScript interpreters and host environments

        • Standards Examples: Binary, Console, I/O, Encoding, Modules, Packages, Unit Testing etc

        _____________________________________________
        A javascript module loader with Require.js

        COMMON JS

        What can we do? 

        • Server-side JavaScript applications (node.js)

        • Command line tools (for Browsers)

        • Desktop GUI-based applications (Wakanda)

        • Hybrid applications (Titanium, Adobe AIR)
          _____________________________________________
           A javascript module loader with Require.js

          Common JS

          Advantages on Require JS? 

          • Specify a way to load dependencies

          • Asynchronous definitions

          • Modules transportation

          • Scalable project:  Solve complexity of huge web sites  
          _____________________________________________
           A javascript module loader with Require.js

          AMD

          • AMD:  Asynchronous Module Definition

          • Modules  and its dependencies can be asynchronous loaded

          • Problems to Solve:
            • Performance
            • Usability
            • Debugging
            • Cross-Domain access
          _____________________________________________
          A javascript module loader with Require.js

          AMD

           define(id?, dependencies?, factory);
          Usage    
          // Calling define with module ID, dependency array and factory function
          define('myModule', ['dep1', 'dep2'], function (dep1, dep2) {
          
              // Define the module value by returning a value.
              return function () {};
          });
          • You should avoid naming modules yourself, and only place one module in a file while developing. 

          • For tooling and performance, a module solution needs a way to identify modules in built resources.
          _____________________________________________
          A javascript module loader with Require.js

          AMD

          • AMD solves the issues by

            • Register the factory function by calling define() 

            • Pass dependencies as an array of string values, do not grab globals

            • Only execute the factory function once all the dependencies have been loaded and executed

            • Pass the dependent modules as arguments to the factory function
          _____________________________________________
          A javascript module loader with Require.js

          Require JS 

          • Require JS:  JavaScript file and module loader

          • Uses AMD to structure your dependencies

          • Allow the developer to configure all libraries and their dependencies once and avoids cyclic dependencies 

          • Improvements: 
            • Speed (Less HTTP Requests)
            • Quality of your code
            • Structured project

          _____________________________________________
          A javascript module loader with Require.js

          Require JS

          • Project Structure using Require JS library

            • project-directory/ 
              • project.html 
                • scripts/ 
                  • main.js 
                  • require.js 
                  • helper/
                    • util.js

           
          _____________________________________________
          A javascript module loader with Require.js

          Require JS

          • Different approach to script loading than traditional <script> tags
          <!DOCTYPE html>
          <html>
              <head>
                  <title>My Sample Project</title>
                  <!-- data-main attribute tells require.js to load
                       scripts/main.js after require.js loads. -->
                  <script data-main="scripts/main" src="scripts/require.js"></script>
              </head>
              <body>
                  <h1>My Sample Project</h1>
              </body>
          </html>
              
          
          _____________________________________________
          A javascript module loader with Require.js

          REQUIRE JS

          • Inside of main.js  
            • You can use require()  to load any other scripts you need to run. 
            • This ensures a single entry point, since the data-main script you specify is loaded asynchronously.
          require(["helper/util"], function(util) {
            // This function is called when scripts/helper/util.js is loaded.
            // If util.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"
          });
          _____________________________________________
          A javascript module loader with Require.js

          REquire JS

          • AMD and RequireJS :  Simplified CommonJS wrapper
            define(function(require, exports, module) {
                    var a = require('a'),
                        b = require('b');
            
                    // Return the module value
                    return function () {};
                }
            );
          • Direct alignment of dependency name to the local variable used for that dependency
          • Uses Function.prototype.toString()  function to get the string value of the contents
          _____________________________________________
           A javascript module loader with Require.js

          Question

            What is the loading type on Require JS? 
            1. Eager loading:  you do everything when asked. Multiply two matrices. You do all the calculations.        
            2. Over-eager loading:  you try to anticipate what the user will ask for and preload it  
            3. Lazy loading:  you only do a calculation when required. Don't do any calculations until you access an element of the result matrix
            It uses LAZY LOADING to manage dependencies! 
            _____________________________________________
             A javascript module loader with Require.js

            Differences Between Require and Define

            • define()  is to create modules such as AMD
              • Well-scoped object that avoids polluting the global namespace
              • Only one module per file (name-to-file-path lookup algorithm)
              • Any return value

            • require()  is to use in call hierarchy of JS files
              • Reuse of defined modules
            _____________________________________________
            A javascript module loader with Require.js

            How to Struct a Project with Require JS

            •  Usually, you specify a module and call with require
              • What if you can't change the library lines (JQuery, Foundation)?
              • What if you want to concentrate all dependencies without calling them on <script> tag?
              • What if you want change the location of your JS files and organize your dependencies?

             
            USE A CONFIGURATION FILE
            _____________________________________________
             A javascript module loader with Require.js

            BASEURL and Paths


            • baseURL: The root path to use for all module lookups
              • If you don't specify, will attend the HTML current location

            • Paths: Path mappings for module names not found directly under baseUrl
            _____________________________________________
             A javascript module loader with Require.js

            BaseURL and PATHS

            Example 

            requirejs.config({
                baseUrl: 'js/lib',
            
                // If the module ID starts with "app",
                // load it from the js/app directory. 
                // Paths are relative to the baseUrl, 
                // and never includes a ".js" extension since
                // the paths config could be for a directory.
                paths: {
                    app: '../app'
                }
            });
            requirejs(['jquery', 'canvas', 'app/sub'],
            function ($, canvas, sub) {
                // Use either Jquery or Canvas libraries
            });
            _____________________________________________
             A javascript module loader with Require.js

            MAPS

            • Maps: Instead of loading the module with the given ID, substitute a different module ID
              • Larger projects that needs to use two different versions of the script
                requirejs.config({
                    map: {
                        '*': {
                            'foo': 'foo1.2'
                        },
                        'some/oldmodule': {
                            'foo': 'foo1.0'
                        }
                    }
                })
                
            _____________________________________________
             A javascript module loader with Require.js

            ShIMS

            • SHIM: Configure the dependencies, exports, and custom initialization for older and traditional "browser globals" scripts
              • Scripts that do not use define() to declare the dependencies and set a module value
            requirejs.config({
                shim: {
                    'jquery.colorize': {
                        deps: ['jquery'],
                        exports: 'jQuery.fn.colorize'
                    }
                }
            });
            _____________________________________________
             A javascript module loader with Require.js

            CONFIG

            • Config: Pass down the configuration to a module
            requirejs.config({
                config: {
                    'bar': {
                        size: 'large'
                    },
                    'baz': {
                        color: 'blue'
                    }
                }
            });
            
            define(function (require, exports, module) {
                // Will be the value 'large'
                var size = module.config().size;
            });
            
            _____________________________________________
             A javascript module loader with Require.js

            Structure EXAMPLE

            require.config( {
                baseUrl: "/script",
                map: {
                    '*': {
                        'jquery': 'jquery-private'
                    },
                    'jquery-private': {
                        'jquery': 'jquery'
                    }
                },
                paths: paths,
                shim: shim
            } );                

            You can create variables to be used on require.config function

              _____________________________________________
               A javascript module loader with Require.js

              Conclusion


              • Common JS is a strong comunity that provides JS standards and are growing every day
              • AMD is one of the standards used on Require JS to load dependencies asynchronous
              • Require JS helps struct, config and improve performance of your app
              • We must develop JS code based on good standards, improving performance and structure on the code
              • Structured JS is the present and future
              _____________________________________________
               A javascript module loader with Require.js

              Learn more


              _____________________________________________
               A javascript module loader with Require.js

              Assignment

              Get your multiple-choice quiz developed on Backbone and create the Require JS fundamentals, considering:

              1. You should have at least 5 libraries 
              2. At least two SHIM cases
              3. You must map the libraries
              4. Create paths as well
              5. Use at least one optimization criteria based on the optimizer page at requirejs.org (Optional Task)
              6. Explain the optimization with comments
              7. Send me the solution in a GitHub repo 
              _____________________________________________
               A javascript module loader with Require.js

              A Javascript Module Loader - RequireJS

              By Avenue Code

              A Javascript Module Loader - RequireJS

              Learn how to use AMD to struct your code and fight against infinite requests. By Henrique Filho

              • 4,352