33

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

Szymon Rozga
  • 17,971
  • 7
  • 53
  • 66
  • it's relative to the `baseUrl` that you set up. For example: if u set up `baseUrl: '/js/lib/bridge'`, then you can use: `require(['bindings1', 'bindings2', 'bindings3']` – Cristi Pufu Jan 27 '13 at 14:37
  • 1
    Right, but I have other code I want to load from other paths. My understanding is that you can use './' to load JS files from the same 'directory', if you will, as the current js file. http://requirejs.org/docs/api.html#modulenotes – Szymon Rozga Jan 27 '13 at 14:44
  • 5
    For require("./relative/name") calls that can happen inside a define() function call, be sure to ask for "require" as a dependency, so that the relative name is resolved correctly. Have you tried to require "require" also ? – Cristi Pufu Jan 27 '13 at 14:47
  • @CristiPufu, that worked. Thanks! Why does one have to do this? If you type up a quick answer I'll accept it. Another option I just noticed works, is to set up a path in the require-config file. – Szymon Rozga Jan 27 '13 at 14:56

2 Answers2

30

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.

ddotsenko
  • 4,926
  • 25
  • 24
  • Doesnt your last example introduce concurrency issues though? This dependency will load immediately and return nothing to the module requesting module.js because the inner require is asynchronous and doesnt run right away. Ie) it does no good to return anything from the inner require because by the time it executes, the module has long since returned.. – computrius Feb 08 '13 at 19:38
  • @computrius Although the example was simplified to the bone just to show the use of *local* require, you are generally right about the concurrency issue. I adjusted the lower example to make the concurrency argument mute, but dread that this answer muddies the example a bit, as the point was to highlight just the mechanics of "local" require. – ddotsenko Feb 09 '13 at 02:23
  • this worked for me better: http://stackoverflow.com/questions/12271152/relative-path-doesnt-work-with-paths – Totty.js Sep 09 '13 at 14:01
  • This may be true for AMD, but I do not believe it's true for RequireJS. See this tweet by @jrburke (creator of RequireJS): https://twitter.com/jrburke/status/386598717802819584 – tbranyen Oct 06 '13 at 05:32
  • I've been trying for days, and no matter what, I keep getting an error saying "Module name '../../../src/debugger/test.js' has not been loaded yet for context: _". –  Feb 26 '18 at 20:39
  • Nevermind, I figured it out. I had to go back to the standard "define" syntax, and change "./src/debugger/test" to "./src/debugger/test.js" –  Feb 26 '18 at 23:50
26

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.

Community
  • 1
  • 1
Dmitry Masley
  • 525
  • 4
  • 9