Imagine you have a large web application and you decide to use the require.js for loading some of your modules. To stir things up a little bit let's suppose that all your modules are stored directly at the root of the server and all the modules have an additional prefix (let's say the prefix consists of 'n/') which should be ignored when loading the module.
On some nested page - e.g. [host]/path/to/page you want to define some entry point module with some dependency on some arbitrary module e.g. n/my/modulename. So you have:
define('entrypoint', ['n/my/modulename'], function(modulename){ ....
});
But when you open the page, require.js decides to load your module according to the module name relatively to current document location - so it tries to fetch
[host]/path/to/page/n/my/modulename. So far you think that the poor require.js is just blindly doing its work and does not know about your crazy location of your modules.
So how do you tell require to rewrite the path ? According to Require.js documentation we might try configuring it in a way similar to this:
require.config({
baseUrl: '/'
})
That does not work
So let's try this
require.config({
baseUrl: ''
})
No.
require.config({
baseUrl: '/',
paths: {
n: ''
}
})
Still wrong
require.config({
baseUrl: '/',
paths: {
n: '/'
}
})
Almost there. Now you realize that the require tries to load your modules from this path: http://my/modulename and you start wondering what were the authors of the library smoking.
After some struggling I think I figured out the only suitable solution for my use case. You have to configure the require with this:
require.config({
baseUrl: '/',
paths: {
n: 'FOO/../'
}
})
Now it finally grabs the n/my/modulename from url http://[host]/my/modulename.
Related
I have the baseUrl in a RequireJs based application set to /angular. Sometimes I'd like to set the path relative to the base, other times I'd like to set it relative to the current directory.
I'm very new to RequireJs and very confused.
This is what I have now:
require([
'require',
'angular',
'module/draft/draftDisplay'// module that I want relative to baseUrl
], function(requireLocal, angular) {
requireLocal('./autoSave'); // Modules that I want relative to current url
requireLocal('./module');
Which creates this error: Error: Module name "autoSave" has not been loaded yet for context: _
As I said before, I can't get a good handle on how RequireJs works. Some things I don't understand are:
1) When does RequireJs use the baseUrl and when does it use the current directory
2) What's the difference between a module ID and its path?
3) Does the way previous modules are specified in the require([...],.. array affect how subsequent ones are resolved (which seemed to be the case when I tinkered)
If you could include those things in your answer, that would be very helpful.
1) When does RequireJs use the baseUrl and when does it use the current directory
Always baseUrl, except when the module name is prefixed by ./ or ../, in which case it uses the directory of the module that requires the other.
2) What's the difference between a module ID and its path?
The path includes the baseUrl. E.g. could be something like scripts/vendor/angular/angular.js. The module id does not include the baseUrl or the suffix, e.g. for baseUrl: 'scripts', the module id above would be vendor/angular/angular.
3) Does the way previous modules are specified in the require([...],.. array affect how subsequent ones are resolved (which seemed to be the case when I tinkered)
No.
Your error is caused from using the synchronous version of require for modules that are not loaded. Use the asynchronous version instead; something like:
requireLocal(['./autoSave', './module'], function(autosave, module) {
// here autosave and module are loaded
});
// BEWARE: Here neither autosave nor module are loaded
But are you sure you want the inner require? From the information you provide, pulling the requirements in the outer require would probably suffice, i.e.
require(['require','angular','module/draft/draftDisplay','./autoSave','./module'],...)
Also, the import called 'module' has special meaning in require; it contains information about the current module; If you are literally using './module' it will be quite different than 'module' (the first looks for a module.js file in the same directory as this file, the second provides information about this module).
I am using requirejs. My main.js content is like following.
requirejs.config({
async: true,
parseOnLoad: true,
packages: [],
paths: {
jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min'
}
});
require(["login"], function (loginService) {
loginService.login('validUser');
});
Now, my config elements are little. But later, I will add packages, paths and others, so the require.config lines will increase.
I wanna separate require.config as a different file and use it?
If jquery load delays, does the error occurs? My other javascript files are using it.
Yes you can, require your config before you require anything else, like this:
config example:
require.config({
baseUrl: '/Public/js',
paths: {
jquery: '../../Scripts/jquery-1.10.2.min',
jqueryui: '../../Scripts/jquery-ui-1.10.2.min',
},
shim: {
jqueryui: {
deps: ['jquery']
},
}
waitSeconds: 3
});
and, then I load it:
require(['/Public/js/config.js'], function() {
require(['home/index'], function() {
});
});
Just remember that you reference the config.js by path in the first require-statement because require.js can not resolve by baseUrl since it has not been loaded. When you get to the inner require()-statement, its loaded and you can reference dependencies relative to baseUrl.
You can put the config into a separate JS file, that's not a problem. Just make sure that file is loaded prior to the require() call in your main code.
If you're using jQuery for other scripts that are not loaded via requireJS, you will get errors if they happen to load sooner than jQuery. What you need to do is convert all those static files into requireJS modules and load them all via requireJS. By using a define() function in each of the modules, you can set up dependencies, so all modules will wait for jQuery to load prior to executing their own code.
This is an example of a multipage requirejs based project where the requirejs.config call is in a separate file
https://github.com/requirejs/example-multipage/tree/master/www
Is it possible to import individual modules from within an optimized RequireJS/r.js bundle?
I have a javascript project broken up into two separate components - 'MyLibrary' and 'MyApplication'
MyLibrary consists of two separate modules, 'MyModule1' and 'MyModule2'.
In development mode, I can import each of these modules using RequireJS with the normal define(['MyLibrary/MyModule1'],function(){}) syntax from MyApplication.
However once running MyLibrary through r.js, this no longer appears to be possible - there doesn't appear to be a way to reference the internal modules directly anymore?
I can see from the compiled/optimized source that there are define() blocks for each module, however RequireJS within My Application doesn't appear to be able to reference these directly.
Is this possible, or will I need to bundle my entire application into a single file for this to work.
Edit: The RequireJS optimization phase is being done my the Play framework, and I have minimal control over the build config.
({appDir: "javascripts",
[info] baseUrl: ".",
[info] dir:"javascripts-min", mainConfigFile: "javascripts/build.js", modules: [{name: "main"}]})
In order to use the modules from the library, you need to instruct RequireJS how to find this modules. In main.js you need to have something like this:
require.config({
// ...
paths: {
// ...
'MyLibraryBundleName': 'dist/MyLibraryFile',
// ...
},
// ...
bundles: {
//...
'MyLibraryBundleName': ['MyLibrary/MyModule1', 'MyLibrary/MyModule2'],
//...
}
});
When MyApplication is referencing a module like this:
define(['MyLibrary/MyModule1'],function(){})
... as you mention, RequireJS will look for 'MyLibrary/MyModule1' and will find it into the 'bundles' section and after that will check the 'path' section to locate the actual file 'dist/MyLibraryFile' which will be loaded.
I'm testing out requireJS and am trying to make a simple project using highcharts. I've started with the requireJS multipage example project as a starting point.
My dir structure looks the same as the base structure, with highstock.js added in the lib directory.
page1.html: page 1 of the app.
page2.html: page 2 of the app.
js
app: the directory to store app-specific modules.
lib: the directory to hold third party modules, like jQuery.
common.js: contains the requirejs config, and it will be the build
target for the set of common modules.
page1.js: used for the data-main for page1.html. Loads the common
module, then loads app/main1, the main module for page 1.
page2.js: used for the data-main for page2.html. Loads the common
module, then loads app/main2, the main module for page 2.
common.js holds the configuration and I've added a shim for highstock there:
requirejs.config({
baseUrl: 'js/lib',
paths: {
app: '../app'
},
shim: {
"highstock": {
"exports": "Highcharts",
"deps": [ "jquery"]
},
} // end Shim Configuration
} );
I also am using the base build file, with the addition of a line to set common.js as the config file and another to disable minifying.
optimize: "none",
mainConfigFile: '../www/js/common.js',
In apps/main1.js I've added a var HighCharts= require('highstock'); and I then try to use it.
When I run this in the normal build everything works fine. All the dependencies hold and everything loads.
When I attempt to optimize my build, highcharts doesn't receive the jQuery dependency. I think I see why its happening, but I'm not sure how to fix it.
My build creates 3 files, common.js, page1.js, and page2.js.
The relevant parts of the build output:
js/lib/../common.js
----------------
js/lib/../common.js
js/lib/jquery.js
...
js/lib/../page1.js
----------------
js/lib/../page1.js
js/lib/highstock.js
js/app/main1.js
...
My page then references the built page1. When it attempts to load the highstock module it errors out since jQuery has not yet been loaded/isn't accessible.
When I see the built page1 I can see why.
require(['./common'], function (common) {
require(['app/main1']); //highcharts is in main1 in the non-optimized version
});
define("../page1", function(){});
//a few more defines
(function () { // start highcharts module definition HERE
So instead of being defined in the callback after common (including jQuery) has been loaded, its loaded after making the request, but before the callback executes.
My question is, why is this happening there instead of inside the callback (which is where it is loaded in the non-optimized version). I've tried multiple options in the build.js file and config file and I seem to be missing some key concept or small error.
Sorry for the super long question but I felt all the info was necessary. If more info is needed I can post it, or get rid of something superfluous.
Please take look at very simple example which use require js http://jsfiddle.net/wAM3h/
require({
paths: {
jquery: "//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min",
hchart: [
"http://code.highcharts.com/highcharts",
"http://code.highcharts.com/highcharts-more",
"http://code.highcharts.com/modules/exporting"
]
}
},
['jquery', 'hchart'], function($, hc) {
window.chart = new Highcharts.Chart(options);
});
Not sure you're still involved with the project or not:
I see that you've not defined the path to the highcharts library in the code above. I could not see it even in the repo you mentioned.
And, again, highcharts prevents re-declaration of this namespace, so you must use a different name
- Hence, you must use a different name while shim-ming it
Note: Libraries like highcharts can be safely used in an amd module without using a shim (unless you need explicit access to the object exported by it).
So, your Config File should look like this:
requirejs.config({
baseUrl: 'js/lib',
paths: {
app: '../app',
'highstock-custom-name': 'path/to/highcharts.js'
},
shim: {
"highstock-custom-name": {
... //as is, although not necessary
}
}
});
I have many modules. One module loads another module, which loads another module. Etc...
And of course, when I load the page, all of these modules load. It works perfectly. Without the optimizer. (even though it takes a minute, because the browser has to load 50 things).
When I use optimizer...in my app.build.js, it seems that I have to manually specify each module!??
Why can't optimizer automatically traverse through the modules?
You only have to specify the module you wanna optimize, not its dependencies. From the docs:
In the modules array, specify the module names that you want to
optimize, in the example, "main". "main" will be mapped to
appdirectory/scripts/main.js in your project. The build system will
then trace the dependencies for main.js and inject them into the
appdirectory-build/scripts/main.js file.
({
appDir: "../",
baseUrl: "scripts",
dir: "../../appdirectory-build",
modules: [
{
name: "main"
}
]
})
Solved.
I had my paths wrong (I didn't understand baseURL , etc) . That's why things broke in the middle.