Szymon Rozga
Szymon Rozga

Reputation: 18178

RequireJS relative paths

I'm new to RequireJS. I'm writing a number of custom bindings in Knockout.js and want to split them up using modules.

The layout of my code at the moment is:

/
  default.html
  js
    code.js
    require-config.js 
    lib
      /require.js
      bridge
        bridge.js
        bindings1.js
        bindings2.js
        bindings3.js

I want to load bridge.js from default.html and have that load in all of the bindings files. I've tried loading bridge.js using a or inline js using the require function.

My require-config is very simple:

require.config({
    baseUrl: '/'
});

In bridge.js, I am having problems loading the files using a relative path. I tried:

require(['./bindings1', './bindings2', './bindings3'], function () {
    console.log('loaded');
});

But this just ends up using the path baseUrl + 'bindings1.js', for example. I've tried various iterations in bridge.js. The only success I've had is if I write the entire path:

require(['js/bridge/bindings1', 'js/bridge/bindings2', 'js/bridge/bindings3'], function () {
    console.log('loaded');
});

But that is not what I want. This seems like a pretty basic use case and I think I may be misunderstanding how the relative paths work.

Thanks

Upvotes: 33

Views: 29035

Answers (2)

Dmitry Masley
Dmitry Masley

Reputation: 525

Use "packages" in require config. Here the valid answer for you question topic

require.config({
packages: [
{ 
    name: 'packagename',
    location: 'path/to/your/package/root',  // default 'packagename'
    main: 'scriptfileToLoad'                // default 'main' 
}]
   ... some other stuff ...
});

Inside of package you will be able to use relative paths.

Upvotes: 26

ddotsenko
ddotsenko

Reputation: 4996

Relative IDs are resolved relative to the module ID within which the ID is resolved. See AMD spec's module id format section.

There are two ways to frame a relative dependency ID into a correct context/scope:

Define call

Define call is the start/definition of "module." All dependencies asked for within define() call are scoped to be within/relative to that module's ID. Example:

// does not matter what the file name is.
define(
    'hand/named/module'
    , ['./child']
    , factoryFunction
)

or

// inside of 'hand/named/module.js' file.
define(
    ['./child']
    , factoryFunction
)

In both of the above cases, ./child is resolved against the module ID defined by the define() call. The module id in both cases is hand/named/module and the ./child is resolved to hand/named/child (+ '.js' obviously, when time comes to get it)

"Scoped" require

You can change the scope of require call from global to local by overriding it. You actually don't need to override / keep the name require, it's the meaning of what it does changes. The require functionality becomes "local" to a particular module.

// inside 'hand/named/module.js' file
define(
    ['require']
    , function(myLocalRequire){
        require('./child', function(){
            // outcome A
        })
        myLocalRequire('./child', function(){
            // outcome B
        })
    }
)

There in outcome A you continue to use "global" require - the one attached to parent scope. Your ./child resolves to baseURL + '/child'

The outcome B is locally-scoped, tied to module id hand/named/module so, ./child is resolved to hand/named/child

What @CristiPufu recommended is to override the global require variable with local object that will be local only to the scope of that function:

// inside 'hand/named/module.js' file
define(
    ['require']
    , function(require){
        return function(){
            // here we have access only to "local" require,
            // since in the function declaration you decided to
            // override the 'require' variable with new object.
            // All code outside of this function will use global require.
            require('./child', function(){
                // outcome B
            })
        }
    }
)

My preference is to put all relative resources inside define call. Makes them explicit and meeningfull as it's clear what they are relative to.

Upvotes: 30

Related Questions