Search code examples
javascriptknockout.jsrequirejsknockout-es5-plugin

Require JS with Knockout components is looking for js file in incorrect path


I am trying to understand how require js works by building knockout components.I have built 2 separate knockout components for testing. My directory structure is as follows:

- App
  |_ Components
     |_ Like-Widget
        |_like-widget.js
        |_like-widget.html
     |_ sign-in
        |_sign-in.js
        |_sing-in.html
     |_ startup.js
- Scripts
    |_ knockout.js
    |_ knockout-es5.js
    |_ app.js

I have configured require.js as follows in app.js file

    require.config({
    paths: {
        ko: "/Scripts/knockout-3.4.0",
        kox: "/Scripts/knockout-es5",
        jquery: "/Scripts/jquery-1.10.2.min",
        text: "/Scripts/text"
    },
    shim: {
        "kox": {
            deps:["ko"]
        }
    },
    baseUrl: "/App/Components"
});

require(["/App/Components/startup.js"]);

Here is my startup.js file

define(['ko'], function (ko) {
ko.components.register('like-widget', { require: 'like-widget/like-widget' });
ko.components.register('sign-in', { require: 'sign-in/sign-in' });
ko.applyBindings();

});

my like-widget.js and sign-in.js files are almost identical for testing purpose

define(["kox", "text!like-widget/like-widget.html"], function (ko, template) {

function myViewModel(params) {
    var self = this;
    self.personName = 'Bob';
    self.personAge = 23;
    ko.track(this);
};

return {
    viewModel: myViewModel,
    template: template
};

});

define(["kox", "text!sign-in/sign-in.html"], function (ko, template) {

function signInViewModel(params) {
    var self = this;
    self.userName = 'User 1';
    ko.track(this);
};

return {
    viewModel: signInViewModel,
    template: template
};

});

this is how I am referring to require.js in my html page

 <script type='text/javascript' data-main="/Scripts/app.js" src="~/Scripts/require.js"></script>

The problem is that my like-widget component is working fine but as soon as I try to use my sign-in component, I am getting an error

GET http://localhost:65182/App/Components/knockout.js

Uncaught Error: Script error for "knockout", needed by: kox http://requirejs.org/docs/errors.html#scripterror

From the error it seems that requirejs is trying to load knockout from incorrect location, my knockout.js is not in components directory but in scripts directory. What I can't understand is how it is correctly loading the like-widget component?

I am new to requirejs so I am assuming I am making some naive mistake, can you please point it out?


Solution

  • If you look at the source code for knockout-es5 plugin you will see that it requires the knockout path to be set to 'knockout', not 'ko'.

    } else if (typeof define === 'function' && define.amd) {
          define(['knockout'], function(koModule) {
            ko = koModule;
            attachToKo(koModule);
            weakMapFactory = function() { return new global.WeakMap(); };
            return koModule;
          });
    }
    

    If you change your require config path for knockout

    require.config({
        paths: {
            knockout: "/Scripts/knockout-3.4.0",
            // instead of ko: "/Scripts/knockout-3.4.0" 
        }
    

    it should work. You can also remove the shim for knockout-es5 (kox in your example) since it shouldn't be needed.