Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Using RequireJS for Modular JavaScript Code


Published on

Slides and notes from my lightning talk at Scandinavian Developer Conference, April 2012 in Gothenburg.

Published in: Technology
  • Be the first to comment

Using RequireJS for Modular JavaScript Code

  1. 1. RequireJS for modular JavaScript code this presentation is about Require JS. * why use it * How it works Thomas Lundström, Softhouse * How it’s used * How to start using it @thomaslundstrom Let’s start with some of the problems I’ve seen (and been guilty of) in web apps that use JavaScript during my April 16, 2012 tenure as a consultant Scandinavian Developer Conference
  2. 2. JS is big Even if you don’t run a JS framework, just “some HTML and JS”, you often have rather large JS files - quite often spaghetti-like with a large number of functions calling each other. New JS-heavy apps often use one or more of the JS Frameworks that exist today, e.g. Backbone, Knockout, Ember, SproutCore etc, making it more and more important to think about componentizing and structuring your code.• Web-apps today contain large amounts of JavaScript
  3. 3. Dependencymanagement is hard Top-level functions in the global namespace often lead to circular dependencies (which aren’t easily spotted - you basically need to wade through the JS code to find all dependencies). 2 Files - 5 different functions calling each other
  4. 4. Dev/deploy conflict Requirements conflict bet ween development and deployment: Devs want small discrete files since it’s easier to debug and test small units. Additionally, using large files with a script tag doesn’t scale in larger apps with large number of developers: e.g. merge hell in version control Deployment should be done on large files since we don’t want the browser to load lots of files - the latency gives us slowly loaded pages
  5. 5. Require tries to solve the problems with growing JS code bases by introducing the “module” abstraction. In its core, modules exposes an interface and has dependencies. You ask RequireJS for a module, and RequireJS traces and instantiates its dependencies (including transitive dependencies) before instantiating the module you wish to use. Why modules? Modules are (or, should be) small => easy to understand => easy to change + easy to testRequireJS
  6. 6. Define This is a quite standard logger that every site needs. This one works with IE (where console.log throws an error if the development tools aren’t enabled). You use the define function to define a module. The API is called AMD - asyncronous module definition. The file name (modules/logger) is the name of the module. Dependencies are stated in the array in the beginning of the function call. This one has no dependencies - the array is empty The function @ param2 is a factory function that’s executed when we instantiate this module The returned object is fed as an argument to the module requiring this module as a dependency. Here, the factory returns an object containing only one function: log (msg). Note: we don’t clobber the global scope since everything in this module is hidden by the scope of the anonymous function.
  7. 7. Define A module that takes t wo other modules as dependencies. The names of the dependencies are the module names, e.g. “modules/logger” from the previous slide The returned objects from the dependencies are injected into our factory function. (Logger returns an object containing the log function.)
  8. 8. Require The require() call is the main entry point to the modules defined by the define() call. The first argument is an array containing all module names we wish to load. The anonymous function is a callback that’s called after the required modules and their dependencies have been loaded. The args to the function is the required modules.
  9. 9. End result The different modules in the diagram have defined dependencies, a clean interface (i.e. the returned object) and are easy to unit-test.
  10. 10. Firebug An image from firebug with the modules from the previous slide. Current problem: we have too many files, leading to slow loading times. Require JS optimizer to the rescue!
  11. 11. Firebug (optimized) The RequireJS optimizer compiles a top-level module (in our case, “module1.js”) and its dependencies (recursively) together into one file. The file is also uglified (see example below). -> One file per top-level module with minimal footprint
  12. 12. legacy JS files = large, spaghetti, global scopeIntroducing RequireJS with legacy JS files
  13. 13. Single JS file If you are using only one js file (or you have no cross-refs bet ween different stand-alone js files): you’re in luck.• One file = one module This requires that no-one accesses the JS functions that are defined in the single JS file (e.g. literal click handlers on buttons/links etc). It’s rather uncommon, sadly. BUT: If we have this we can rather easily introduce RequireJS in the application. Let the entire file be your module as a start. Then, refactor small pieces of functionality into sub-modules as you go along.
  14. 14. Interconnected filesThe problem here is the circular dependency bet ween file A and B at: file_a_2() -> file_b_2() -> file_a_1().This state is rather common. There is no super-simple solution if we have these circular dependencies bet weenfile A and B.This issue doesn’t only occur if we have different functions calling each other. We could also have one file anda literal click handler on a button/a-link with the function name stated in HTML.To start solving this issue, we can modularize and export only the globally used functions. (In next slide.)
  15. 15. Interconnected filesin the t wo highlighted rows we export the cross-ref’d functions to the global namespace. These global functions are then called atlines 9 and 13 in file A and B respectively.The next step is to refactor out file_a_1 and file_b_2 into separate modules. This is left as an excercise to the reader. The reason for extracting this is that we don’t want to use circular references bet ween modules.
  16. 16. Thanks! RequireJS is Open Source, dev @ GitHub I’ll post this presentation + some samples at my• blog.• Thomas Lundström, Softhouse•• @thomaslundstrom•