write better javascript with requirejs. what is requirejs?
TRANSCRIPT
Write Better Javascript
with RequireJS
What is RequireJS?
What is RequireJS?
from requirejs.org,
"RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Rhino and Node. Using a modular script loader like RequireJS will improve the speed and quality of your code."
What is RequireJS?
• Async Script Loader• 12 k• Very actively developed• Well documented• new BSD / MIT
Why use a tool like RequireJS?
Why use a tool like RequireJS?
Because Javascript Sucks. Also, user side scripting makes things worse.
JS sucks.├── local_settings.py├── manage.py├── datacleaning│ ├── admin.py│ ├── forms.py│ ├── migrations│ │ └── 0001_initial.py│ ├── models.py│ ├── tests.py│ ├── urls.py│ └── views.py├── journals│ ├── admin.py│ ├── fixtures│ │ └── 20101124_5.03.json│ ├── forms.py│ ├── migrations│ │ ├── 0001_initial.py│ │ ├── 0002_auto__images__add_entry.py│ │ └── 0003_loading_test_journal_entries.py│ ├── models.py│ ├── tests.py│ ├── urls.py│ └── views.py├── lib│ ├── context_processors.py│ ├── string_processors.py│ ├── template.py│ ├── urlmiddleware.py│ ├── user.py│ └── widgets.py
├── parks│ ├── admin.py│ ├── fixtures│ │ ├── initial_featurecategories.json│ │ └── train_examples.json│ ├── forms.py│ ├── importers│ │ └── recdata.py│ ├── management│ │ ├── commands│ │ │ ├── exportoregonparks.py│ │ │ ├── importparks.py│ │ │ ├── ......
JS sucks.├── ckeditor│ ├── ckeditor.js│ ├── contents.css│ ├── lang│ │ ├── af.js│ │ ├── ar.js│ │ ├── bg.js│ │ ├── bn.js│ │ ├── bs.js│ │ ├── ca.js│ │ ├── cs.js│ │ ├── cy.js│ │ ├── da.js│ │ ├── de.js│ │ ├── el.js│ │ ├── en-au.js│ │ ├── en-ca.js│ │ ├── en-gb.js│ │ ├── en.js│ │ ├── eo.js│ │ ├── es.js│ │ ├── et.js│ │ ├── eu.js│ │ ├── fa.js│ │ ├── fi.js│ │ ├── fo.js│ │ ├── fr-ca.js│ │ ├── fr.js│ │ ├── gl.js│ │ ├── gu.js│ │ ├── he.js
│ │ ├── hi.js│ │ ├── hr.js│ │ ├── hu.js│ │ ├── is.js│ │ ├── it.js│ │ ├── ja.js│ │ ├── ka.js│ │ ├── km.js│ │ ├── ko.js│ │ ├── _languages.js│ │ ├── lt.js│ │ ├── lv.js│ │ ├── mn.js│ │ ├── ms.js│ │ ├── nb.js│ │ ├── nl.js│ │ ├── no.js│ │ ├── pl.js│ │ ├── pt-br.js│ │ ├── pt.js│ │ ├── ro.js│ │ ├── ru.js│ │ ├── sk.js│ │ ├── sl.js│ │ ├── sr.js│ │ ├── sr-latn.js│ │ ├── sv.js│ │ ├── th.js│ │ ├── _trans.txt│ │ ├── tr.js│ │ ├── uk.js│ │ ├── vi.js│ │ ├── zh-cn.js│ │ └── zh.js│ ├── plugins│ │ └── styles│ │ └── styles
│ │ └── default.js│ ├── skins│ │ └── kama│ │ ├── dialog.css│ │ ├── editor.css│ │ ├── icons.png│ │ ├── icons_rtl.png│ │ ├── images│ │ │ ├── dialog_sides.gif│ │ │ ├── dialog_sides.png│ │ │ ├── dialog_sides_rtl.png│ │ │ ├── mini.gif│ │ │ ├── noimage.png│ │ │ ├── sprites_ie6.png│ │ │ ├── sprites.png│ │ │ └── toolbar_start.gif│ │ ├── skin.js│ │ └── templates.css│ └── SQRLY_TEAM_PLEASE_README__LICENSE├── elevationservice_eg_google.js├── jquery.form.js├── jquery.history.js├── jqueryplugins│ ├── jquery.address-1.3.js│ └── jquery.simplemodal-1.3.min.js├── markers.js├── pages│ ├── add-park.js│ ├── datacleaning.js│ └── park-detail.js├── park-ratings.js├── polylinearray_eg_google.js├── star-rating.js└── star-rating-metadata.js
JS sucks1. code is too long2. just a little code from somewhere else3. copy and paste4. goto: 1
JS sucks<head> <script src="foo.js" type="text/javascript"></script> <script src="bar.js" type="text/javascript"></script> <script src="baz.js" type="text/javascript"></script> <script src="biff.js" type="text/javascript"></script> <script src="bop.js" type="text/javascript"></script> <script src="foo.js" type="text/javascript"></script> <script src="bar.js" type="text/javascript"></script> <script src="baz.js" type="text/javascript"></script> <script src="biff.js" type="text/javascript"></script> <script src="bop.js" type="text/javascript"></script> <script src="foo.js" type="text/javascript"></script> <script src="bar.js" type="text/javascript"></script> <script src="baz.js" type="text/javascript"></script> <script src="biff.js" type="text/javascript"></script> <script src="bop.js" type="text/javascript"></script>...</head>
RequireJS makes JS suck less• Help you make your code more modular• manages script loading for you• build and compress your code
(oh, and other stuff too...)
Making code more modular
So what's the code look like?
Loading from the page<script data-main="pages/profile.js" src="scripts/require.js"></script> <script src="scripts/require.js"></script>require(["pages/profile"]);
Loading from the pagerequire(["pages/profile"], function(Profile) { ...do stuff... require.ready() { ...do more stuff... Profile.init(INSERT_SOMETHING_HERE); });});
Defining a Moduledefine(["foo", "baz", "x"], function(Foo, Baz) { ...do stuff... return { init: function(data) { container = data; }, do_something: some_internal_method }});
Loading - production vs dev
Loading - production vs dev
Loading - production vs dev
Let's look at an example
require("map", function(Map) { ... map file is loaded ... });
require("map", function(Map) { ... map file is loaded ... });
require("map", function(Map) { ... map file is loaded ... });
define(["gm", "foo"], function(GM, Foo) { ... set up js ... return {};});
define(["gm", "foo"], function(GM, Foo) { ... set up js ... return {};});
require("map", function(Map) { ... map file is loaded ... });
define(["gm", "foo"], function(GM, Foo) { ... set up js ... return {};});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { ... page is ready ... }); });
define(["gm", "foo"], function(GM, Foo) { ... set up js ... return {};});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init(); }); });
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init(); }); });
define(["gm", "foo"], function(GM, Foo) { ... set up js ... return {};});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init(); }); });
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return {};});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init(); }); });
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init };});
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init };});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init(); }); });
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init };});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init("div_id"); }); });
That's it.
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init("div_id"); });});
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init };});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init("div_id"); });});
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init("div_id"); }); });
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init("div_id"); a = Map.m; });});
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init("div_id"); a = Map.m; Map.init("another_div_id"); b = Map.m; });});
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
require("map", function(Map) { ... map file is loaded ... require.ready(function() { Map.init("div_id"); a = Map.m; Map.init("another_div_id"); b = Map.m; });});
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
require("map", function(Map) { require.ready(function() { Map.init("div_id"); });});
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
require("map", function(Map) { require.ready(function() { Map.init("div_id"); a = Map; });});
require("map", function(Map) { require.ready(function() { Map.init("another_div_id"); b = Map; });});
// a === b
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
require({context:"abc"},"map", function(Map) { require.ready(function() { Map.init("div_id"); a = Map.m; });});
require({context:"xyz"},"map", function(Map) { require.ready(function() { Map.init("another_div_id"); b = Map.m; });});
// a.m !== b.m
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
require("map", function(Map) { require.ready(function() { a = new Map.init("div_id"); b = new Map.init("another_id"); });});
require("map", function(Map) { require.ready(function() { a = new Map.init("div_id"); b = new Map.init("another_id"); });});
define(["gm", "foo"], function(GM, Foo) { var m; function init(id) { m = GM.create(id); } return { init: init, map: m };});
require("map", function(Map) { require.ready(function() { a = new Map.init("div_id"); b = new Map.init("another_id"); });});
define(["gm", "foo"], function(GM, Foo) { function init(id) { var that = {}; that.m = GM.create(id); return that; } return { init: init, map: m };});
require("map", function(Map) { require.ready(function() { a = new Map.init("div_id"); b = new Map.init("another_id"); });});
define(["gm", "foo"], function(GM, Foo) { function init(id) { var that = {}; that.m = GM.create(id); return that; } return { init: init };});
require("map", function(Map) { require.ready(function() { a = new Map.init("div_id"); b = new Map.init("another_id"); });});
define(["gm", "foo"], function(GM, Foo) { function init(id) { var that = {}; that.m = GM.create(id); return that; } return init;});
require("map", function(Map) { require.ready(function() { a = new Map.init("div_id"); b = new Map.init("another_id"); });});
define(["gm", "foo"], function(GM, Foo) { return function(id) { var that = {}; that.m = GM.create(id); return that; }});
define(["gm", "foo"], function(GM, Foo) { return function(id) { var that = {}; that.m = GM.create(id); return that; }});
require("map", function(Map) { require.ready(function() { a = new Map.init("div_id"); b = new Map.init("another_id"); });});
define(["gm", "foo"], function(GM, Foo) { return function(id) { var that = {}; that.m = GM.create(id); return that; }});
require("map", function(Map) { require.ready(function() { a = new Map("div_id"); b = new Map("another_id"); });});
Plugins
define([ "foo!bar" ], function() { ... });
When order matters...define(["order!foo", "order!bar", "order!baz"], function(Foo, Bar, Baz) { ...});
Loading a Templatedefine(["resig_micro", "text!bar"], function(Resig, BarTmpl) { ... data = { foo: 1, bar: "once upon a time..." }; rendered = Resig(BarTmpl, data); ...});
Write in CoffeeScriptdefine(["cs!foo"], function(Foo) { ...});
Loading CSSdefine(["css!foo"], function() { ...});
function loadCss(url) { var link = document.createElement("link"); link.type = "text/css"; link.rel = "stylesheet"; link.href = url; document.getElementsByTagName("head") [0].appendChild(link);}
Loading Offsite contentdefine(["foo", "https://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"], function(Foo, $) { ...});
Loading Google Maps, etc.define(["async!http://maps.google.com/maps/api/js? sensor=false!callback"], function() { return google.maps;})
Getting specific with your settingsrequire({ baseUrl: "/another/path", paths: { "some": "some/v1.0" }, waitSeconds: 15, locale: "fr-fr", context: "foo" }, ["some/module"], function(someModule) {...
// some/v1.0/module.js
Compiling / Minifying./requirejs/build/build.sh app.build.js
• app.build.js• dev/
o your_stuff.js• requirejs/
o require.js source files• built/
o destination directory
app.build.js({ appDir: "dev/", baseUrl: "scripts", dir: "built/", optimize: "uglify", ... paths? priority? ...})
github.com/jrburke/r.js/blob/master/build/example.build.js
Thanks
Chris Pitzerrequirejs.org
#requirejs on irc.freenode.net