foo! - Lo

advertisement
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 sucks
1. code is too long
2. just a little code from somewhere else
3. copy and paste
4. goto: 1
JS sucks
<head>
<script
<script
<script
<script
<script
<script
<script
<script
<script
<script
<script
<script
<script
<script
<script
...
</head>
src="foo.js" type="text/javascript"></script>
src="bar.js" type="text/javascript"></script>
src="baz.js" type="text/javascript"></script>
src="biff.js" type="text/javascript"></script>
src="bop.js" type="text/javascript"></script>
src="foo.js" type="text/javascript"></script>
src="bar.js" type="text/javascript"></script>
src="baz.js" type="text/javascript"></script>
src="biff.js" type="text/javascript"></script>
src="bop.js" type="text/javascript"></script>
src="foo.js" type="text/javascript"></script>
src="bar.js" type="text/javascript"></script>
src="baz.js" type="text/javascript"></script>
src="biff.js" type="text/javascript"></script>
src="bop.js" type="text/javascript"></script>
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 page
require(["pages/profile"], function(Profile) {
...do stuff...
require.ready() {
...do more stuff...
Profile.init(INSERT_SOMETHING_HERE);
});
});
Defining a Module
define(["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 {};
});
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();
});
});
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) {
... 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
};
});
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");
});
});
define(["gm", "foo"], function(GM, Foo) {
var m;
function init(id) {
m = GM.create(id);
}
return {
init: init
};
});
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
};
});
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");
});
});
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) {
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;
}
});
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");
});
});
define(["gm", "foo"], function(GM, Foo) {
return function(id) {
var that = {};
that.m = GM.create(id);
return that;
}
});
Plugins
define([ "foo!bar" ], function() { ... });
When order matters...
define(["order!foo", "order!bar", "order!baz"],
function(Foo, Bar, Baz) {
...
});
Loading a Template
define(["resig_micro", "text!bar"], function(Resig, BarTmpl) {
...
data = { foo: 1,
bar: "once upon a time..." };
rendered = Resig(BarTmpl, data);
...
});
Write in CoffeeScript
define(["cs!foo"], function(Foo) {
...
});
Loading CSS
define(["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 content
define(["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 settings
require({
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 Pitzer
requirejs.org
#requirejs on irc.freenode.net
Download