Search code examples
knockout.jsrequirejsknockout-validation

How to require one file, but load one or more with it


I'm just getting started with Require.js. I have the basics working.

Here's the issue I'm trying to solve: I'm using KnockoutJs and Knockout.validation. I always use these files together. So I'd like to do something where I only have to reference knockout and it will include knockout.validation.

This: (loading both knockout and knockout.validation)

define(["knockout"],
    function (ko) {     
        return {
            name: ko.observable();
        };
    }
);

Instead of this:

define(["knockout", "kovalidation"],
    function (ko) {     
        return {
            name: ko.observable();
        };
    }
);

I need the reference to ko, I just need the other(s) loaded.

Update:

based on the answer bellow I'm trying the bundle configuration option. Unfortunately I can't get it to work.

My understanding is the config should look like:

<script>
    var require = {
        baseUrl: "/Scripts",
        bundles: {
            'knockout-3.0.0': ['knockout.validation']
        }
    };
</script>
<script src="~/Scripts/require.js" data-main="views/home"></script>

Then in my home.js:

require(["knockout-3.0.0"], function (ko) {
   ...
});

Inside home.js, I would expect to see that knockout and knockout.validation are both loaded, but only knockout is loaded.

Update:

It seems like the bundle option in the configuration should do what I need, but at least at this point and with the information I have, it's not the right solution. @daedalus28 gave some good information and a good example that helped me come up with a solution that is acceptable. I have accepted that answer, if a better answer comes a long, please up vote it so we'll all know it's better.


Solution

  • I often have a LibraryPlugins module which I load in my initial require call. In that module, I load up all of the plugins I want available everywhere - like knockout bindings, underscore mixins, jquery plugins, etc. Since it's one of my first require calls, I know the extensions it adds are generally available throughout my application

    Sometimes I will take a more modular approach and have one extra module for each library which returns the library it's operating on (i.e. one for knockout with custom bindings that returns ko and one for underscore with custom mixins that returns a modified underscore). That approach ends up looking much like Louis's answer, but without the extra map:* config. Some modules expose themselves as a named module which makes it a bit more difficult to work with - that's when you'd use the map:* alias like in Louis's solution. For projects where I'm not using a ton of different libraries, I tend to just have one LibraryPlugins module as it is easier to manage when there's a small number of dependencies.

    Here's a jsfiddle where I show both approaches.

    For convenience I'll also paste the code in here:

    require.config({
        paths: {
            'knockout':'//cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min',
            'knockout.validation': '//cdnjs.cloudflare.com/ajax/libs/knockout-validation/1.0.2/knockout.validation.min',
            'underscore.core': 'http://underscorejs.org/underscore-min',
            'underscore.string': 'http://epeli.github.com/underscore.string/lib/underscore.string'
        },
        shim: {
            'underscore.core': {exports:'_'}
        }
    });
    
    // Approach 1: One module to load everything in advance
    define('LibraryPlugins', ['knockout', 'knockout.validation'], function(ko){ });
    
    // Approach 2: One module for each library
    define('underscore', ['underscore.core', 'underscore.string'], function (_, _string) {
        _.mixin(_string.exports());
        return _;
    });
    
    require(['knockout', 'underscore', 'LibraryPlugins'], function(ko, _) {
        console.log(ko.validation);
        console.log(_.humanize);
    });