RequireJS: Is there a way to achieve multiple base URLs?

jpillora picture jpillora · Sep 6, 2012 · Viewed 17.2k times · Source

I want to use a separate domain as a JavaScript framework and it will create a base require config which I can augment from the app.

foo.example.com
    main.js
    lib/foo-specific.js
framework.example.com
    framework.js <-- entry point
    lib/jquery.js
    lib/etc...

Optimally, I'd like to be able to require 'lib/foo-specific' and/or 'lib/jquery' and have the paths just resolve nicely, but from what I've found, there's no way to do this, unless I use a specific path key/value for every js file in the framework. At the moment, I've got a custom plugin to load the given path with a different base url (e.g. fw!lib/jquery), though if I wanted to use the text! plugin, it won't work as plugin chaining is unsupported.

See https://github.com/jpillora/js-framework for what I've currently got, and also https://github.com/jpillora/prettyprinter for a use case.

Is there a clean way to solve this ? or to achieve multiple base URLs ?

Note: I have also looked into multiple require instances, though I don't think that would work as I'd like the the app to be able to access the framework's config.

Answer

jpillora picture jpillora · Sep 9, 2012

Answered by James Burke on RequireJS Github Issue's page: Issue #447: Multiple Base URLs · jrburke/requirejs.

Turns out to be quite simple if data-main is the only entry point to your scripts(comments for more info), I solved my particular problem with the following:

My app's index.html:

<script src="http://framework.jpillora.com/js/lib/require.js" 
  data-main="http://framework.jpillora.com/js/framework" > </script>

has the requirejs entry point set to framework.js:

var framework = ... //set using script elements src attribute

require.config({

    baseUrl: 'js/',

    //Framework paths
    paths: {
      'framework': framework,
      'lib'      : framework + 'js/lib',
      'ext'      : framework + 'js/ext',
      'util'     : framework + 'js/util'
    },

    //Shortcuts
    map: {
      '*': {
        ...
      }
    },

    //Non-modularised libraries with deps
    shim: {
      ...
    }
});

require(['main']);

So instead of normally doing index.html->main.js, we're adding an extra step index.html->framework.js->main.js, which gives the app code knowledge of paths to the framework code.

For example, in the app http://prettyprint.jpillora.com/, once require has loaded framework.js, it will setup paths to lib/... which to http://framework.jpillora.com/ and set the baseUrl as ./js/ so once main is required, it will have the base url set to it's own domain and lib pointing to another domain.

Which results in require(['lib/foo', 'view/bar']); resolving to:

http://framework.jpillora.com/js/lib/foo.js and http://prettyprint.jpillora.com/js/view/bar.js

As displayed here, the app is only a main.js everything else comes from the framework:

chrome devtools loaded app

So finally, whenever I load an app's main.js via with the above framework.js, I then have access to all of my commonly used libraries and utility classes. See app source.

Also note, with the r.js optimiser and a nice local file structure, one can also optimise the app into a single js file pulling only what's required from framework.