Using bootbox in RequireJS app - requirejs

I have a sample app.js file with:
requirejs.config({
"baseUrl": "js/lib",
"paths": {
"jquery": "jquery",
"app": "../app",
"bootstrap": "bootstrap/js/bootstrap.bundle",
"bootbox": "bootbox.min"
},
"shim": {
"bootstrap": {
"deps": ["jquery"],
"exports": 'bootbox'
},
"main": { "deps": ["jquery","bootstrap"] },
"bootbox": {
"deps": ["jquery","bootstrap"],
"exports": 'bootbox'
},
}
});
require(['jquery','bootstrap','bootbox'], function($){
$(function(jquery) {
bootbox.alert("bla")
});
});
When I run my page, I can see the correct JS files being grabbed:
...yet my code fails:
bootbox.alert("bla")
Gives:
ReferenceError: bootbox is not defined
I must be missing something simple (again, apologies if this is a newbie error - I'm still trying to get my head around this library)

Don't use shim with Bootbox. If you look at the source code of Bootbox, you'll see it calls define, which registers it as a proper AMD module. The shim option is only for code which is not a proper AMD module.
Now, the define in Bootbox does this:
define(["jquery"], factory);
It sets a dependency on jQuery, but that is wrong, because in fact Bootbox also depends on Bootstrap being present. So we need to fix this. The following shows how you can fix it. You can use a map configuration option so that when Bootbox requires jQuery, it gets Bootstrap. And you set a shim for Bootstrap so that, in addition to having a dependency on jQuery, its module value is the same as jQuery ($).
Without the map setup, there's no guarantee that Bootstrap will load before Bootbox and you'll be facing a race condition: sometimes it'll work, sometimes not.
requirejs.config({
baseUrl: ".",
paths: {
jquery: "//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min",
bootstrap: "//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min",
bootbox: "//github.com/makeusabrew/bootbox/releases/download/v4.4.0/bootbox.min"
},
shim: {
"bootstrap": {
"deps": ["jquery"],
// We set bootstrap up so that when we require it, the value with get is just $.
// This enables the map below.
"exports": "$"
},
},
map: {
// When bootbox requires jquery, give it bootstrap instead. This makes it so that
// bootstrap is **necessarily** loaded before bootbox.
bootbox: {
jquery: "bootstrap",
},
}
});
require(["jquery", "bootbox"], function($, bootbox) {
$(function(jquery) {
bootbox.alert("bla");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

Related

Bootstrap library with requirejs

I am trying to use bootstrap with require js. So far jquery, underscore and boostrap are loading fine, but I am having issues with one library not loading: bootstrap-tagsinput. How can I debug requirejs and see whether this library is loading or not?
Here is my common.js
requirejs.config({
shim: {
'jquery': {
exports: '$'
},
'underscore': {
exports: '_'
},
'bootstrap': {
deps: [ "jquery" ]
},
'bootstrap-tagsinput': {
deps: [ "bootstrap" ]
}
},
baseUrl: "/",
paths: {
'jquery': [
'//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min',
'jquery/jquery.min'
],
'underscore': [
'//underscorejs.org/underscore-min',
'underscore/underscore-min'
],
'bootstrap': [
'//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min',
'bootstrap/dist/js/bootstrap.min'
],
'bootstrap-tagsinput': 'bootstrap-tagsinput/dist/bootstrap-tagsinput.min'
}
});
Require.js is invented to handle dependencies between modules, so it is quite clear that you specify those dependencies in the modules where you use it like you said in your own answer already. The function given as the second parameter to define() gets handles to those modules in the order they are given.
As $ is normally used for jQuery library, it is not a good idea to use $ for something else, because this would create a lot of confusion. But normally you need jQuery in a module as well, so your define() call will most probably look like
define['jquery', 'bootstrap-tagsinput'], function($) {
...
});
In this case $ is bound to jQuery, not to bootstrap-tagsinput. It is instead called via the jQuery mechanisms, so you don't need a second parameter in the function.
I figured out that 'bootstrap-tagsinput' needs to be defined where it's being used. For example, in a page that makes use of this library:
define(['bootstrap-tagsinput'], function() {
// js for the page here
});
And in order to auto-load modules that should always be available (eg. bootstrap or jquery) we can do the same.
define(['bootstrap'], function() {
// main.js contents
});

Loading hyperagent with require.js

I've used bower to install hyperagent, and it pulled down some dependencies, I'm just not sure how to properly initialise it now.
As far as I call tell, it doesn't support AMD loading, so I'm trying to use a shim config. I've tried a few things, looking something like this:
<script src="{{ path('root') }}bower/requirejs/require.js"></script>
<script>
require.config({
"baseUrl": "{{ url('root') }}/bower/",
paths: {
"vue": 'vue/dist/vue.min',
"hyperagent": 'hyperagent/dist/hyperagent',
"jquery": "jquery/jquery.min",
"uri": "uri.js/src/URI.min"
},
shim: {
'hyperagent': {
'deps': ['jquery', 'uri'],
'exports': 'Hyperagent'
}
}
});
</script>
When I later do
require(['vue', 'hyperagent'], function(Vue, Hyperagent) { ... });
Hyperagent is undefined.
Am I way off the mark? (Oh, and the mustaches are twig, this is a Symfony project)
Thanks to Ben Weiner for this one. Taken from here.
I installed hyperagent and URIjs via bower and for now I'm just setting window.URI as a global before requiring hyperagent. Here's the relevant part of my require.js config:
require.config({
paths: {
'hyperagent': '../bower_components/hyperagent/dist/amd/hyperagent',
'URIjs': '../bower_components/uri.js/src',
}
});
To use it I just define an amd module that returns a configured hyperagent eg configured_hyperagent.js:
define(function(require) {
window.URI = require('URIjs/URI');
window.URITemplate = require('URIjs/URITemplate');
Hyperagent = require('hyperagent');
// Hyperagent.configure() etc..
return Hyperagent;
});

require js beginner - dependency injection

I'm a beginner with require js and I have a doubt here.
My files are structured like below:
root
|____assets
|____bootstrap-3.0.1
|________dist
|____________js
|____________bootstrap.min.js
|________js
|________angulajs.min.js
|________app.js
|________jquery.min.js
|________underscorejs-min.js
|____________app
|________________main.js
My app.js file is like below:
requirejs.config({
"baseUrl": "assets/js",
"paths": {
": "app",
"jquery": "jquery.min",
"jquery-migrate": "jquery-migrate.min",
"twitter-bootstrap": "../bootstrap-3.1.0/dist/js/bootstrap.min",
"underscore": "underscore-min"
},
"shim": {
"twitter-bootstrap": {
deps: [ "jquery" ]
}
}
});
requirejs(["app/main"]);
My main.js is like below:
define([ "jquery", "twitter-bootstrap" ], function($) {
$(function() {
$("#teste").tooltip();
});
});
My question is about the main file and the dependency jquery in the case of bootstrap. If I had declare that the Bootstrap depends on jQuery I still have to include "jquery" in define function?
I tried to remove "jquery" declaration but the dependency was not injected and I received a undefined error.
Thanks for any help!
Doing it like this is really the way to go:
define([ "jquery", "twitter-bootstrap" ], function($) {
$(function() {
$("#teste").tooltip();
});
});
In the code above, it is clear that $ should be bound to the jquery module. If you do this:
define(["twitter-bootstrap" ], function($) {
$(function() {
$("#teste").tooltip();
});
});
You are binding $ to the twitter-bootstrap module. This won't work without further configuration because twitter-bootstrap exports nothing. (It installs itself as a jQuery plugin.) You could work around it by setting your shim like this:
"shim": {
"twitter-bootstrap": {
deps: [ "jquery" ],
exports: '$.fn.tooltip',
init: function ($) { return $; }
}
}
However, I don't recommend this since someone who comes across the code without knowing the context (that is, not knowing the relationship between the jquery and twitter-bootstrap modules) won't readily know what is going on.
In the shim above the exports field is not absolutely necessary but it help RequireJS know when Bootstrap has been loaded. It should be a symbol that does not exist prior to Bootstrap being loaded but exists after it is loaded.

require cdn libraries in browserify without bundling it in the final js file

If I have a library that is being pulled down from cdn and wouldn't like it to be part of the final js file but be able to require it using browserify, how would I solve it?
Here is how I currently solve it using alias and a shim file.
browserify: {
options: {
debug: true,
transform: [ 'reactify' ],
alias: [
'client/shims/jquery.js:jquery'
]
},
app: {
src: 'client/app.js',
dest: 'public/app.js'
}
}
here is the shim file client/shims/jquery.js which I alias to jquery so I can use require('jquery') instead of the full path.
module.exports = $;
Is there a shortcut in grunt-browserify to support this scenario? I would like to know if it is possible to define it in Gruntfile.js without creating the shim file.
Adding external: [ 'jquery' ] seems to totally ignore it and doesn't work.
With browserify-shim you can add this in your package.json file:
"browserify": {
"transform": [
"browserify-shim"
]
},
"browserify-shim": {
"jquery": "global:$"
}
Then jquery will be available in your modules via require('jquery')
If you load jQuery before the Browserify bundle on the page, $ will be available as a global.

requirejs no longer loads cdn scripts after optimization

I'm struggling to get requirejs to work after optimizing with r.js
It works fine pre optimization
I'm following the docs for configuring main.js and the build profile using empty:
However after optimization, CDN scripts are no longer loaded.
public/index.html
<script data-main="editor/js/main" src="editor/js/vendor/require.js"></script>
public/editor/js/main.js
requirejs.config({
baseUrl: "/editor/js",
paths: {
"jquery": "http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min",
"order": "vendor/require_order",
"underscore": "vendor/underscore",
"handlebars": "vendor/handlebars-1.0.0.beta.4",
"jquery.mobile.router": "vendor/jquery.mobile.router",
"jquery.mobile": "http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min"
}
});
require(["order!jquery", "order!underscore", "order!handlebars", "order!jam", "order!jquery.mobile"], function () {
//loaded
});
config/build.js
({
baseUrl: "../public/editor/js",
name: "main",
out: "../public/editor/js/main-built.js",
paths: {
"order": "vendor/require_order",
"underscore": "vendor/underscore",
"handlebars": "vendor/handlebars-1.0.0.beta.4",
"jquery.mobile.router": "vendor/jquery.mobile.router",
"jquery": "empty:",
"jquery.mobile": "empty:"
}
})
When I run r.js node config/r.js -o config/build.js
main-built.js is built successfully.
Is there a particular reason why you are loading everything using the order plugin?
Were you having load order problems in your built javascript?
If you load jQuery mobile normally (without the plugin) your "empty" configuration should take effect.
require(["jquery", "underscore", "handlebars", "jam", "jquery.mobile"], function () {
http://requirejs.org/docs/optimization.html#empty
You will also need to define the dependency chain for jQuery.mobile.router
requirejs.config({
paths: {
"jquery": "http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min",
"order": "vendor/require_order",
"underscore": "vendor/underscore",
"handlebars": "vendor/handlebars-1.0.0.beta.4",
"jquery.mobile.router": "vendor/jquery.mobile.router",
"jquery.mobile": "http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min"
},
shim: {
"router": {
"deps" : ["jquery.mobile"]
},
"jquery.mobile" : {
"deps" : [ "jquery.mobile.router"],
"exports": "$.mobile"
},
"jquery.mobile.router": {
"exports": "$.mobile.Router"
}
}
});
see the answer to this question:
Require.js with jQueryMobile-Router
I hope that resolves your issues with requirejs, I've found it to be a very powerful and useful tool, once you get used to its structure.
_Pez

Resources