Using requireJS with jquery-dependant library (responsiveIframe) - javascript

I am having a lot of trouble wrapping my head around requireJS dependancy management. I've read the docs and all online resources plenty of times but I can't seem to get it working correctly.
End scenario: I have an embeddable widget that eventually will attach a responsive iFrame to a page. The outer page is assumed to have some version of jQuery, but to be safe I am including my own jQuery.
I am using a library called responsiveIframe, which depends on jQuery.
Basically, when I call $('#responsive-frame').responsiveIframe({xdomain: '*'}); from inside the require function, I get an undefined function error. When I change $ to jQuery it works because it is able to use the existing library on the page (not what I want).
Here is the code (assume paths all work):
require.config({
baseUrl: 'http://localhost:4000/assets',
paths: {
'jquery': 'jquery-1.11.1.min',
'responsiveIframe': 'jquery.responsiveiframe'
},
map: {
'*': {'jquery': 'jquery-lc'},
'jquery-lc': {'jquery': 'jquery'}
}
});
require(['jquery', 'responsiveIframe'], function($) {
$('#responsive-frame').responsiveIframe({
xdomain: '*'
});
});
I've tried using various shims like so:
shim: {
responsiveIframe: {
init: function() {
return this.responsiveIframe
}
}
}
,
shim: {
'responsiveIframe': ['jquery']
}
,
shim: {
'responsiveIframe': {
'deps': 'jquery',
'exports': 'ResponsiveIframe'
'init': function() {
return this.responsiveIframe.noConflict()
}
}
I feel like I'm missing something fundamental about requireJS. Any help would be greatly appreciated, please let me know if you need more information :)
edit
Also, wrapping my responsiveiframe.js lib in this:
define(['responsiveIframe', 'jquery'], function(ri, jQuery) {
Seems to work... but this seems 'hacky'.
edit #2
I was able to get this to work by wrapping the responsiveIframe lib like this:
define(['jquery'], function(jQuery) {
//library code here
}
I was able to remove all shims:
require.config({
baseUrl: 'http://localhost:4000/assets',
paths: {
jquery: 'jquery-1.11.1.min',
responsiveIframe: 'jquery.responsiveiframe'
},
map: {
'*': {'jquery': 'jquery-lc'},
'jquery-lc': {'jquery': 'jquery'}
}
});
... and call like so:
require(['jquery','responsiveIframe'], function($) {
$('#responsive-frame').responsiveIframe({xdomain: '*'});
});
However, I am always a fan of doing things the 'right' way and modifying libraries rubs me the wrong way.
I feel like I should be able to use shim to properly apply this wrap code...

The last shim you tried was close, but the values of deps should be an array rather than a string. Try:
shim: {
'responsiveIframe': {
deps: ['jquery']
}
}
This is ensure jquery is loaded before the responseIframe script is loaded and run.

You should set shim like this:
shim: {
'responsiveIframe': {
deps: ['jquery'],
exports: '$'
}
}
And change your module definition to this
define(['responsiveIframe'], function($) {
$('#responsive-frame').responsiveIframe({xdomain: '*'});
}
That should do the trick
UPD.
If exports returns different jquery then you should modify shim to this:
shim: {
'responsiveIframe': {
deps: ['jquery'],
init: function(jquery) {
return jquery;
}
}
}

Related

How to inclue Jquery TimeEntry plugin with RequireJS

I am new working with requirejs, I have an old Asp.net Webform application that I am trying to apply some javascript module loading using requirejs. In this app I am using a jquery plugin named Time Entry, but is not working if I use requirejs, only works if I added the reference the old way. Here is my requirejs configuration and declaration.
In the aspx file:
<script src="../../scripts/require.js"></script>
<script>
require(["../../app/shared/require.config"],
function (config) {
require(["appIncidentTracking/incident-type-init"]);
});
</script>
My require.config file is like this:
require.config({
baseUrl: '../../scripts',
paths: {
app: '../../app/utilization-management',
appIncidentTracking: '../../app/incident-tracking',
jquery: 'jquery-3.1.1.min',
jqueryui: 'jquery-ui-1.12.1.min',
jqueryplugin: '../../js/jquery.plugin.min',
timeentry:'../../js/jquery.timeentry.min',
handlebars: 'handlebars.amd.min',
text: 'text',
moment: 'moment.min',
datatable: 'DataTables/jquery.dataTables.min',
blockUI: 'jquery.blockUI.min',
shared: '../../app/shared',
bootstrap: 'bootstrap.min',
'bootstrap-datepicker': 'bootstrap-datepicker.min',
'bootstrap-multiselect': '../js/bootstrap-multiselect/bootstrap-multiselect'
},
shim: {
bootstrap: {
deps: ['jquery']
},
'bootstrap-multiselect': {
deps: ['bootstrap']
},
timeentry: {
deps:['jquery', 'jqueryplugin']
}
}
});
and in my incident-type-init.js I only call the plugin:
/**
* Incident Type Init page
* #module incident-type-init
*/
define(function (require) {
var $ = require('jquery'),
jqueryplugin = require('jqueryplugin'),
timeentry = require('timeentry'),
bootstrap = require('bootstrap');
/**
* Jquery ready function
*/
$(function () {
$('.js-timeentry').timeEntry();
});
});
but when the application runs I got this error:
$.JQPlugin.createPlugin is not a function, it is like does not find the jquery.plugin.js
I checked the network tab in chrome and both files are loaded, jquery.plugin.js and jquery.timeentry.js
UPDATE: In our application, we are using Asp.net MasterPages, and there we are loading an old jquery version, 1.5.1, and I use that MasterPage in my page, but when I check the network tab in chrome, is loading the MasterPage scripts first,then all the requirejs stuff.
and the funniest part is that sometimes work, sometimes not.
Any clue?
The module jqueryplugin needs to have jQuery already loaded for it. It is not an AMD module because it does not call define. So you need an additional entry in shim for it:
jqueryplugin: ["jquery"]
The above is short for:
jqueryplugin: {
deps: ["jquery"]
}
I don't think your code is syntactically correct.
Try this:
1. Your script should refer to the require.config in data-main.
<script data-main="PATH_TO_CONFIG_FILE" src="../../scripts/require.js"></script>
2. Quotes are missing in paths of the config file. Instead it should be like this
require.config({
baseUrl: '../../scripts',
paths: {
"app": '../../app/utilization-management',
"appIncidentTracking": '../../app/incident-tracking',
"jquery": 'jquery-3.1.1.min',
"jqueryui": 'jquery-ui-1.12.1.min',
"jqueryplugin": '../../js/jquery.plugin.min',
"timeentry":'../../js/jquery.timeentry.min',
"handlebars": 'handlebars.amd.min',
"text": 'text',
"moment": 'moment.min',
"datatable": 'DataTables/jquery.dataTables.min',
"blockUI": 'jquery.blockUI.min',
"shared": '../../app/shared',
"bootstrap": 'bootstrap.min',
"bootstrap-datepicker": 'bootstrap-datepicker.min',
"bootstrap-multiselect": '../js/bootstrap-multiselect/bootstrap-multiselect'
},
shim: {
"bootstrap": {
deps: ["jquery"]
},
"bootstrap-multiselect": {
deps: ["bootstrap"]
},
"timeentry": {
deps:["jquery", "jqueryplugin"],
exports:"timeentry"
}
}
});
3. Since your module has dependencies, list them like this:
define(["jqueryplugin","timeentry","bootstrap"],function(jqueryplugin,timeentry,bootstrap) {
$(function () {
$('.js-timeentry').timeentry();
});
});

How to load jQuery Migrate for jQuery via RequireJS?

Can I load jQuery migrate via RequireJS? I don't understand how the timing can be handled correctly. See this example:
require([
'jquery',
'jqmigrate'
], function ($) {
if ($.browser.msie) {...}
});
Isn't is possible that jqmigrate will load before jquery? Also, I do not want to keep loading jqmigrate explicitly in every module. Any way to do this in the require.config so it loads jqmigrate automatically when jQuery is required?
There are a couple of things you will need:
make sure jqmigrate depends on jquery.
you could write a wrapper module that include both, and return jquery, so your require.config could look like:
jquery-wrapper.js:
define(['jquery-src', 'jqmigrate'], function ($) {
return $;
})
require.config
{
paths: {
'jquery-src' : '/path/to/jquery',
'jqmigrate': '/path/to/jqmigrate',
'jquery': '/path/to/jquery-wrapper'
}
}
using shims worked for me. I did get stuck because i had pluralized shims its; shim
requirejs.config({
paths: {
'jquery': '//code.jquery.com/jquery-2.1.4',
'jquery-migrate': '//code.jquery.com/jquery-migrate-1.2.1'
},
shim: {
'jquery-migrate': { deps: ['jquery'], exports: 'jQuery' },
'foo': ['jquery']
}
});
require(['jquery-migrate', './foo'], ($, foo) => {
console.log('bootstrapped', $, foo);
});
jQuery Migrate 3.0.1 currently has a defect that renders it unusable for RequireJS or any AMD loader. A change is required to the UMD fragment before implementing the accepted answer:
define( [ "jquery" ], function ($) {
return factory($, window);
});
Details and solution are here.
jquery-migrate-wrapper.js
define(['jquery', 'jquery-migrate'], function ($) {
// additional initialization logic can be added here
$.UNSAFE_restoreLegacyHtmlPrefilter();
return $;
})
require-config.js
require.config({
...otherConfigOptions,
shim: {
...otherShimSettings,
'jquery-migrate':{deps: ['jquery']},
},
map: {
// provides 'jquery-migrate-wrapper' for all (*) modules that require'jquery'
'*': { 'jquery': 'jquery-migrate-wrapper' },
// but provides the original 'jquery' for 'jquery-migrate-wrapper' and
// 'jquery-migrate'
'jquery-migrate-wrapper': { 'jquery': 'jquery' },
'jquery-migrate': {'jquery': 'jquery'}
}
})

The jquery.fileupload plugin causes require.js to randomly fail imports

I'm using require.js and have a page with an from that used jquery.fileupload. After introducing the plugin I now see some files fail to be imported before the define call back is executed. This causes random errors where the libraries can't find their dependencies. It's as though require.js is moving on before all the dependencies can be resolved.
I've followed these instructions:
https://github.com/blueimp/jQuery-File-Upload/wiki/How-to-use-jQuery-File-Upload-with-RequireJS
But beyond that it's a very vanilla install. I'm using the minified versions of libraries where possible. Any insight is welcome.
here's the main.js:
(function () {
'use strict';
require.config({
baseUrl: '/js',
waitSeconds: 800,
paths: {
jquery: ['//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min',
'lib/jquery/jquery-2.0.3.min'],
'jquery.fileupload': 'lib/jquery.fileupload/jquery.fileupload',
'jquery.fileupload-ui': 'lib/jquery.fileupload/jquery.fileupload-ui',
'jquery.fileupload-image': 'lib/jquery.fileupload/jquery.fileupload-image',
'jquery.fileupload-validate': 'lib/jquery.fileupload/jquery.fileupload-validate',
'jquery.fileupload-video': 'lib/jquery.fileupload/jquery.fileupload-video',
'jquery.fileupload-audio': 'lib/jquery.fileupload/jquery.fileupload-audio',
'jquery.fileupload-process': 'lib/jquery.fileupload/jquery.fileupload-process',
'jquery.ui.widget': 'lib/jquery.ui/jquery.ui.widget',
'jquery.iframe-transport': 'lib/jquery.iframe-transport/jquery.iframe-transport',
'load-image': 'lib/load-image/load-image.min',
'load-image-meta': 'lib/load-image/load-image-meta',
'load-image-exif': 'lib/load-image/load-image-exif',
'load-image-ios': 'lib/load-image/load-image-ios',
'canvas-to-blob': 'lib/canvas-to-blob/canvas-to-blob.min',
tmpl: 'lib/tmpl/tmpl.min',
bootstrap: 'lib/bootstrap/bootstrap',
bootstrapTab: 'lib/bootstrap/bootstrap-tab',
EventEmitter: 'lib/event_emitter/EventEmitter',
linkedin: ['//platform.linkedin.com/in.js?async=true',
'http://platform.linkedin.com/in.js?async=true'],
skinny: 'lib/skinny/skinny',
selectize: 'lib/selectize/selectize.min',
sifter: 'lib/sifter/sifter',
microplugin: 'lib/microplugin/microplugin.min'
},
shim: {
bootstrap: {
deps: ['jquery'],
},
bootstrapTab: {
deps: ['jquery', 'bootstrap'],
},
linkedin: {
exports: 'IN'
},
selectize: {
deps: ['jquery', 'sifter', 'microplugin']
},
'jquery.iframe-transport': {
deps: ['jquery']
}
}
});
require(['app'], function (App) {
App.initialize();
});
}());
And the from code:
define([], function () {
'use strict';
return function () {
require(['jquery', 'tmpl', 'load-image', 'canvas-to-blob',
'jquery.iframe-transport', 'jquery.fileupload-ui'], function ($) {
$('#product').fileupload({
url: '/products/create'
});
});
};
});
The module gets called after the page has been loaded.
It's also worth noting that all files are downloaded successfully. No 404's, etc.
It turns out there is a flaw in the minified version of load-image.js that breaks how the dependencies load. I don't have exact proof as to why, it could be the smaller size causes a race condition, or it could be something weird in that particular file. What I do know is the minified version causes the random errors and the normal version does not (this is off master so I suppose I was taking a risk).
I raised a flag here
EDIT: it turns out the minified version of the plugin includes all the extensions which explains the odd dependency behavior.
The Answer from matt is the best solution in this case. Thanks a million, it save us a lot of time.
In requirejs.config, you have to add the load-image dependecies separatly - file by file.
For example:
require.config({
'jquery.ui.widget' : 'lib/jQuery-File-Upload-9.9.2/js/vendor/jquery.ui.widget',
'jquery.fileupload':'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload',
'jquery.fileupload-ui': 'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-ui',
'jquery.fileupload-image': 'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-image',
'jquery.fileupload-validate':'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-validate',
'jquery.fileupload-audio':'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-audio',
'jquery.fileupload-video':'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-video',
'jquery.fileupload-process': 'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-process',
'jquery.fileupload-jquery-ui': 'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-jquery-ui',
'jquery.iframe-transport': 'lib/jQuery-File-Upload-9.9.2/js/jquery.iframe-transport',
'load-image':'lib/load-image-1.10.0',
'load-image-meta':'lib/load-image-meta-1.10.0',
'load-image-ios':'lib/load-image-ios-1.10.0',
'load-image-exif':'lib/load-image-exif-1.10.0',
'canvas-to-blob':'lib/canvas-to-blob-2.0.5',
'tmpl':'lib/tmpl.2.4.1'
}
});
call in html site:
requirejs(['jquery',
'jquery.ui.widget',
'tmpl',
'load-image',
'jquery.iframe-transport',
'jquery.fileupload-ui'], function () {
$('#fileupload').fileupload({
url: 'photo-upload.html'
});
}
);
One possibility modify the shim:
shim: {
bootstrap: {
deps: ['jquery'],
},
bootstrapTab: {
deps: ['jquery', 'bootstrap'],
},
linkedin: {
exports: 'IN'
},
selectize: {
deps: ['jquery', 'sifter', 'microplugin']
},
'jquery.iframe-transport': {
deps: ['jquery']
},
'jquery.fileupload-ui':{
deps: ['jquery']
}
Another option downgrade jquery to 1.X (this is because the sample page is using jquery 1.X)

How to handle dependencies with requireJS

This is what my config.js file looks like:
require.config({
baseUrl: '../',
paths: {
jQuery: 'js/jquery-1.10.2.min',
uiEffectsCore: 'js/jQueryUIEffectsCore',
//Handlebars: 'js/handlebars',
SyntaxHighlighter: 'js/syntaxhighlighter/scripts/shCore',
shXml: 'js/syntaxhighlighter/scripts/shBrushXml'
},
shim: {
jQuery: {
exports: 'jQuery'
},
uiEffectsCore: {
deps: ['jQuery']
},
shXml: {
deps: ['SyntaxHighlighter']
}
}
});
require(['js/main']);
Then my main.js looks like this:
define(function(require){
require('jQuery');
require('uiEffectsCore');
require('SyntaxHighlighter');
require('shXml');
});
I think the problem is that there is no define(...) wrapper around my shXml file... I am wondering if I can make this work without having to use that wrapper. Maybe an export shim would do it.
As it stands now, i get this error every time.
This question has also been asked here on github.
Check out this article, also from github. I tested this, and it works great, but you have to replace the first line of your brush.js files (inside syntaxhighlighter) with this line here:
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
I don't even know why that fixes the issue, but it does, and you can load your scripts like this:
define(function(require){
require('jQuery');
require('uiEffectsCore');
require('SyntaxHighlighter');
require('shXml');
require('shCss');
require('shJs');
require('Raphael');
And you need a shim in your config for dependencies:
paths: {
SyntaxHighlighter: 'js/syntaxhighlighter/scripts/shCore',
shXml: 'js/syntaxhighlighter/scripts/shBrushXml',
shCss: 'js/syntaxhighlighter/scripts/shBrushCss',
shJs: 'js/syntaxhighlighter/scripts/shBrushJScript'
},
shim: {
shXml: {
deps: ['SyntaxHighlighter']
},
shCss: {
deps: ['SyntaxHighlighter']
},
shJs: {
deps: ['SyntaxHighlighter']
}
}

How to optimize requireJS application setup?

I have a working application using requirejs, which I'm trying to optimize. I'm launching the application in 2 steps:
First I start with a setup file setup.js, which I'm calling from the page source code:
<script data-main="../js/setup" src="../js/l/require/require.js"></script>
This file contains my require setup
var IS_LOCAL = /(:\/\/localhost|file:\/\/)/.test(document.location.href);
requirejs.config({
waitSeconds: (IS_LOCAL ? 2 : 45),
baseUrl: "../js",
paths: {
intro: 'intro',
overrides: 'overrides',
jquery: 'l/jquery/jquery-1.8.2.min',
mobile: 'l/jquery-mobile/jquery-mobile-1.3pre.min',
multiview: 'p/multiview/multiview.min',
respond: 'p/respond/respond.min',
i18next: 'p/i18next.min.js'
},
shim: {
'overrides': { deps: ['jquery'] },
'mobile': { deps: ['jquery'] },
'multiview': { deps: ['jquery', 'mobile'] },
'respond': { deps: ['jquery'] },
'i18next': { deps: ['jquery'] }
}
});
// launch application - works, but I'm not happy with it
requirejs('overrides','jquery','mobile','multiview','respond','i18next','intro'],
function (overrides, $, mobile, multiview, respond, i18next, Intro) {
'use strict';
Intro.start(overrides, $, mobile, multiview, respond, i18next);
}
);
This "triggers" my application controller intro.js, which looks like this:
define([], function () {
'use strict';
var start = function () {
require(['overrides','jquery','mobile','multiview','respond','i18next'],
function () {
// stuff
}
); // end require
} // end start
return {
"start": start
};
});
I'm still figuring out my way with requireJS, so while the above initializes correctly, I'm not sure if this is the best way to handle. Specifically I'm wondering:
Questions:
1) In my setup.js file, I'm triggering Intro.start() with plenty of parameters. Do I need the parameters there or should I put them inside intro.js when I'm doing my second require call?
2) Do I need the first require at all, because I'm requiring all files and then trigger a "file" (intro), which requires everything again?
3) How do I make objects available in intro.js? Say I need the i18next object inside intro.js to do some manual translations. Do I export in the shim and pass along through my two requires?
Thanks for some insights!

Categories