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.
As per RequireJS API documentation, shim lets you. Configure the dependencies, exports, and custom initialization for older, traditional "browser globals" scripts that do not use define() to declare the dependencies and set a module value. - Configuring dependencies.
RequireJS is a JavaScript file and module loader. It improves perceived page load times because it allows JavaScript to load in the background. In particular, it enables asynchronous JavaScript loading.
Generally you only use RequireJS in its loading form during development. Once the site is done and ready for deployment, you minify the code. The advantage here is RequireJS knows exactly what your dependencies are, and thus can easily minify the code in the correct order.
Advertisements. RequireJS can be initialized by passing the main configuration in the HTML template through the data-main attribute. It is used by RequireJS to know which module to load in your application. For instance − <script data-main = "scripts/main" src = "scripts/require.js"></script>
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
:
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
.
I had a similar problem while trying to set up a testing environment. I had a file structure like this:
myApp/ src/ js/ app.js data.js lib/underscore.js test/ karma.conf.js test-main.js matchers.js spec/ data.js
Here's where it gets tricky: my app scripts (app.js
and data.js
) assume a RequireJS configuration that resolves data
to src/js/data.js
, lib/underscore
to src/js/lib/underscore.js
etc, so I need that configuration in my test environment as well:
test/test-main.js ----------------- require.config({ // Karma serves files under /base, which is the basePath from your config file baseUrl: '/base/src/js', // ... });
Now I can write my tests:
test/spec/data.js ----------------- define(['data', '../../test/matchers'], function(dataModule) { describe('The data module', function() { it('should satisfy my custom matcher', function() { expect(dataModule).toSatisfyMyCustomMatcher(); }); }); });
With some custom matchers:
test/matchers.js ---------------- define([], function() { beforeEach(function() { this.addMatchers({ toSatisfyMyCustomMatcher: function() { return this.actual.isGood; }, }); }); });
However, that '../../test/matchers'
part is horrendously ugly. The test specifications shouldn't be bothered with knowing file paths to other modules - that's RequireJS's job. Instead we want to use symbolic names.
The RequireJS paths config can also map directories.
The path that is used for a module name should not include an extension, since the path mapping could be for a directory.
So, the solution is a simple path config:
test/test-main.js ----------------- require.config({ baseUrl: '/base/src/js', paths: { test: '../../test', }, // ... });
Now I can refer to the test
directory as if it were a child of the baseUrl
:
test/spec/data.js ----------------- define(['data', 'test/matchers'], function(dataModule) { // ... });
Which in my case effectively comes out pretty much the same as if I could have multiple baseUrl
s.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With