When I use requirejs (v2.1.13) to include log4javascript (v1.4.10) js variable log4javascript is undefined however as I can see in chrome network console log4javascript.js is loaded successfully.
Here is my requirejs config:
requirejs.config({
'baseUrl': 'resources/js',
'paths': {
'angular': 'libs/angularjs/angular',
'jquery' : 'libs/jquery/jquery-2.1.1.min',
'bootstrap' : 'libs/bootstrap/bootstrap',
'log4javascript': 'libs/log4javascript/log4javascript_uncompressed'
},
'shim' : {
'angular' : {'exports' : 'angular', deps: ['jquery']},
'jquery': {'exports' : 'jquery'},
'bootstrap': {'exports' : 'bootstrap', deps: ['jquery']}
}});
Sine 1.4.10 log4javascript should support AMD so I don't need to add shim.
I can't understand what am I doing wrong. Please help!
UPD: It seems something wrong with AMD support in version 1.4.10, because when I commented out following lines in "log4javascript_uncompressed.js" and added shim, everything became fine:
/*
if (typeof define == "function" && define.amd) {
// AMD. Register as an anonymous module.
define(factory);
} else if (typeof module != "undefined" && typeof exports == "object") {
// Node/CommonJS style
module.exports = factory();
} else {
// No AMD or CommonJS support so we place log4javascript in (probably) the global variable
*/
root.log4javascript = factory();
//}
When I use requirejs (v2.1.13) to include log4javascript (v1.4.10) js variable log4javascript is undefined however as I can see in chrome network console log4javascript.js is loaded successfully.
Which is exactly what would happen if everything is working perfectly. Look at the code you commented out. When log4javascript detects an AMD loader it does not leak a variable named log4javascript into the global space. It leaks that variable only if it detects neither an AMD loader or that it is running in Node.
If the code that uses log4javascript is all in AMD modules, then the proper way to access log4javascript is to include it as a dependency in the define or require calls. For instance, require(['foo', 'log4javascript'], function (foo, log4javascript) {...});
If you have to work with code that expects a log4javascript variable to exist in the global space you can work around it by deliberately leaking the variable. See this answer for details of how to do it.
Related
I'm trying to use Jest for unit testing my React code but I'm also using requirejs and so all my React code is in AMD modules. It obviously works well in browser but when I run Jest tests, it can't load my AMD modules.
Initially it was giving me error for define saying define is not defined, so I used amdefine by Requirejs to fix it. Now it can understand define but still can't load my module.
I had the same problem today and here is what I've done :
Module.js
(()=> {
const dependencies = ['./dep.js'];
const libEnv = function (dep) {
// lib content
function theAnswer (){
return dep.answer;
}
return {theAnswer}; // exports
};
//AMD & CommonJS compatibility stuff
// CommonJS
if (typeof module !== 'undefined' && typeof require !== 'undefined'){
module.exports = libEnv.apply(this, dependencies.map(require));
module.exports.mockable = libEnv; // module loader with mockable dependencies
}
// AMD
if (typeof define !== 'undefined') define(dependencies, libEnv);
})();
You will found all needed files on my github repository to test :
in browser for requirejs
with node for jest
https://github.com/1twitif/testRequireJSAmdModulesWithJest
I ran into same problem, so I went ahead and mocked my dependency at the top of test file:
jest.mock('../../components/my-button', () => {
// mock implementation
})
import MyButton from '../../components/my-button';
This way, when MyButton is loaded, its dependency is already mocked, so it won't try to load the RequireJS module.
There's no official Facebook support for requirejs in Jest yet. But's planned. Look this thread:
https://github.com/facebook/jest/issues/17
Also in this thread Sterpe posted a plugin he wrote to do it (but I didn't try it):
https://github.com/sterpe/jest-requirejs
I thought I'd be able to expose my JS library to Require.js, and make it dependent on jQuery, Backbone, and Underscore, with the following code:
} else if (typeof define === 'function' && define.amd) {
define(['backbone', 'jquery', 'underscore'], function(Backbone, $, _) {
return factory(root, Backbone, $, _);
});
where factory is a function that returns my library. That seems ok, except that the module name "backbone" appears to be hard-coded to the filesystem path "{Require root}/backbone". Even if I define a path in my Require config before requiring the library:
'backbone': '/some/other/path/backbone'
my browser still gives me an error:
GET http://localhost:8000/js/backbone.js 404 (NOT FOUND)
Can anyone explain how I can define "this library depends on Backbone" without saying "this library requires exactly {root}/backbone.js"?
That is exactly what Backbone does so I'm not sure why you're having problems. Can you post the code of how you're requiring this library and where you're defining your require config?
if (typeof define === 'function' && define.amd) {
define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
I'm trying to bring the Underscore.String library in to a Require.js project. The library is setup to support AMD, with the following code:
} else if (typeof define === 'function' && define.amd) {
// Register as a named module with AMD.
define('underscore.string', [], function() {
return _s;
});
But I have a problem: I don't keep the library in my root path, I keep it in "ext/underscore.string". This seems to make it impossible to require the library.
I have tried requiring both "ext/underscore.string" and "underscore.string", with and without defining a path (of "underscore.string": "ext/underscore.string"). When I don't have a path, and I require "underscore.string" the file (unsurprisingly) doesn't load, and in all other cases the file loads but the library doesn't get defined.
If I try to reference the library afterwards I get:
Error: Module name "underscore.string" has not been loaded yet for
context:
... even if I do so immediately after the define line (in the code above)! In other words, if I change the code to
define('underscore.string', [], function() {
return _s;
});
console.log(require('underscore.string'))
Require tells me that "underscore.string" hasn't been loaded yet!
Can anyone help me figure out how I can bring this library in to my codebase?
In your require configuration do:
var require = {
...
map: {
"*": {
"underscore.string": "path/to/file/disregarding/baseUrl"
}
}
};
NOTE: The path to file should include the baseUrl, so in your case and assuming baseUrl="scripts", it would be something like:
"scripts/ext/underscore.string.js"
NOTE 2: It needs the .js extension, i.e. it is exact file name.
Suppose I have a JS-library, neatly wrapped in a define('myModule', function(myModule) { return myModule.someObject; });
How could I bind the myModule.someObject to global scope (please don't ask why, I know modular programming has a lot of benefits over putting stuff on the global scope), without using requirejs or any other module handling framework?
The thing is: while developing, I'd like to use requirejs. The library that we build should be able to be included by somebody using requirejs (AMD, CommonJS, whatever), but should also be available as window.SomeObject for the people that don't want to use require just for the sake of being able to use our SomeObject. After the development phase, all code will be minified and obfuscated to a single JS file.
I think I'm just googling with the wrong search terms, because all I can find is an answer to the question how to include code that isn't wrapped in a requirejs friendly define function.
Any ideas on this would greatly be appreciated. Thanks!
--- EDIT ---
My file (before it all started) looked like:
(function(define, global) {
define([a,b,c],function(theA, theB, theC) {
return theA + theB + theC; // or something, it doesn't matter
});
})(define, this);
I'm thinking of something like this:
(function(define, global) {
// same as above
})(typeof define === 'function'
? define
: function(factory /* need more args? */) { /* solution here */ }, this);
But I'm not sure how to implement it properly...
I guess you need to wrap your modules so that they could be accessed without requirejs:
if ( typeof define === "function" && define.amd ) {
define( "mymodule", [], function () {
// do your logic
return mystuff;
} );
} else {
// do your logic
window.mystuff = mystuff;
}
Look at jQuery as an example.
I would refrain from giving your module an id if you can help it, it makes it less portable. jQuery is incredibly annoying that it forces you to set a jquery path option, but they did it for compatibility reasons. Always prefer anonymous modules if you can.
From the jQuery source
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
James Burke goes into a little more detail here also.
I would instead use a more common example from the umdjs repository:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['b'], factory);
} else {
// Browser globals
root.amdWeb = factory(root.b);
}
}(this, function (b) {
//use b in some fashion.
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
return {};
}));
For another example that also supports CommonJS, check out the reqwest library:
!function (name, context, definition) {
if (typeof module != 'undefined' && module.exports) module.exports = definition()
else if (typeof define == 'function' && define.amd) define(definition)
else context[name] = definition()
}('reqwest', this, function () {
return {};
});
How can I provide a library to others that does not depend on RequireJS?
This allows you to ship code that does not ship with all of RequireJS, and allows you to export any kind of API that works on a plain web page without an AMD loader.
You need to make a build config file which uses wrap and almond.
It all feels pretty dirty, but I've had it working (by following the almond ReadMe) with exactly what you're describing.
Say I want to use jquery together with a standard, non-amd enabled jquery plugin that has been defined using standard closure: (function($))( $.fn.myplugin = { ... } )(jQuery); and it all sits inside of a js/libs/jquery/jquery.myplugin.js.
I use this config:
require.config({
baseUrl: 'js/',
paths: {
'jquery': 'libs/jquery/jquery-noconflict',
'underscore': 'libs/underscore/underscore',
'backbone': 'libs/backbone/backbone',
'jquery-myplugin': 'libs/jquery/jquery.myplugin'
},
shim: {
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'jquery-myplugin': {
deps: ['jquery']
}
});
I load jQuery in no-conflict mode in libs/jquery/jquery-noconflict.js, becase I don't want to pollute global namespace:
define(['libs/jquery'], function () {
return jQuery.noConflict(true);
});
and this is how I load my main app.js:
define([
'jquery',
'underscore',
'backbone',
'jquery-myplugin'],
function($, _, Backbone, MyPlugin){
//MyPlugin is always undefined, not even sure if
//I should be passing it here if it only extends jQuery?
});
Now, here is the problem I am experiencing - while I can use all libraries defined above without any problems, I could not work out the correct shim configuration to load non-AMD enabled jquery plugins.
I've tried setting up jquery-myplugin as deps of the jquery (and other way around) but I could never get it working.
It seems like I'm having problem with the following scenario:
jQuery loads in no-conflict mode.
plugin code runs, extending the instance of the jQuery above
I can use $ within my application, extended by the plugin code, so $.myplugin is available.
I have seen similar questions floating around but none of them actually resolves this issue giving only vague suggestions such as "use shim config"...
Edit
I also tried using
"jquery-myplugin": {
deps: ["jquery"],
exports: "jQuery.fn.myplugin"
}
And whilst plugin methods are available once loaded as AMD module this way, I still can't access: $('.class').myplugin() as default $ object hasn't been extended with myplugin code.
Using jQuery.noConflict(true) removes the jQuery global variable. When your plugin loads, it tries to access jQuery, but can't, causing this failure.
If your plugin was a module, it could get access to jQuery as a dependency. Or you could leave jQuery available as a global.
First, insure that "path/to/jquery-myplugin" actually extends window.jQuery and not $
noConflict() leaves window.jQuery object defined but unbinds itself from window.$ On some new browsers window.$ is built in alias for native document.querySelectorAll function.
Second, your myplugin does NOT need to return itself, as it cannot be used by itself. Since it extends jQuery, return jQuery from myplugin call.
Lastly, "path/to/jquery-myplugin" is NOT a module. It's a plain JS file. It's possible RequireJS tries to load it like a module and does not find define() call, which leads to mess. Try actually adding ".js" file extension to the reference to signal to RequireJS that it needs to use "js!" plugin to load the resource.
require.config({
paths: {
"jquery": "path/to/jquery",
"jquery-myplugin": "path/to/jquery-myplugin.js"
},
shim: {
"jquery": {
init: function() {
return window.jQuery.noConflict();
},
"jquery-myplugin": {
deps: ['jquery']
init: function($) {
return $;
},
}
}
});
I had the same problem as you today. Here is how I could fix it :
requirejs.config({
"baseUrl": "js/lib",
"paths": {
"app": "../app"
}
});
// Final version of jQuery with all needed plugins.
define("jquery", ["jquery-core", "myplugin"], function(jqCore) {
return jqCore;
});
// Define core jQuery module.
define("jquery-core", ["jquery-1.9.1.min"], function() {
return jQuery.noConflict(true);
});
// This module exposes jquery module to the global scope and returns previous defined version.
define("jq-global", ["jquery-core"], function(jqCore) {
var tmp = jQuery;
jQuery = jqCore;
return tmp;
});
// Define your plugin here, and don't forget to reset previous jQuery version.
define("myplugin", ["jq-global", "jquery.myplugin"], function(jqGlobal, jqPlugin) {
jQuery = jqGlobal;
});
// Load the main app module to start the app
requirejs(["app/main"]);
Now in my app/main.js file I can do the following :
define(["jquery"], function($) {
$('body').myplugin();
});
The idea here is to expose jQuery temporary before plugin code is executed. So far I didn't test the solution in a larger environment with a lot more modules to load, so I can't guarantee it will work in the long term ;)
Edit
This solution won't work!! Since requirejs doesn't load the scripts sequentially, it is possible the plugin js file loads before jquery which will cause the execution to fail. Sorry for this.
If someone has another idea...