Perfect Housewife keeps code clean with require.js
The context
The well-known problem: washing socks and mixing colorful clothes. Every time we have to put on socks there is always a small difference within chosen pair. Sometimes one sock is missing, sometimes the color is washed more on one, sometimes we can also get nice rouge t-shirt while washing it with lost red sock.
We have a couple of solution for that. As explained below we have to use some kind of bag to pack socks together before putting them in a wash machine.
The problem
Maintaining large websites often causes real mess within JavaScript libraries and custom code over time. Especially new developer, who has just joined the project team never knows if he/she can exclude any library or plugin and how many relations does it have with other included files. Very often large websites include big amount of unused files, because of the risk of many sad JavaScript console log lines :)
The solution
The solution is require.js – JavaScript file and module loader, which gives a possibility to create clean, modular projects. Require.js gives you ease of development and refactoring. The biggest advantage is modular structure of the project. In each newly written module you have to include all of needed files without worrying if the files has been already used earlier. The same case is in the opposite situation, when you need to remove one module with all included files – you just don’t care, the rest must work This is a short example how to define base URL of JavaScript files or create paths of often used libraries:
require.config({
baseUrl: scriptBaseUrl + '/scripts/libs/',
paths: {
jquery: '//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min',
modernizr: 'modernizr-custom',
conf: '../conf'
}
});
A few sample modules initialized in main project file:
require(['jquery', 'cookiesPolicy', 'conf'], function ($, cookiesPolicy, conf) {
cookiesPolicy.getCookie(conf.cookie.cookiesPolicyName);
});
require(['shareYourOpinion'], function (shareYourOpinion) {
shareYourOpinion.init();
});
require(['jquery', 'tabs'], function ($) {
$('.tabs').tabs();
});
All modules in the example above need jQuery, two of them need “conf” file. There is no problem with using it for two, three or more times, because require.js will include them only once. The developer can attach JavaScript libraries from local web server or external sources like CDN. The new developer can easily recognize relationships between modules and other JavaScript files. Written modules are separated from each other by default but the developer has ability to pass data between them on demand with small code overhead. Attached libraries are “invisible” for the inline JavaScript code.
Sample module from external file:
define(['jquery', 'conf', 'cookies', 'lightbox'], function ($, conf, cookies, lightbox, shareYourOpinion) {
var shareYourOpinion = {
cookieName: 'cookieShareOpinion',
getCookie: function (name) {
cookies.getCookie(shareYourOpinion.cookieName, function(){}, shareYourOpinion.showBar);
},
setCookie: function () {
cookies.setCookie(shareYourOpinion.cookieName, 360000);
},
showBar: function () {
....
};
return shareYourOpinion;
});
The developer initializes module in main file but dependencies are declared inside the external file with definition of module. He can easily distinguish initialized modules and dependencies while editing main and module files.
Pros and cons
Pros:
- modular structure of project
- separated modules with possible data exchange
- easily recognizable module dependencies
- files loaded once but used multiple times
- forces keeping code clean
- ease of introducing a new developer
- self-documentary
Cons:
- without proper optimizing can generate a lot of http requests
- small code overhead
Remember: Wash colors separately. Keep away from fire :)