More Related Content


Managing JavaScript Dependencies With RequireJS

  1. Managing JavaScript Dependencies with RequireJS Den Odell
  2. Libraries jQuery, Modernizr, ... Frameworks Backbone, Ember, ... Reusable Plugin and Utility Scripts jQuery plugins, TypeKit, Underscore, ... Custom Application Code
  3. <script src="/assets/js/lib/jquery-1.7.1.min.js"></script> <script src="/assets/js/lib/jquery-ui-1.8.17.custom.min.js"></script> <script src="/assets/js/global.js"></script> <script src="/assets/js/breaking-news.js"></script> <script src="/assets/js/lib/jquery.colorbox.js"></script> <script src="/assets/js/modal.js"></script> <script src=""></script> <!--[if lt IE 9]> <script src="/assets/js/lib/cssSandpaper/EventHelpers.js"></script> <script src="/assets/js/lib/cssSandpaper/cssQuery-p.js"></script> <script src="/assets/js/lib/cssSandpaper/"></script> <script src="/assets/js/lib/cssSandpaper/cssSandpaper.js"></script> <script src="/assets/js/lib/jquery-extended-selectors.js"></script> <script src="/assets/js/lib/selectivizr-min.js"></script> <![endif]--> <script src="/assets/js/lib/bgpos.js"></script> <script src=""></script> <script src="/assets/js/lib/yepnope.css-prefix.js"></script> <script src="/assets/js/feature-carousel.js"></script> <script src="/assets/js/dropdown.js"></script> <script src="/assets/js/lib/jquery.ui.selectmenu.js"></script> <script src="/assets/js/lib/jquery.selectmenu.js"></script> <script src="/assets/js/lib/swfobject.js"></script> <script src="/assets/js/flashembed.js"></script> <script src="/assets/js/lib/jquery.jqplugin.1.0.2.min.js"></script> <script src="/assets/js/audioplayer.js"></script> <script src="/assets/js/game-tray.js"></script> <script src="/assets/js/tracking.js"></script> <script src="/assets/js/lib/time-tracker.js"></script>
  4. More JavaScript typically means more complexity
  5. RequireJS Modules & Dependencies
  6. Let’s build a signup form!
  7. <!doctype html> <html> <head> <meta charset="utf-8"> <title>Mailing list</title> <link rel="stylesheet" href="styles/main.css"> </head> <body> <form action="thank-you.html" id="form" method="post"> <h1>Join our mailing list</h1> <label for="email">Enter your email address</label> <input type="text" name="email" id="email" placeholder="e.g."> <input type="submit" value="Sign up"> </form> </body> </html>
  8. Current version: 2.1.4 Support: IE6+, FF2+, Safari 3.2+, Chrome 3+, Opera 10+ Size: 5.5KB min+gzip
  9. 1. Listen for ‘submit’ event on the form 2. Validate the format of the email address provided 3. If the format is valid, allow the form to submit to the server 4. If the format is not valid, highlight the error and prevent the form submitting
  10. jQuery Validation plugin for jQuery 1. Listen for ‘submit’ event on the form 2. Validate the format of the email address provided 3. If the format is valid, allow the form to submit to the server 4. If the format is not valid, highlight the error and prevent the form submitting Main application script
  11. jQuery Validation plugin for jQuery Main application script
  12. Dependencies jQuery Validation plugin for jQuery Main application script
  13. Adding RequireJS to HTML <script src="scripts/require.js" data-main="scripts/main"></script>
  14. Defining a code module in RequireJS define( moduleName, // optional, defaults to name of file dependencies, // optional array listing dependencies function(params) { // Function to execute once dependencies have been loaded // params contains return values from the dependencies } );
  15. Example of a code module in RequireJS define(["lib/jquery-1.9.0"], function($) { // Do something with jQuery as $ });
  16. Creating a module mapping for jQuery in main.js requirejs.config({ paths: { "jquery": "lib/jquery-1.9.0” } });
  17. Extending the module mapping for jQuery in main.js requirejs.config({ paths: { "jquery": [ "", // If the CDN fails, load from this local module instead "lib/jquery-1.9.0" ] } });
  18. jQuery Validation Plug-in Module scripts/lib/validation-plugin.js
  19. scripts/lib/validation-plugin.js define(["jquery"], function($) { $.fn.isValidEmail = function() { var isValid = true, regEx = /S+@S+.S+/; this.each(function() { if (!regEx.test(this.value)) { isValid = false; } }); return isValid; }; });
  20. Main application script scripts/lib/main.js
  21. scripts/lib/main.js require(["jquery", "lib/validation-plugin"], function($) { var $form = $("#form”), $email = $("#email"); $form.on("submit", function(e) { e.preventDefault(); if ($email.isValidEmail()) { $form.get(0).submit(); } else { $email.addClass("error").focus(); } }); $email.on("keyup", function() { $email.removeClass("error"); }); });
  22. Improving page load performance...
  23. scripts/lib/main.js require(["jquery"], function($) { var $form = $("#form"), $email = $("#email"); $form.on("submit", function(e) { e.preventDefault(); require(["lib/validation-plugin"], function() { if ($email.isValidEmail()) { $form.get(0).submit(); } else { $email.addClass("error").focus(); } }); }); $email.on("keyup", function() { $email.removeClass("error"); }); });
  24. What else can RequireJS do?
  25. Some Useful Plug-ins i18n text handlebars font cache
  26. Thank You

Editor's Notes

  1. Learn how to manage and dynamically load JavaScript code files and their dependencies in a robust, scalable way within your large web sites and applications using the RequireJS library.
  2. JavaScript code is usually divided into layers, each building upon the last becoming more application-specific as it goes along.
  3. Example of script tags used in a real site. Order is important such that plugins are loaded after libraries, etc. and variables are present and loaded before they ’ re used.
  4. If I wanted to know which of those files are safe to remove without affecting other files, how could I know? Where would I add in a new file - at the bottom?
  5. RequireJS is a JavaScript implementation of the AMD API (Asynchronous Module Definition), a language-agnostic unified way of associating a block of code ( “ module ” ) with the code it relies upon ( “ dependencies ” ). Gaining a lot of traction in the industry. Used on sites for the BBC, Hallmark, Etsy, and Instagram.
  6. BBC use it across their sites - here ’ s their documentation site for their developers.
  7. I ’ m going to talk you through building this simple newsletter signup form, managing the JavaScript code with RequireJS.
  8. Here ’ s how it ’ s going to look - if you use my CSS :)
  9. Here ’ s the base HTML code for this page. There ’ s a form that submits to a thank-you.html page, which we ’ re assuming will save the given email address into a database somewhere.
  10. Download RequireJS from the site. Good browser support Small footprint.
  11. Define what our page will do so we can plan the JavaScript code we ’ ll need.
  12. Which files will we need?
  13. 3 files required. A library, a plugin, and our main application script.
  14. Dependencies are marked with arrows. Plugin only dependent on jQuery. Main application script dependent on plugin and jQuery.
  15. Let ’ s organise this into a file structure. RequireJS goes in the root of the ‘ scripts ’ folder. Let ’ s create our 3 JavaScript files and place them into this folder. I place the main application script at the same level as RequireJS and any 3rd party or reusable scripts (here, jQuery and the plugin script) I ’ m placing together into a ‘ lib ’ folder.
  16. We can go back to our HTML page and add in a &lt;script&gt; reference to RequireJS. When it initialises, RequireJS looks for a data-main attribute on its &lt;script&gt; tag. If it finds it, it will asynchronously load in the file referenced within it. RequireJS assumes a .js file extension by default, so we can safely leave this out.
  17. Reusable blocks of code or “ modules ” are defined with RequireJS using its ‘ define ’ method, which follows this pattern. All you NEED is the code block wrapped in a function. You SHOULD pass an array of dependency script modules that this code needs to function correctly. You MAY give an optional name, though the default name is taken from the location and name of the file. This codifies the relationship between a code block and its dependencies, and RequireJS contains code to ensure no code block gets executed before its listed dependencies are loaded first.
  18. Example of a code module that has a dependency on jQuery. We reference the dependency based on its location relative to the RequireJS script itself. We don ’ t need the .js file extension. Any values returned by dependencies are provided as input parameters to the code block function, in order. This ensures encapsulation of code and dependency. jQuery contains code to register itself as a RequireJS module, so we don ’ t need to do anything special with jQuery in order for this to work.
  19. We don ’ t always want to have to write our dependencies on jQuery to include the specific version number within it, but jQuery file naming convention has this version number in its name. We can add a configuration object to setup RequireJS at the top of our main application script (main.js) to create a module name-value mapping so we can refer to just ‘ jquery ’ in our dependency arrays and it will be mapped to the specific version of jQuery we specify. We only need update our reference to the jQuery file in one place should we wish to upgrade it to a version of jQuery with a different file name.
  20. Many devs want to use jQuery from a CDN. RequireJS supports this as dependencies can be accessed directly from external locations just by using the URL.
  21. Simpler to add this into a module name/value mapping so as not to duplicate the URL across your code base. Using an ARRAY means that we can provide a list of backup files in case the external URL fails to load.
  22. Let ’ s write our jQuery validation plug-in module, using RequireJS to codify our dependencies.
  23. The module name is taken from the file name and its position relative to the RequireJS script. This module will be named lib/validation-plugin.js
  24. We ’ ve already written the configuration at the top of our main application script file to setup a module name/value mapping for jQuery. Now let ’ s extend our main application script, using RequireJS to codify our dependencies.
  25. So far we ’ ve been using the ‘ define ’ method of RequireJS to configure modules for later use. Here we ’ re going to use the ‘ require ’ method instead. It has the same function pattern as ‘ define ’ , the only difference is in the meaning behind its use. ‘ require ’ should only be used where you want to immediately execute some code, based on dependencies, and which should not be stored in a module for reuse later. It ’ s this reusability that ’ s the difference between whether you use ‘ define ’ or ‘ require ’ . The validator plugin extends jQuery directly so is not provided as an input parameter to the code block function.
  26. We ’ re loading in jQuery and the plugin on page load right now. RequireJS loads in main.js which immediately loads in the two dependencies. In actual fact, we don ’ t need that plugin until the user attempts to submit the form. We can take advantage of RequireJS ’ asynchronous file loading capability by rewriting our code.
  27. Now I only load jQuery at the start to configure my form submit handler. I wait until that handler is called, then I call ‘ require ’ to load in the validation plugin on-demand in order to validate the form. If this plugin were large, there might be a delay loading the file before validating the form which isn ’ t a good user experience. Consider adjusting the code to load in the plugin when the user focuses into the input box instead to improve reaction time when the user submits the form. If the user never submits the form, the code is never downloaded.
  28. Waterfall for script loading in our updated code. Notice how the plugin loads much later, when the user actually submits the form.
  29. Load plain JavaScript objects data as modules for use throughout your page. Load that data from URLs using JSON-P (callback function should be specified as = define) Numerous configuration options including options for configuring how to pull in external scripts (like Backbone) that don ’ t support RequireJS by default, allowing them to be used. Optimisation as part of a build process - scans files and groups together dependencies used together to minimise HTTP requests, and minifies files for deployment
  30. i18n - allows you to configure ‘ locale ’ parameter and loads in files dynamically based on that text - allows text files to be loaded in - useful for blocks of HTML or plain text to be used as a string handlebars - allows handlebars templates to be used as dependencies in modules. Passed through as function to which you pass your data and it renders a string you can place on your page using innerHTML font - uses Google WebFonts loader API to specify font files as dependencies in your code cache - stores downloaded modules in localStorage so they don ’ t need to be redownloaded on page refreshes