Packaging a Library for AMD/Require.js With Dependencies - 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) {

Related

Not able to load AMD modules through Jest

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

UMD javascript module which also works in strict mode

I'm having trouble rewriting this to work in 'strict' mode. Since 'this' is not defined explicitly I'm getting jshint errors on compile. I'm thinking my brain is just not thinking abstractly enough to find a creative solution. Any help would be appreciated. Code adapted from the Universal Module Definition Github repo: https://github.com/umdjs/umd/blob/master/returnExports.js
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD Module
define([], factory);
} else if (typeof module === 'object' && module.exports) {
// Node Module
module.exports = factory();
} else {
// Browser Global
root.returnExports = factory();
}
}(this, function () {
return {};
}));
Looking at your code, I see that root is only actually used in the case that you are in a browser, which simplifies things.
That means that we can replace this with the following expression:
typeof window !== "undefined" ? window : undefined
This is valid in strict mode (I tried it in Node, it returns undefined, no errors), and JSHint.com allowed it.
If you need the global object in other cases as well, you can chain the ternary expressions.

log4javascript is undefined when I try to include it using RequireJS

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.

Require.js Can't Load Library That Defines its Own Alias

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.

How do you use a requirejs friendy JavaScript file without using requirejs? I.o.w. how to demodularize?

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.

Resources