I have a file structure which looks like this:
/js
/vendor/
/spec
|-main.js
spec/min.js is my entry point and from it I load modules in /js, /vendor, /spec
Actually to make the things working properly I need to put baseUrl: '../'.
Since the directory js, vendor and spec have many subdirectories, is quite boring to handle them, also because If I change something in file structure I need to change a lot of strings.
My question is:
is possible using requirejs to set different paths or a variable to which refer?
Obviously, without defining any global variable.
Example:
require.config({
baseUrl: '../',
paths: {
userView: 'js/users/views/userView' // how it works
userView: baseDir + '/jquery' // possible solution where baseDir = js/users/views/
}
});
To avoid creating global variables you could just wrap it in a self-invoking function:
(function() {
var baseDir = 'something/';
require.config({
baseUrl: '../',
paths: {
userView: 'js/users/views/userView' // how it works
userView: baseDir + '/jquery' // possible solution where baseDir = js/users/views/
}
});
})();
Related
So I'm trying to set up Typescript and Chutzpah for testing purposes. Typescript is set up to output in this format:
define(['require', 'exports', './someModule'], function(require, exports, someModule) {
//examplecode
});
Which works fine, the problem occurs when someModule is actually a directory with an index.js.
/app
app.js
/someModule
index.js
require.js is unable to resolve someModule in this way and the test fails.
Is there any way to tell require.js that this is a module?
RequireJS won't automatically check for the presence of index.js and load that as your module. You need to tell RequireJS that when you want to load someModule, it should load someModule/index. I'd set a map in my call to require.config:
require.config({
[ ... ]
map: {
'*': {
someModule: 'someModule/index',
}
},
});
You have to adjust the name you give there so that it is a path relative to your baseUrl. It's not clear from the information you give in your question what it should be.
(For the record, there's also a packages setting that you could probably tweak to do what you want but putting something packages says "this is a package", which is not what you appear to have here. So I would not use it for what you are trying to do.)
I didn't like the configuration in map either. The most simple way I accomplished this was writing a plugin for require.
Let's name the plugin mod, where it is to be used as mod!module/someModule, you can also call it index as in index!module/someModule, whatever suits you best.
define(function(require, exports, module) {
// loading module/someModule/index.js with `mod!`
var someModule = require('mod!module/someModule');
// whatever this is about ..
module.exports = { .. };
});
So lets assume you have paths set in require's configuration with some sort of project structure:
- app
- modules
- someModule/index.js // the index we want to load
- someModule/..
- someModule/..
- etc
- plugins
- mod.js // plugin to load a module with index.js
Requires config:
require.config({
paths: {
'module': 'app/modules',
// the plugin we're going to use so
// require knows what mod! stands for
'mod': 'app/plugins/mod.js'
}
});
To read all the aspects of how to write a plugin, read the docs at requirejs.org. The simplest version would be to just rewrite the name of the requested "module" you are attempting to access and pass it back to load.
app/plugins/mod.js
(function() {
define(function () {
function parse(name, req) {
return req.toUrl(name + '/index.js');
}
return {
normalize: function(name, normalize) {
return normalize(name);
},
load:function (name, req, load) {
req([parse(name, req)], function(o) {
load(o);
});
}
};
});
})();
This is not production code, it's just a simple way to demonstrate that requires config wasn't meant to solve problems like this.
This code works when I access codemirror over the web:
var modules = ["lib/codemirror"];
requirejs.config({
baseUrl: 'http://codemirror.net/'
});
requirejs(modules, function (CodeMirror) { .. etc.
However I now wish to use a local codemirror.js file in my Scripts directory but the configuration fails to load codemirror. Here is my new code which does not work. I've tried several variations on specifying the baseUrl but no luck. Thanks for taking a look at this issue.
var modules = ["codemirror"];
requirejs.config({
baseUrl: './Scripts',
paths: {
'codemirror', '/codemirror'
}
});
requirejs(modules, function (CodeMirror) { .. etc.
Looks like a typo to me. This is not something RequireJS can use:
paths: {
'codemirror', '/codemirror'
}
I'd expect you want this:
paths: {
'codemirror': '/codemirror'
}
I have two Javascript file loading from the same domain. Each JS performing different function and for that, I have used requirejs module loader.
My problem is, I have used require.config call under both js and baseUrl is different for both configuration.
JS1
require.config({
baseUrl : server + "js/", // server is 192.168.1.10:3000/
paths :
{
jquery : "jquery",
moment : "moment.min"
},
waitSeconds: 20
});
require(["jquery","moment"], function(jQuery,moment)
{
jQuery.noConflict();
window.moment = moment;
jQuery(function($)
{
window.$191 = $;
callback($191);
});
});
JS2
require.config({
baseUrl: "http://192.168.1.9:6060/App/resources",
paths:
{
moment: "js/moment.min",
ejs : "js/ejs"
}
});
require(["moment","ejs"],function()
{
callback("OK");
});
I am loading JS1 first followed by JS2, but when I am loading JS2 its baseUrl change by 1st one i.e. from JS1 (server+"js/") !! Which is totally wrong. Can some one point me out here, if something I have done wrong.
Nikos Paraskevopoulos has the right idea for one way (multiversion) to approach this, but I think there are two ways.
1. Using multiversion
Passing two configs to require.config() will return to you two unique require functions.
// It is important to give the config objects a "context" name.
// This is what keeps them unique.
var r1 = require.config({
context: "r1",
baseUrl: "//rawgithub.com/requirejs/text/2.0.10/"
});
var r2 = require.config({
context: "r2",
baseUrl: "//cdnjs.cloudflare.com/ajax/libs/require-text/2.0.10/"
});
In addition, even if you used the same baseUrl in each config in the sample above, each text module would be a unique instance because of the nature of multiversion support.
These can be used to load modules from different URLs. In the example below, text1 and text2 are different module instances, even though they are essentially the same file.
r1(["require", "text"], function(r, text1) {
// ...
});
r2(["require", "text"], function(r, text2) {
// ...
});
The "require" module is required as a dependency if you use the var myModule = require("..."); syntax within the module body.
If all your dependencies are declared in the dependency array then you do not need this.
(There is a simple example of this at this jsfiddle)
But back to your example, you can assign local require functions to each file, and load modules via that local require function.
JS1
(function () {
var r = require.config({
context: "JS1",
baseUrl: server + "js/", // server is 192.168.1.10:3000/
paths: {
jquery: "jquery",
moment: "moment.min"
},
waitSeconds: 20
});
r(["jquery", "moment"], function (jQuery, moment) {
jQuery.noConflict();
window.moment = moment;
jQuery(function ($) {
window.$191 = $;
callback($191);
});
});
}());
JS2
(function () {
var r = require.config({
context: "JS2",
baseUrl: "http://192.168.1.9:6060/App/resources/",
paths: {
moment: "js/moment.min",
ejs: "js/ejs"
}
});
r(["moment", "ejs"], function () {
callback("OK");
});
}());
Aside
It's unusual for modules to not start with a call to the define() function, however. Usually, config and the modules are in separate files. So you might have:
JS1-config.js and JS1.js
JS2-config.js and JS2.js
And JS1.js and JS2.js would be of the form:
define(["array", "of", "dependencies"], function(array_, of_, dependencies_) {
});
2. Using a consolidated require config
A cohesive application is probably better served with a single module loader configuration file. You have visibility on all the required modules, and it'll probably play better with the r.js optimiser, should you want to use that.
As such, I would recommend consolidating your configs into a single config for your application. This way you don't mix the module loader config with the code that actually uses the modules.
If you can't modify some of the code, then this could be tricky to do though.
E.g.:
var baseUrl1 = server + "js/";
var baseUrl2 = "http://192.168.1.9:6060/App/resources/";
require.config({
paths: {
jquery: baseUrl1 + "jquery",
moment: baseUrl1 + "moment.min",
//moment: baseUrl2 + "js/moment.min",
ejs: baseUrl2 + "js/ejs"
},
waitSeconds: 20
});
This assumes that both JS files can use the same "moment" module.
Hi i'm using requirejs to just organize my javascript codes into AMD modules, i'm building a non-single page website right now using codeigniter, what i do is i have a default layout html file which i always call to render the dynamic content of the body so my script which call the requirejs and has the data-main attribute is encoded on my layout html page.
<script data-main="<?=base_url('assets/js/main.js');?>" src="<?=base_url('assets/js/require.js');?>"></script>
and my main.js looks like this.
requirejs.config({
baseUrl: "assets/js",
paths: {
jquery: 'vendor/jquery',
bootstrap: 'vendor/bootstrap',
datatables: 'vendor/jquery.dataTables'
},
shim: {
jquery: { exports: '$' },
datatables: { deps: ['jquery'] }
}
});
requirejs(['bootstrap','datatables'], function(){
})
so when i type on my url "localhost/ci-project/" it will load the layout page together with the dynamic body. On this scenario it works fine. sicne requirejs will render the path correctly "localhost/ci-project/assets/js/vendor/[js file/module]"
but when i change the URL to say, 'localhost/ci-project/welcome/admin'. what requirejs do to load the modules is concatenate the baseUrl + module path, to the current URL which in this case is 'localhost/ci-project/welcome/admin' and ending result is like this:
'localhost/ci-project/welcome/admin/assets/js/vendor/[module]' which is wrong.
so how can i configure requirejs to always load the from the root url and then concatenate the baseUrl value together with the paths of each modules?
The way to solve this is to output the baseUrl from a server side variable.
In your PHP page:
<script>
var require = {
baseUrl: '<?= base_url(); ?>' // Or whatever outputs the full path to your site root
};
</script>
<script data-main="<?=base_url('assets/js/main.js');?>" src="<?=base_url('assets/js/require.js');?>"></script>
Creating a require object before RequireJS is loaded allows you to define config options that will be picked up automatically.
Calling require.config() again from inside main.js is fine, it will just add the additional config options, but be sure to remove baseUrl from there.
Simon's answer above helped when I had issues with navigating to routes with parameters - relative paths to base url go wrong. I am using asp .net mvc, but the solution is exactly the same:
(_Layout.cshtml)
<script>
var require = {
// by default, load any module IDs from
baseUrl: '#Url.Content("~/Scripts/lib")'
}
</script>
<script data-main="#Url.Content("~/Scripts/application/app.js")" src="#Url.Content("~/Scripts/lib/require.js")"></script>
I'm fairly new to RequireJS and I've run into a bit of a problem. I've written a little framework built on Backbone using RequireJS and I want it to be re-usable in different projects. So, with some searching I learned that require allows packages. This seemed like what I was looking for. I have a main.js file to launch my app that essentially looks like this:
require.config({
packages: ['framework']
});
require(['framework'], function(framework) {
framework.createDash();
});
Then in the same directory as my main.js I have another directory called "framework" which contains another main.js which looks like this:
define(function(require, exports, module) {
exports.createDash = function(dash, element) {
require(['dash/dash.model', 'dash/dash.view'], function(DashModel, DashView) {
return new DashView({
model: new DashModel(dash),
el: element ? element : window
});
});
};
});
In searching I found this page which indicates that the 'require' argument should be scoped to the submodule. However, when I try to require things they are still relative to my original main.js. I've tried a number of things and searched for hours to no avail. Is there any way I can have my require/define calls within my package included relative to the main.js in it's root?
You need to define your submodule as package in the require configuration:
require.config({
packages: [
{ name: 'packagename',
location: 'path/to/your/package/root', // default 'packagename'
main: 'scriptfileToLoad' // default 'main'
}]
... some other stuff ...
});
To load your module you just need to use your 'packagename' at the requirements:
define(['jquery', 'packagename'], function($, MyPackage) {
MyPackage.useIt()
});
In your package you must use the ./ prefix to load your files relative to your submodule:
define(['globalDependency', './myLocalFile'], function(Asdf, LocalFile) {
LocalFile.finallyLoaded();
});
There is a useful shortcut: If your package name equals to your location and your main file is called 'main.js', then you can replace this
packages: [
{ name: 'packagename',
location: 'packagename',
main: 'main'
}]
to this:
packages: ['packagename']
As far as I can see, you already tried to define a package but did you also use the ./ prefix? Without this prefix require will try to find the files in it's global root-path. And without a package, ./ will be useless because the relative path is the same as the global root-path.
Cheers
I figured out the answer to my question, and the solution (they were not the same apparently). I guess I'll post it here in case it can help someone else in the future.
Essentially what I was wanting was to load my framework within its own context. I found the context option under the configuration section on require's website and an example of how to use it. Originally I tried this by doing something like:
var req = require.config({
baseUrl: 'framework',
context: 'framework',
paths: {
jQuery: 'lib/jquery/jquery-1.7.min.js',
Underscore: 'lib/underscore/underscore.min.js',
Backbone: 'lib/backbone/backbone.min.js',
etc...
}
});
req(['main'], function() {});
There were two problems with this. First, my 'req' variable was being defined outside of the framework, but I wanted the framework to define it's own paths. And second, whenever a file outside of the framework would require a file within the framework, which would in turn require 'jQuery', for example, then jQuery (or whatever else) wouldn't be required from within the context of the framework instance of require and so it couldn't find the file.
What I ended up doing was defining my framework's main.js to look something like this:
var paths = {
jQuery: 'lib/jquery/jquery-1.7.min.js',
Underscore: 'lib/underscore/underscore.min.js',
Backbone: 'lib/backbone/backbone.min.js',
etc...
};
define(function() {
var exports = {};
exports.initialize = function(baseUrl, overridePaths, callback) {
if(!overridePaths) {
overridePaths = {};
}
if(baseUrl && baseUrl[baseUrl.length - 1] != '/') {
baseUrl = baseUrl + '/';
}
var fullpaths = {};
for(var path in paths) {
// Don't add baseUrl to anything that looks like a full URL like 'http://...' or anything that begins with a forward slash
if(paths[path].match(/^(?:.*:\/\/|\/)/)) {
fullpaths[path] = paths[path];
}
else {
fullpaths[path] = baseUrl + paths[path];
}
}
var config = {paths: fullpaths};
for(var pathName in overridePaths) {
config.paths[pathName] = overridePaths[pathName];
}
require.config(config);
// Do anything else you need to do such as defining more functions for exports
if(callback) {
callback();
}
}
return exports;
});
And then in my project's main.js file I just do this:
require(['framework/main'], function(framework) {
// NOTE: This setTimeout() call is used because, for whatever reason, if you make
// a 'require' call in here or in the framework without it, it will just hang
// and never actually go fetch the files in the browser. There's probably a
// better way to handle this, but I don't know what it is.
setTimeout(function() {
framework.initialize('framework', null, function() {
// Do stuff here
}
}, 0);
});
This takes whatever is passed in to the framework's initialize() method for 'baseURL' and prepends that to any paths that the framework defines that do not start with a forward slash or 'anything://', unless they are override paths. This allows the package using the framework to override things like 'jQuery'.
This worked for me, adding a "./" prefix to the module names:
define(function (require, exports, module) {
exports.createDash = function (dash, element) {
require([ './dash/dash.model', './dash/dash.view' ], function (DashModel, DashView) {
return new DashView({
model : new DashModel(dash),
el : element ? element : window
});
});
};
});
A process that worked well for me for allowing a package with submodules to be used directly from data-main or from an outside framework, assuming that a main.js (or other package main) is called by a particular name, was to use var baseUrl = require.toUrl('packageName') + '/../' as a prefix to a require.config({ paths: { ... } }) configuration file. For instance:
var music21Base = require.toUrl('music21') + '/../';
require.config({ paths: {
'jquery': music21Base + 'ext/jquery/jquery.2.1.10.min';
'subModuleLoader': music21Base + 'src/subModuleLoader';
} });
The setting of context: "xxx" worked fine for calling normal modules with ./modName but did not work for the paths argument for me.