Jakub Elżbieciak
Software Developer @XSolve
t: @jelzbieciak
m: jelz@post.pl
<script src="js/jquery.js"></script>
<script src="js/jquery.payment.js"></script>
<script src="js/jquery.ui.js"></script>
<script src="js/underscore.js"></script>
<script src="js/backbone.js"></script>
<script src="js/app/main-view.js"></script>
<script src="js/app/order-view.js"></script>
<script src="js/app/confirm-view.js"></script>
<script src="js/app/router.js"></script>
<script src="js/app/custom-logic.js"></script>
<script src="js/app/user-collection.js"></script>
<script src="js/startup.js"></script>
Looks pretty organized, huh? :)
define([
// define module's dependencies:
'jquery', 'underscore', 'router', 'some/custom/module'
], function (
// give them local names:
$, _, Router, CustomModule
) {
// ... do someting interesting here ...
// export some useful things outside:
return {
fn1: function() { y(); },
start: function () { x(); }
};
});
Assume that previous example was saved as app.js
require(['jquery', 'app'], function ($, app) {
$(function () {
app.start();
});
});
Assume that previous example was saved as main.js
<script
src="bower_components/requirejs/require.js"
data-main="app/main.js"
></script>
...to ideas and possibilities
Code is only an illustration
10 complete examples to take a look at on GitHub
...that depends on one module
define(['jquery'], function ($) {
// use $ here...
});
We also need underscore and moment!
define([
'jquery', 'underscore', 'moment'
], function (
$, _, moment
) {
// use $, _, moment here...
});
define([
'backbone', 'app', 'moment',
'view/NavView', 'view/SwitchView',
'view/DayView', 'view/WeekView', 'view/MonthView'
], function (
Backbone, app, moment,
NavView, SwitchView,
DayView, WeekView, MonthView
) {
// ...
});
define(function (require) {
var _ = require('underscore'),
$ = require('jquery'),
moment = require('moment');
var updateClock = _.throttle(function () {
var t = moment().format('H:mm:ss');
$('#clock2').text(t);
}, 1000);
return {
start: function () {
updateClock();
setInterval(updateClock, 990);
}
};
});
Pair variable with require()
call – code gets much cleaner
Remember module loader on the bottom of your HTML?
<script
src="bower_components/requirejs/require.js"
data-main="app/main.js"
></script>
RequireJS is only an inplementation and can be replaced by any other inplementation. Let's use Cajon
<script
src="node_modules/cajon/cajon.js"
data-main="app/main.js"
></script>
(as you can see, Cajon is installed using npm)
What else to say – Cajon eliminates need of define()
calls totally
var _ = require('underscore'),
$ = require('jquery'),
moment = require('moment');
var updateClock = _.throttle(function () {
var t = moment().format('H:mm:ss');
$('#clock').text(t);
}, 1000);
module.exports = {
start: function () {
updateClock();
setInterval(updateClock, 990);
}
};
This code can be loaded and executed without any troubles
require()
calls load dependenciesmodule.exports
allows to expose module's API
// alice.js file
define(['cat'], function (cat) {
return {
name: 'Alice',
haveWhat: function () {
console.log('I\'m ' + this.name);
console.log('I have ' + cat.name);
}
}
});
And vice versa
// cat.js file
define(['alice'], function (alice) {
return {
name: 'Cat George',
haveWhat: function () {
console.log('I\'m ' + this.name);
console.log('I have ' + alice.name);
}
};
});
madge --format amd --image dep-graph.png .
(graph healthier than previous one)
define(function (require, exports, module) {
var alice = require('alice');
exports.name = 'Cat George';
exports.haveWhat = function () {
console.log('I\'m ' + this.name);
console.log('I have ' + alice.name);
};
exports.sayWhatAliceSays = function () {
console.log('She says:');
alice.haveWhat();
};
});
exports
is used on both sides, then modules get valid references, that will be loaded, when module function returnsr.js -o app/build.js
({
baseUrl: '.',
mainConfigFile: 'main.js',
name: '../bower_components/requirejs/require',
include: 'main',
wrap: true,
out: '../built/main.built.require.js'
})
({
baseUrl: '.',
mainConfigFile: 'main.js',
name: '../bower_components/almond/almond',
include: 'main',
wrap: true,
out: '../built/main.built.almond.js'
})
plugin!dependency
<script>
tags is messy and hard to maintain (especially when you do hundreds of atomic views)
var templates = [
require('text!tpl/layout.html'),
require('text!tpl/content.html'),
require('text!tpl/menu.html')
];
_.each(templates, function (markup) {
$(markup).appendTo($('body'));
});
Now, when editing, you know where to search each template
But don't forget about optimization!
Define root (default) translations
// file "nls/labels.js"
define({
root: {
change_lang: 'Change language',
show_message: 'Show message'
},
pl: true
});
pl
key indicates that there is also translation for another language
// in file "nls/pl/labels.js"
define({
change_lang: 'Zmień język',
show_message: 'Pokaż wiadomość'
});
require('i18n!nls/labels')
, correct translations will be loadedlocale
key in configRead from localStorage when building config:
require.config({
config: {
i18n: {
locale: localStorage.getItem('locale') || 'en'
}
}
});
Read, swap, set, reload on chosen event:
$('#toggle').on('click', function () {
var current = localStorage.getItem('locale') || 'en';
var next = 'en' === current ? 'pl' : 'en';
localStorage.setItem('locale', next);
window.location.reload();
});
You should:
jquery-require.js
files
require.config({
paths: {
jquery: (function () {
var local = window.location.host.match(/localhost/);
var paths = [
'http://codeorigin.jquery.com/jquery-2.0.3.min',
'../bower_components/jquery/jquery'];
return local ? paths.reverse() : paths;
}())
}
});
It simply handles first three points
require.config({
paths: {
jquery: '../bower_components/jquery/jquery'
'jquery.payment': '../bower_components/jquery.payment/lib/jquery.payment'
},
shim: {
'jquery.payment': ['jquery']
}
});
When writing open-source plugins, keep jQuery styleguide.
When writing for you or client, use AMD.
define(function (require) {
var $ = require('jquery');
$.fn.fart = function () {
alert('fart!');
};
});
(very stupid jQuery plugin, AMD style)
When in base directory (it defines util and widget packages in corresponding subdirectories, with main files named main.js
)
require.config({
packages: ['util', 'widget']
});
Package config options used
require.config({
packages: ['widget', {
main: 'index',
location: '../vendor/widget'
}]
});
Calling require('widget/input')
will load ../vendor/widget/input.js
, calling require('widget')
will load ../vendor/widget/index.js
)
define(function (require) {
return {
date: require('widget/date'),
input: require('widget/input')
};
});
(keep in mind that loading index loads all its modules)
Create package for Bootstrap
require.config({
paths: {
jquery: '../bower_components/jquery/jquery'
},
packages: [
'bootstrap', {
name: 'bootstrap',
location: '../bower_components/bootstrap/js'
}
],
shim: {
bootstrap: ['jquery']
}
});
Now it's under your fingers
define([
'bootstrap/modal', 'bootstrap/tooltip', 'bootstrap/transition'
], function () {
// play with bootstrap
});
b
")
var $ = require('jquery-browserify'),
moment = require('moment');
var updateClock = function () {
var t = moment().format('H:mm:ss');
$('#clock').text(t);
};
updateClock();
setInterval(updateClock, 1000);
Bundle with: browserify app/main.js -o bundle.js
Gliwice | Katowice | Warszawa