Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Require JS is ignoring my config

I'm having pretty simple directory structure for scripts:

/js/        <-- located in site root
    libs/
        jquery-1.10.1.min.js
        knockout-2.2.1.js
        knockout.mapping.js
    models/
        model-one.js
        model-two.js
        ...
    require.js
    config.js

Since the site engine uses clean URLs I'm using absolute paths in <script>:

<script type="text/javascript" data-main="/js/config.js" src="/js/require.js"></script>

RequireJS config:

requirejs.config({

    baseUrl: "/js/libs",

    paths: {
        "jquery":       "jquery-1.10.1.min",
        "knockout":     "knockout-2.2.1",
        "komapping":    "knockout.mapping"
    }

});

Somewhere in HTML:

require(["jquery", "knockout", "komapping"], function($, ko, mapping){
    // ...
});

So the problem is that RequireJS completely ignores baseUrl and paths defined in config file. I get 404 error for every module required in the code below. I see in browser console that RequireJS tries to load these modules from /js/ without any path translations:

404: http://localhost/js/jquery.js
404: http://localhost/js/knockout.js
404: http://localhost/js/komapping.js

However after the page is loaded and the errors are shown I type in console and...

> require.toUrl("jquery")
  "/js/libs/jquery-1.10.1.min"

Why so? How to solve this problem?

It's my first experience using RequireJS, so I'm feeling like I've skipped something very simple and obvious. Help, please.

Update

Just discovered this question: Require.js ignoring baseUrl

It's definitely my case. I see in my Network panel that config.js is not completely loaded before require(...) fires own dependency loading.

But I don't want to place my require(...) in config because it is very specific for the page that calls it. I've never noticed such problem with asynchronicity in any example seen before. How do authors of these examples keep them working?

like image 289
Rango Avatar asked Jun 27 '13 10:06

Rango


2 Answers

Solved.

The problem was that config file defined in data-main attribute is loaded asynchronously just like other dependencies. So my config.js accidentally was never completely loaded and executed before require call.

The solution is described in official RequireJS API: http://requirejs.org/docs/api.html#config

... Also, you can define the config object as the global variable require before require.js is loaded, and have the values applied automatically.

So I've just changed my config.js to define global require hash with proper configuration:

var require = {
    baseUrl: "/js/libs",
    paths: {
        "jquery":       "jquery-1.10.1.min",
        "knockout":     "knockout-2.2.1",
        "komapping":    "knockout.mapping"
    }
};

and included it just BEFORE require.js:

<script type="text/javascript" src="/js/config.js"></script>
<script type="text/javascript" src="/js/require.js"></script>

This approach allows to control script execution order, so config.js will always be loaded before next require calls.

All works perfectly now.

like image 119
Rango Avatar answered Oct 21 '22 15:10

Rango


Fixed the issue.

My config was being loaded asynchronously, and therefore the config paths weren't set before my require statement was being called.

As per the RequireJS docs Link here, I added a script call to my config before the require.js call. And removed the data-main attribute.

var require = {
    baseUrl: '/js',
    paths: {
        'jquery':      'vendor/jquery/jquery-2.0.3.min',
        'picker':      'vendor/pickadate/picker.min',
        'pickadate':   'vendor/pickadate/picker.date.min'
    },
    shim: {
        'jquery': {
            exports: '$'
        },
        'picker':    ['jquery'],
        'pickadate': {
            deps:    ['jquery', 'picker'],
            exports: 'DatePicker'
        }
    }
}

All is now working

like image 23
Leon Avatar answered Oct 21 '22 14:10

Leon