RequireJS Passing Dependencies - javascript

Not sure if this has been asked already but I am just wondering if importing a dependency using RequireJS to one file and then importing that file to another means the second file has to import the same dependency as the first file.
example -
file A
define([
'jquery'
],function($) {
//jquery thing here
}
File B
define([
'A'
],function(A) {
// do some jquery thing here
}
or
define([
'jquery','A'
],function($,A) {
// do some jquery thing here
}

It is good modularization practice to have each module list its own dependencies explicitly rather than silently depend on a module being loaded through an intermediary. So your module B should take the second form you suggested for it: define(['jquery', 'A'], function ($, A) {....
Now, strictly speaking, you could have B only require A and you would be able to use jQuery in B without B having an explicitly dependency on jQuery. This is doable because jQuery, even when it is loaded as an AMD module, by default leaks $ and jQuery into the global space just like it does when it is loaded outside RequireJS. However, it is not good practice. You should not rely on this though unless you have a substantial reason to do so and document it very verbosely.

You will have to use the third option, because otherwise $ will be undefined in the module B. But this doesn't mean RequireJS will import jQuery twice internally, it will just pass you the $ variable.
define([
'jquery','A'
],function($,A) {
// $ was passed as a function argument.
}

Related

Can not include JQuery without npm in Vue JS project

I'm trying to import JQuery without using npm to my Vue JS project. Here's what I'm trying:
***jquery-functions.js***
import '../../public/js/jquery.min.js'
export function bar(){ $(".foo"){...} }
/$ is not defined as function/
var hello is evaluated in module scope, this prevents variables from leaking to global scope.
In order for a global to be defined, it should be assigned explicitly as such:
window.hello = function (x){x+5};
As for jQuery, it's specific to how the module works. It's UMD module and it isn't exposed as a global when jquery.min.js is imported as a module.
It should be assigned explicitly as a global either:
import jQuery from '../../public/js/jquery.min.js';
window.$ = window.jQuery = jQuery;
Or this can be done by means of Webpack that is used by Vue CLI internally, as the answer in related question suggests.
I tried everything above but somehow I couldn't get it working. Either eslint was giving function not defined error for $() or bootstrap couldn't see the included jQuery. I don't know if it's ok to include jQuery globally but I found the solution by including jQuery to my index.html file with <script> tags. Then in my jquery-functions.js file I disabled eslint then everything was working just fine on run time.
***jquery-functions.js***
/* eslint-disable */
export function bar(){ $(".foo"){...} }
I did it like that so that I can separate jQuery methods from from Vue JS methods. It might be better to use npm to avoid including jQuery globally so that you can include it only in components that you need. For me I was concerned with compatibility of all other (6 of them) jQuery dependent libraries included in the template that I downloaded from internet.

How to import jQuery only in certain modules with Webpack 4?

I'm using Webpack 4 in a Codeigniter project. A lot of my Javascript code still depends on jQuery (installed through npm), so I have this Webpack configuration:
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
}),
It works, but I'm planning to ditch jQuery, or at least to depend less on it, so instead of importing it globally, I would like to import it only in the modules where it's needed.
I tried removing the above config and added it in a module:
import { $, jQuery } from 'jquery';
import Dropzone from 'dropzone';
When loading the page I receive this error in the console:
myDropzone.js:95 Uncaught TypeError: Object(...) is not a function
at Object.<anonymous> (myDropzone.js:95)
at r (bootstrap:76)
at t (bootstrap:43)
at bootstrap:134
at bootstrap:134
The code causing the error:
$('.dropzone').each(function () { // <--- this line
$(this).dropzone(config);
});
In the console I tried checking for $ and jQuery and the first one works fine, but with jQuery I get an error saying that it's not defined
Ok, I am pretty sure the following happens:
You are loading the jQuery dropzone plugin somewhere high up in the dependencies tree, probably loaded by some other package. The plugin expects to find the jQuery object in the global scope, in order to attach itself to it (hence giving you access to the $().dropzone method, see here ). By using the ProvidePlugin when the dropzone plugin tries to attach itself onto the jQuery object, there is no problem
However since you are now removing the ProvidePlugin the dropzone plugin never manages to attach itself and so there is no $().dropzone method available for use, so you get that error
Long story short, as long as you are depending on external code that assumes that jQuery is loaded in the global scope, you cannot truly eliminate the usage of webpack.ProvidePlugin, unless of course you directly modify the source code of those dependencies.
Try using
import $ from 'jquery';
window.jQuery = $;
window.$ = $;

requirejs export global variable

I am trying to use bootbox (http://bootboxjs.com) with requirejs.
main.html
<script>
var require = {
baseUrl: 'js',
paths: {
"jquery" :['jquery-1.11.0.min'],
"bootbox" :['bootbox.min'],
"bootstrap" :['//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min']
},
shim:
'bootstrap' :{deps:['jquery']},
'bootbox' :{deps:['bootstrap'],exports: 'bootbox'}
}
}
</script>
<script src="require.min.js"></script>
<script src="myscript1.js"></script>
main.js
define(['bootbox'],function(bootbox){
bootbox.alert("Hello world!"); // working properly
});
myscript1.js
require(['main'],function(){
bootbox.alert("Hello world!"); // not functioning (bootbox is not defined)
});
Normally once bootbox plugin is loaded, we can use bootbox anywhere on the page with this: bootbox.alert("Hello world!"); When using requirejs, I have to pass the bootbox variable and define it everytime when using requirejs in order to use bootbox. I have tried with "exports", but it doesn't seem help.
How can we have the bootbox variable available globally once it is loaded?
Thank you.
Here's the deal. Bootbox detects whether it is running in an AMD loader in place (like RequireJS). If so, it won't export anything into the global space but will instead define itself as an AMD module, to be loaded by an AMD loader.
Tidoo's suggestion of loading Bootbox with a script tag works, if you do it carefully. You'd have to load Bootbox before you load RequireJS, for one thing. Otherwise, it would detect that RequireJS is loaded, determine that it is running with an AMD loader, and define itself as an AMD module. This would cause a mismatched anonymous module error from RequireJS. Another thing is that you'd have to load jQuery outside RequireJS and load it before Bootbox. So that's another script tag.
I'd suggest avoiding that solution by simply modifying your code to add the required dependency:
require(['bootbox', 'main'],function(bootbox){
bootbox.alert("Hello world!");
});
Also, you must not use a shim configuration for Bootbox because it detects whether there is an AMD loader around and calls define by itself if it detects one. A shim configuration is needed only for code that does not call define.
If you want Bootbox to be available globally you should include it manually with a script tag. RequireJS doesn't expose it.
However, I highly recommend against this. The whole idea of dependency frameworks such as RequireJS is that you don't define anything on global scope, but to make your dependencies explicit. This not only allows you to lazy load scripts, but it also makes it possible to later replace dependencies, e.g. for unit testing.
EDIT:
As Louis correctly mentioned Bootbox already has AMD support. If it detects RequireJS (or any other AMD loader) it doesn't expose anything to the global scope, but since it has AMD support you also don't need to shim it.

RequireJS - change jQuery module name

I have a file called "lib.jquery.js" (all libraries are starting with "lib." and not reusable application modules are starting with "app.") in my baseUrl directory, and a module definition:
define([
"lib.jquery"
],
function(
jQuery
){
console.log(jQuery) // undefined
})
But jQuery here is undefined because jQuery module name is hardcoded inside it as "jquery" but not "lib.jquery". How do I configurate RequireJS correctly to make all loading modules check "lib.jquery" file when requesting "jquery" or force jQuery module to be named "lib.jquery"?
The jquery script defines the module as 'jquery' and expects that you will simply reference it as 'jquery'. This is done because one should not load 2 jquery files of different versions.
Workaround would be put the lib.*.js files into a separate directory called lib.
define(['lib/jquery'], function (jQuery) {
});
I have found the solution here: Use requirejs and jquery, without clobbering global jquery?
Renamed file lib.jquery.js to lib.jquery-core.js
Created file lib.jquery.js with "jquery loader module":
define(['lib.jquery-core'], function () {
return jQuery.noConflict(true);
});
Now it's working as intended to. Hardcoding names is evil.

Testing Custom Modules with DOH

I'm trying to build some unit tests for an old JS file/module that is out of my control.
The JS module is built using the following pattern...
var myModule = {
myMethod:function() {
}
};
I am then trying to build a DOH test harness to test this. I tried the following...
require([
"doh/runner",
"../../myModules/myModule.js"
], function(doh) {
console.log(doh);
console.log(myModule);
});
The file seems to be getting picked up fine but I can't reference anything in it. "console.log(myModule);" just returns undefined.
Anyone know how I can correctly include an external non dojo module JS file in a DOH test harness?
Thanks
Other than you shouldn’t be using DOH because it is deprecated (use Intern), there is no reason that you shouldn’t see myModule there. You are using a script address and not a module ID, which isn’t right, and you are using a relative path with a require call, which is also not right, but if either of these things were preventing the loader from finding and loading the script you are trying to load it should be throwing an error that you could see in the console. The only other possibility is you have somehow managed to build a built layer into this myModule script, in which case the entire script ends up wrapped in a closure and so using var foo will no longer define a global variable foo.
You need to declare myModule in the function callback to your require statement:
require([
"doh/runner",
"../../myModules/myModule"
], function(doh, myModule) { // <-- include myModule
console.log(doh);
console.log(myModule);
});
Just be sure that myModule.js returns your module.

Categories

Resources