-
-
Save millermedeiros/1191420 to your computer and use it in GitHub Desktop.
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Example</title> | |
<meta name="description" content="This is just an example"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" href="css/main.css"> | |
</head> | |
<body data-modules="foobar, lorem/ipsum"> | |
<div id="wrapper"> | |
Just an example | |
</div> | |
<script data-main="js/main.js" src="js/lib/require/require.js"></script> | |
</body> | |
</html> |
// main.js is used only for settings and initializing application, | |
// all heavy logic is stored inside proper modules, it makes it | |
// easy to require core modules from inside the application and | |
// also keeps main.js small since settings adds too much noise | |
// to the real code. | |
// | |
// see: http://blog.millermedeiros.com/2011/05/single-entry-point-ftw/ | |
// SETTINGS ======== | |
require.config({ | |
paths : { | |
'jquery' : 'lib/jquery/jquery' | |
} | |
}); | |
// INIT APP ======== | |
define( | |
[ | |
// "require" as depencency so paths are relative to | |
// current context | |
'require', | |
'jquery', | |
'someOtherModuleUsedByAllPages' | |
], | |
function(require, $, someSharedModule){ | |
function init(){ | |
// if metadata on HTML grab it and do a require | |
// body have a `data-modules="foo, bar/ipsum, dolor"` | |
var modules = $('body').data('modules') || ''; | |
if(modules){ | |
require(modules.split(/\s*,\s*/), function(){ | |
// do something when they finish loading, I usually | |
// make this kind of module to auto-instantiate, | |
// so we wouldn't need to do anything here | |
}); | |
} | |
// depending on the project it may be better to simply try | |
// to match a className instead of adding each module to | |
// a data-attribute: | |
if( $('.my-awesome-calendar').length ){ | |
require(['widgets/myAwesomeCalendar']); | |
} | |
someSharedModule.init(); | |
} | |
// if you use URLs to find modules there is no need to wait | |
// for DOM-ready to start loading modules if you have too | |
// many paths it is better to create some sort of look-up | |
// table or use a routing system like crossroads.js to | |
// simplify the logic | |
switch(document.location.pathname){ | |
case '/foo': | |
require(['sections/foo/main'], initSection); | |
break; | |
case '/foo/bar': | |
require(['sections/foo/main'], initSection); | |
break; | |
default: | |
//let's just assume we have a lot of pages with common features | |
require(['sections/simplePage'], initSection); | |
} | |
function initSection(section){ | |
section.init(); | |
} | |
//init app on domready | |
$(document).ready(init); | |
} | |
); |
// This module is only used to decide which section should be loaded and | |
// initialized. | |
// This example is just to demonstrate how Crossroads.js can simplify | |
// the process of loading AMD modules on demand. It assumes it is a | |
// regular website but the same technique could be used for single page | |
// apps with very small teaks. | |
// --- | |
// Author: Miller Medeiros | |
// https://gist.github.com/1191420 | |
define(['crossroads'], function(crossroads){ | |
// ROUTES ==== | |
var newsDetail = crossroads.addRoute('/news/{id}', loadSection); | |
newsDetail.rules = { | |
id : /^\d+$/, //should be numeric | |
//normalize value to return proper module path (which isn't an URL param) | |
normalize_ : function(request, params){ | |
return [ 'news/article', params.id ]; | |
} | |
}; | |
var jobsDetail = crossroads.addRoute('/jobs/{id}/:title:'); | |
jobsDetail.rules = { | |
id : /^\d+$/ //should be numeric | |
}; | |
//we can also use the `SignalBinding.params` to set a default param (same | |
//effect as using `rules.normalize_`). | |
var jobsDetailBinding = jobsDetail.matched.add(loadSection); | |
jobsDetailBinding.params = ['jobs/detail']; | |
var basicSection = crossroads.addRoute('/{section}', loadSection); | |
basicSection.rules = { | |
section : ['news', 'jobs', 'home', 'contact'] //valid sections | |
}; | |
// METHODS ==== | |
function loadSection(path, rest_params){ | |
var params = Array.prototype.slice.call(arguments, 1); | |
//I'm just assuming all sections modules are stored inside a folder | |
//called "sections" and that each section/sub-section have a "main.js" | |
//file. | |
//It's important to note that r.js won't inline these dependencies | |
//automatically since module names are generated dynamically, use the | |
//"includes" build setting or optimize each section individually. | |
require(['sections/'+ path +'/main'], function(mod){ | |
mod.init.apply(mod, params); | |
}); | |
} | |
//if it was a single page app we would probably create a public method to | |
//navigate between sections and also dispose previous section before | |
//initializing the new one, but that is outside the scope of this example. | |
// INIT ==== | |
//parse current URL to decide what to do | |
crossroads.parse(document.location.pathname); | |
}); |
@cherian r.js can't parse HTML documents, you will need to list what modules should be included using the includes setting.
I've been using the approach listed above even for dynamically generated URLs, if I don't have control of the URL I just add some metadata to the <body>
like <body data-modules="sections/foo/main, core/bar">
.
If I know in advance how the URL structure will be and there is a lot of variations, I use crossroads.js to parse the URL and load proper module (just added a new example showing how to do it and how it can simplify the whole process). You have to note that since module names are generated dynamically ('sections/'+ path +'/main'
) they won't be inlined during the optimization, I usually optimize each section individually, so I only load main.js + section_file.
I would favor keeping all the JS modules loading behavior outside the HTML, it will give you more flexibility.
Cheers.
Hi Miller,
Happened to stumble on this. Thanks for sharing.
The way I understand
Executing
will looking for modules and pick up the dependencies from the modules section which is of course in a js file app.build.js
Now in your case how do I instruct node to hit the html and pick the modules listed in it? The ones under
I can only out this in an html file since the url is dynamically generated. Something like
'{% url foo %} '