gorkarod
8/9/2013 - 9:17 AM

index.html

// 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);

});
// 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);
    }
);
<!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>