Optimize shim configuration - javascript

Is there any way to do something like following
shim: {
bsAlert || bsTooltip || dbDropdown: {
deps: ['jquery']
}
}
instead of following
shim: {
bsAlert: {
deps: ['jquery']
},
bsTooltip: {
deps: ['jquery']
},
bsDropdown: {
deps: ['jquery']
}
}
My shim list is getting too long; Is there any way, where i can use logical operator or regular expressions to optimize my shim configuration?

You probably already knew this but using || for this purpose won't work in plain JavaScript. I do not know of a JavaScript "extension" language (like CoffeeScript) which will allow what you propose.
However, the configuration object you pass to requirejs can be dynamically constructed. So you could do something like:
var config = {
baseURL: "lib",
paths: { ... },
shim: {
moduleA: { ... }
}
};
var s = config.shim;
s.bsAlert = s.bsTooltip = s.bsDropdown = { deps: ['jquery'] };
require.config(config);
If you are going to need to do this a lot, it would be possible to write a config like:
var config = {
baseURL: "lib",
paths: { ... },
shim: {
moduleA: { ... }
"bsAlert || bsTooltip || bsDropdown": { deps: ['jquery'] },
}
};
And then have a function walk over the config object to convert keys of the form "A || B" into what requirejs wants before passing the object to requirejs. And since requirejs combines configurations when you configure it multiple times, you could have something like:
require.config({
// ... minimal config allowing to find "convert_config"
});
var convert_config = require("convert_config"); // module returns function
var config = {
baseURL: "lib",
paths: { ... },
shim: {
moduleA: { ... },
"bsAlert || bsTooltip || bsDropdown": { deps: ['jquery'] },
}
};
convert_config(config); // modifies object in-place
require.config(config); // pass the full configuration to requirejs

Adding to #Louis-Dominique Dubeau answer. Definition for convert config can be given as follows.
define("convert_config", function(){
function convert_config(config){
for(var index in config.shim){
if(index.indexOf("||")!=-1){
var keys = index.split("||");
for(var i=0; i<keys.length; i++){
config.shim[keys[i]] = config.shim[index];
}
delete config.shim[index]
}
}
return config;
}
return convert_config;
})
var convert_config = require("convert_config");
var config = {
baseURL: "lib",
paths: {},
shim: {
moduleA: {},
"bsAlert || bsTooltip || bsDropdown": { deps: ['jquery'] },
}
};
config = convert_config(config);
require.config(config);

Related

React-router undefined after concatenation

I've set up an app with react using react-router for routing and are having issues bundling it all.
I'm trying to build/bundle all the js files using gulp-requirejs. But somehow the shim is not included, or the react-router is just ignored. Whatever the problem is, I just end up with an error in the browser console saying Uncaught Error: app missing react-router
I'm including the most important code, feel free to ask if something doesn't make sense.
gulpfile.js
Almond.js is there to replace requirejs
var gulp = require('gulp'),
uglify = require('gulp-uglify'),
rjs = require('gulp-requirejs'),
gulp.task('requirejsBuild', function() {
rjs({
baseUrl: './app/resources/js/',
out: 'app.min.js',
paths: {
'react': '../bower_components/react/react-with-addons',
'react-router': '../bower_components/react-router/dist/react-router',
'react-shim': 'react-shim',
'jquery': '../bower_components/jquery/dist/jquery'
},
shim: {
'react-shim': {
exports: 'React'
},
'react-router': {
deps: ['react-shim']
}
},
deps: ['jquery', 'react-router'],
include: ['init'],
name: '../bower_components/almond/almond'
})
.pipe(uglify()).pipe(gulp.dest('./app/resources/js/'));
});
init.js
require.config({
baseUrl: '/resources/js/',
deps: ['jquery'],
paths: {
'react': '../bower_components/react/react-with-addons',
'react-router': '../bower_components/react-router/dist/react-router',
'react-shim': 'react-shim',
'jquery': '../bower_components/jquery/dist/jquery'
},
shim: {
'react-shim': {
exports: 'React'
},
'react-router': {
deps: ['react-shim']
}
}
});
require(['react', 'app'], function(React, App) {
var app = new App();
app.init();
});
app.js
define([
'react',
'react-router',
], function(
React,
Router,
){
var Route = Router.Route;
var RouteHandler = Router.RouteHandler;
var DefaultRoute = Router.DefaultRoute;
/**
* Wrapper for it all
*
* #type {*|Function}
*/
var Wrapper = React.createClass({displayName: "Wrapper",
mixins: [Router.State],
render: function() {
return (
React.createElement(RouteHandler, null)
);
}
});
var routes = (
React.createElement(Route, {handler: Wrapper, path: "/"}, null)
);
var App = function(){};
App.prototype.init = function () {
Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(React.createElement(Handler, null), document.getElementById('content'));
});
};
return App;
}
);
index.html
Mainly containing a script tag
After build you have to manually swap the src with app.min.js
<script data-main="/resources/js/init" src="/resources/bower_components/requirejs/require.js"></script>

Is it possible to set dependencies for a folder using require.js?

Is it possible to set dependencies for an entire folder using require.js?
I know that you can use the shim configuration to set dependencies for a file:
require.config({
shim: {
'plugin/backbone/xyz': {
deps: ['lib/backbone'],
exports: 'Backbone'
}
}
});
In the above example I define the dependencies for the plugin backbone/xyz, but I would like to define the dependencies for all backbone plugins:
require.config({
shim: {
'plugin/backbone/': { // I would like to specify a folder here but it doesn't work.
deps: ['lib/backbone'],
exports: 'Backbone'
}
}
});
I think that I once found a gist about it on GitHub, but I can't seem to find it again.
To clarify: This isn't about requiring an entire folder, but setting dependencies for it - What all files in the folder needs before they are ready to initialize, each and one of them. It would be accomplished by adding shims for all the files, but I would like to only have to add that shim once for the entire folder:
shim: {
'lib/backbone': {
exports: 'Backbone' // <- No use of .noConflict() so all plugins can be required and export Backbone as well.
},
'plugin/backbone/a': {
deps: ['lib/backbone'], // <- Require backbone
exports: 'Backbone' // <- Export backbone
},
// Same requirement and folder for these files:
'plugin/backbone/b': {
deps: ['lib/backbone'],
exports: 'Backbone'
},
'plugin/backbone/c': {
deps: ['lib/backbone'],
exports: 'Backbone'
}
}
No, you cannot easily create a wildcard to add dependencies to all files under a folder from the configuration itself. You can however create a loop before the config and add whichever dependencies you want.
var config = {
shim: {
'plugin/backbone/xyz': {
deps: ['lib/dependency'],
exports: 'Backbone'
}
}
};
for(var shim in config.shim) {
if(shim.indexOf('plugin/backbone/') == 0) {
if(config.shim[shim].deps == null) {
config.shim[shim].deps = [];
}
config.shim[shim].deps.push('lib/backbone');
}
}
require.config(config);
This is the only way I can think of without having to override one of require's functions yourself. Not elegant, I will admit, but it will do the job.
Inspired by #J_A_X's answer
You can make an array of files that should share the same dependencies and create the shim dynamically:
var config = { shim: { /*...*/ } }
var plugins = ['a', 'b', 'c', 'd'],
plugin_shim = {
deps: ['lib/backbone'],
exports: 'Backbone'
};
plugins.forEach(function(file) {
config.shim['plugin/backbone/' + file] = plugin_shim;
});
require.config(config);
But this wouldn't work very well if someone would minuglify using r.js

Underscore.string with RequireJS

I'm trying to use both Underscore and Underscore.string with RequireJS.
Contents of main.js:
require.config({
paths: {
'underscore': '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
'underscore-string': '//cdnjs.cloudflare.com/ajax/libs/underscore.string/2.3.0/underscore.string.min',
},
shim: {
'underscore': {
exports: '_'
},
'underscore-string': {
deps: ['underscore'],
exports: '_s'
},
}
});
var modules = ['underscore-string'];
require(modules, function() {
// --
});
Browser sees the _, but doesn't see the _s - it is undefined.
Ideally i want to have Underscore under _ and Underscore.string under _.str, but _ and _s are fine too. How can i do that?
Versions: RequireJS 2.1.5, Underscore 1.4.4, Underscore.string 2.3.0
Note: Thanks to #jgillich make sure, that paths have two slashes (//cdnjs.cloudfare.com/...), otherwise the browser would think that URL is relative to the server, and Firebug will throw:
Error: Script error
http://requirejs.org/docs/errors.html#scripterror
I found the error. For some reason RequireJS doesn't work with version of Underscore.string from cdnjs.com, so i replaced it with Github version. I guess it has something to do with the commit 9df4736.
Currently my code looks like the following:
require.config({
paths: {
'underscore': '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
'underscore-string': '//raw.github.com/epeli/underscore.string/master/dist/underscore.string.min',
},
shim: {
'underscore': {
exports: '_'
},
'underscore-string': {
deps: ['underscore'],
},
}
});
var modules = ['underscore', 'underscore-string'];
require(modules, function(_) {
// --
});
Underscore.string resides in _.str.
Edit: As of 16 July 2013 the CDNJS version is updated with the upstream.
Battling with this for hours before i understand what i was doing wrong
This is what i did wrong
You should not rename the file underscore.string in main.js
even though in my library i did rename the file in paths i name it back to 'underscore.string'
This is how your main.js should look like
require.config({
paths: {
underscore: 'lib/underscore',
'underscore.string' : 'lib/_string' ,
},
shim: {
underscore: {
exports: '_',
deps: [ 'jquery', 'jqueryui' ]
},
'underscore.string': {
deps: [ 'underscore' ]
},
}
....
You could then either add it as dependency with in your shim like i did for my mixin file
shim: {
mixin : {
deps: [ 'jquery', 'underscore', 'underscore.string' , 'bootstrap' ]
},
Or just define it in your different pages like
/*global define */
define([
'underscore.string'
], function ( ) {
it just work now you can access it through _.str or _.string
This is why you should do it this way and not try to name it something else
on line 663 of underscore.string.js
// Register as a named module with AMD.
if (typeof define === 'function' && define.amd)
define('underscore.string', [], function(){ return _s; });
Which means that it will only register it with AMD require JS if you are defining 'underscore.string'
works for my ONLY if I use exact "underscore.string" module name in shim. Seems related to hardcoded name in underscore.string itself
Exempt from underscore.string source code (this branch is executed when require used):
// Register as a named module with AMD.
if (typeof define === 'function' && define.amd)
define('underscore.string', [], function(){ return _s; });
So for me the only working configuration is:
require.config({
paths: {
'underscore': '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
'underscore.string': '//raw.github.com/epeli/underscore.string/master/dist/underscore.string.min',
},
shim: {
'underscore': {
exports: '_'
},
'underscore.string': {
deps: ['underscore'],
},
}
});
var modules = ['underscore', 'underscore.string'];
require(modules, function(_) {
// --
});
Here's a working code using Requirejs "order" plugin, also includes Jquery, and everything loads without any conflict:
requirejs.config({
baseUrl: "assets",
paths: {
order: '//requirejs.org/docs/release/1.0.5/minified/order',
jquery: 'http://code.jquery.com/jquery-2.1.0.min',
underscore: '//underscorejs.org/underscore-min',
underscorestring: '//raw.githubusercontent.com/epeli/underscore.string/master/dist/underscore.string.min',
underscoremixed: 'js/underscore.mixed' // Create separate file
},
shim: {
underscore: { exports: '_' },
underscorestring: { deps: ['underscore'] }
}
});
require(['order!jquery','order!underscoremixed'], function($,_) {
// test
console.log( _.capitalize('capitalized text') );
});
Inside js/underscore.mixed.js put the following...
define(['underscore','underscorestring'], function() {
_.mixin(_.str.exports());
return _;
});
Cheers! :)

Unable to resolve _ in a Backbone & RequireJS app

I'm relatively new to Backbone and RequireJS, so please bear with me. I'm getting an error when I do the following in my collection: _.range(0,10). It's giving me this error:
Uncaught TypeError: Cannot call method 'range' of undefined
Somehow the "_" is not getting resolved when my Collection is loaded. Here's my collection below:
define([
'jquery',
'underscore',
'backbone',
'collections/feed',
'text!/static/templates/shared/display_item.html'
], function($, _, Backbone, FeedCollection, DisplayItem){
debugger; // Added this to test the value of _
var FeedView = Backbone.View.extend({
el: '#below-nav',
initialize: function () {
this.feedCollection = new FeedCollection();
},
feed_row: '<div class="feed-row row">',
feed_span8: '<div class="feed-column-wide span8">',
feed_span4: '<div class="feed-column span4">',
render: function () {
this.loadResults();
},
loadResults: function () {
var that = this;
// we are starting a new load of results so set isLoading to true
this.isLoading = true;
this.feedCollection.fetch({
success: function (articles) {
var display_items = [];
// This line below is the problem...._ is undefined
var index_list = _.range(0, articles.length, 3);
_.each(articles, function(article, index, list) {
if(_.contain(index_list, index)) {
var $feed_row = $(that.feed_row),
$feed_span8 = $(that.feed_span8),
$feed_span4 = $(that.feed_span4);
$feed_span8.append(_.template(DisplayItem, {article: articles[index]}));
$feed_span4.append(_.template(DisplayItem, {article: articles[index+1]}));
$feed_span4.append(_.template(DisplayItem, {article: articles[index+2]}));
$feed_row.append($feed_span8, $feed_span4);
$(that.el).append($feed_row);
}
});
}
});
}
});
return FeedView;
});
I added the debugger line so that I could test the values of all the arguments. Everything loaded fine, except for _. Could this be something wrong with my config.js file?
require.config({
// Set base url for paths to reference
baseUrl: 'static/js',
// Initialize the application with the main application file.
deps: ['main'],
paths: {
jquery: 'libs/jquery/jquery.min',
require: 'libs/require/require.min',
bootstrap: 'libs/bootstrap/bootstrap.min',
text: 'libs/plugins/text',
underscore: 'libs/underscore/underscore',
backbone: 'libs/backbone/backbone',
json: 'libs/json/json2',
base: 'libs/base/base'
},
shim: {
'backbone': {
// These script dependencies should be loaded first before loading
// backbone
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'bootstrap': {
deps: ['jquery'],
exports: 'Bootstrap'
}
}
})
Your help is greatly appreciated. My head is spinning as a result of this error.
Based off the project that I'm working on, you need a shim for underscore as well. Underscore isn't 'exported' per say, so use this instead:
shim: {
'backbone': {
// These script dependencies should be loaded first before loading
// backbone
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'bootstrap': {
deps: ['jquery'],
exports: 'Bootstrap'
},
'underscore': {
exports: '_'
}
}
Seems this might also be 'duplicate' question of Loading Backbone and Underscore using RequireJS - one or two of the answers down the list there is a mention of this setup.

Require map: Getting module timeout when mapping extension

I got a Mediator-Sandbox library and a Router extension built on top of this library.
The library is built up like this:
(function(window) {
var MedSan = {};
window.MedSan = MedSan;
})(this);
The extension looks like this:
(function(_, Backbone, MedSan) {
MedSan.Router = {};
})(_, Backbone, MedSan);
The requires config to load the extension looks like this:
require.config({
baseUrl: "javascripts",
shim: {
"jquery": {
exports: "$"
},
"underscore": {
exports: "_"
},
"backbone": {
deps: ['jquery', 'underscore'],
exports: "Backbone"
},
"Distribution": {
exports: "Distribution"
},
"Distribution.Router": {
deps: ['underscore', 'backbone', 'Distribution'],
exports: "Distribution"
}
},
/*
map: {
"*": {
"Distribution": "Distribution.Router"
}
},
*/
paths: {
"jquery": "Vendors/jquery",
"underscore": "Vendors/underscore",
"backbone": "Vendors/backbone",
"Distribution": "Distribution/Distribution",
"Distribution.Router": "Distribution/Plugins/Router"
}
});
I now can use my full library with:
require(['Distribution.Router'], function(Distribution) {});
when I uncomment the map configuration so I can use the full loaded module with router extension this way:
require(['Distribution'], function(Distribution) {});
than I am getting a module timeout.
What am I doing wrong?
When you map Distribution to Distribution.Router, you're creating a circular dependency because Distribution.Router also depends on Distribution.
To fix this just add another line overriding the map for Distribution in Distribution.Router only:
map: {
"*": {
"Distribution": "Distribution.Router"
},
"Distribution.Router": {
"Distribution": "Distribution"
}
}

Categories