Modular JavaScript with
AMD and RequireJS

Jarrod Overson

Modular JavaScript and AMD

Who Am I?

Jarrod Overson

  1. Web Junkie

  2. Modularity Addict

  3. Lover of neat stuff

Why are we here?

JavaScript is going through some growing pains

How do you organize your code now?

  1. Namespaces?

  1. Namespaces?

    yourblog.js

    account.js

    posts.js

    comments.js

    index.html

  1. Globally Accessible Modules?

  1. Globally Accessible Modules?

  1. Globally Accessible Modules?

  1. Globally Accessible Modules?

  1. One Massive File?

Your code is already trying to be modular.

But you're walking a thin line balancing...

  1. Simplicity
  2. Reusability
  3. Resource management
  4. Dependency management
  5. and more...

...and you shouldn't have to sacrifice this much

Why AMD?

If there already are solutions, and even more that have fizzled, What's different with AMD?

AMD

Asynchronous Module Definition

  1. AMD is not a library.
  2. AMD is a set of rules that define what your code means.

With AMD...

You still get to choose the best tool for the job

You buy into a small set of transferable rules

You buy into a philosophical module

To the code!

define() function

The specification defines a single function "define" that is available as a free variable or a global variable.

Using an ID is not recommended unless necessary.

The Module Pattern, a recap

see Essential JS - Module Pattern by Addy Osmani

TestModule.js

Module Pattern in AMD style

var testModule = (function(){
  var counter = 0;
  return {
    incrementCounter: function() {
      console.log(counter++);
    },
    resetCounter: function() {
      console.log('counter value prior to reset:' + counter);
      counter = 0;
    }
  };
})();

testModule.incrementCounter();
testModule.incrementCounter();
testModule.resetCounter();

Module Pattern in AMD style

var testModule = (function(){
  var counter = 0;
  return {
    incrementCounter: function() {
      console.log(counter++);
    },
    resetCounter: function() {
      console.log('counter value prior to reset:' + counter);
      counter = 0;
    }
  };
})();

testModule.incrementCounter();
testModule.incrementCounter();
testModule.resetCounter();

Module Pattern in AMD style

                  function(){
  var counter = 0;
  return {
    incrementCounter: function() {
      console.log(counter++);
    },
    resetCounter: function() {
      console.log('counter value prior to reset:' + counter);
      counter = 0;
    }
  };
}



  

Module Pattern in AMD style

                  function(){
  var counter = 0;
  return {
    incrementCounter: function() {
      console.log(counter++);
    },
    resetCounter: function() {
      console.log('counter value prior to reset:' + counter);
      counter = 0;
    }
  };
}



  

Module Pattern in AMD style

define(           function(){
  var counter = 0;
  return {
    incrementCounter: function() {
      console.log(counter++);
    },
    resetCounter: function() {
      console.log('counter value prior to reset:' + counter);
      counter = 0;
    }
  };
});

/* et voila */

  

AMD module with dependencies

define(['TestModule'], function(TestModule) {
    TestModule.incrementCounter();
    return { /* stuff */ }
});

AMD module with a Class

define(function() {
  function Shape(x,y) {
    this.x = x;
    this.y = y;
  }
  Shape.prototype.move = function(x,y) {
    this.x += x;
    this.y += y;
  }
  return Shape
});

AMD module with a Class cont.

define(['Shape'],function(Shape) {
  function Circle(x,y,radius) {
    Shape.call(this,x,y);
    this.radius = radius;
  }

  Circle.prototype = new Shape();
  Circle.prototype.constructor = Circle;

  return Circle;
});

AMD module as object data

define({
  'foo' : 42,
  'bar' : Math.PI
});

Think JSONP with the callback always being define()

AMD module with plugins

CoffeeScript

define(['cs!coffeescriptModule.cs'],function(csModule){
  csModule.foo(); // ready to use in JavaScript
})

Some common plugins

Or write your own

AMD defines how to write the modules

Not how to load or use them

AMD defines how to write the modules

Not how to load or use them

require.js - requirejs.org

AMD defines how to write the modules

Not how to load or use them

curl.js - github

Application structure

project-root/
  index.html
  scripts/
    lib/
      require.js
    dep1.js
    dep2.js
    main.js

index.html

<html>
  <head>
    <script src="scripts/lib/require.js"></script>
  </head>
  <body>
  </body>
</html>

index.html

<html>
  <head>
    <script data-main="scripts/main.js"
            src="scripts/lib/require.js"></script>
  </head>
  <body>
  </body>
</html>

Instruct require.js to run scripts/main.js on load

index.html

<html>
  <head>
    <script data-main="scripts/main.js"
            src="scripts/lib/require.js"></script>
  </head>
  <body>
  </body>
</html>

The scripts/ directory will be the baseUrl for our modules

main.js

require(['dep1','dep2'],function(dep1,dep2){
  // And away we go!
})

Optimization and Building

$ npm install requirejs
$ r.js -o app.build.js

where app.build.js is your build configuration file

({
  baseUrl: ".",
  name: "main",
  out: "main-built.js",
  modules: [
    {
      name: "main"
    }
  ]
})

r.js can also copy your source tree into a new build dir, and minify and build your CSS.

AMD support/use in the wild

Loaders

Modules/Software

Where to go from here?

Start coding immediately!

Read!

<nutshell>require.js & AMD</nutshell>

There is much more! Stay up to date and start coding now!

AMD/RequireJS is not a silver bullet, but it gets us to a better place

People to follow

Thank you!

- Jarrod Overson / jsoverson

The presentation thanks Deck.js, jQuery sparklines, Codemirror plugin for Deck.js,

/

#