Emberjs resolver, amd and non-amd modules - javascript

I'm trying to use alertify with Emberjs. Thats how it is exported.
// AMD and window support
if (typeof define === "function") {
define([], function () { return new Alertify(); });
} else if (typeof global.alertify === "undefined") {
global.alertify = new Alertify();
}
I have put this line to Brocfile.js
app.import('./bower_components/alertify.js/lib/alertify.js');
But it thinks that it is AMD and to sum up I cant use it.
How should I handle it?

The reason is Ember does not work with unnamed AMD modules.

Related

RequireJS optimized file returns undefined

We are trying to minify/obfuscate a js library, so that we can reuse it in other projects. Background info: I have done some js, but i'm new with AMD or requireJS.
Here's a reduced version of the library, retaining only the format:
(function (global, factory) {
if ( typeof exports === 'object' && typeof module !== 'undefined'){
factory(exports);
}
else if (typeof define === 'function' && define.amd){
define(['exports'], factory);
}
else{
global['SimpleMath'] = factory({});
}}(typeof global !== "undefined" ? global : self.window || self.global,
(function (exports) {
'use strict';
exports.square = function square(value){
return value * value;
}
exports['square'] = exports.square;
return exports;})));
Inside the main.html we have
requirejs(['./libs/SimpleMath'], function (smath){
console.log(smath);
console.log(require.s.contexts._.defined);
});
This works and we can see the loaded object print out.
Since we wish to optimize/obfuscate the code, we are trying requirejs' optimizer (single js file):
node ../../r.js -o name=SimpleMath out=SimpleMath.min.js baseUrl=.
And we do get something that looks like a minified file.
However, if now I try to load the minified version with the same method:
requirejs(['./libs/SimpleMath.min'], function (smath){
console.log(smath);
console.log(require.s.contexts._.defined);
});
we get 'undefined' for the print out instead.
I can't tell if the original code was wrong, or we are not using the optimizer correctly, or we totally got the concept wrong. Any help or pointers is much appreciated. Thanks in advance.
Answering myself in case someone might find it useful: The minified file was exporting a named module like this
define('SimpleMath',['exports'],t)..
we had to either
load it as a named module with require.config or,
make it anonymous, which seems to be the recommended option for our case.

Call of anonymous function (vanilla js, pure js, no jquery)

I want to grab browser version and OS from useragent via js - this is a practicing example (cause yes - I know - feature detection is how you do it properly ;).
I stumbled across a little library that does so and now I'm trying to understand whats going on.
See this Codepen: http://codepen.io/anon/pen/gPWZGE?editors=001
obviously by running bowser.version - you get the version extracted from the browsers useragent. However the function bowser itself is an anonymous function - even though I can access elements within this function which has to do with this part of the code
!function (name, definition) {
var module;
var define;
if (typeof module != 'undefined' && module.exports) module.exports = definition();
else if (typeof define == 'function' && define.amd) define(definition);
else this[name] = definition();
}
To be honest I have hardly any idea whats going on there - can someone please explain what those lines are doing?
Thanks a lot
Ok, so step by step ...
first you have an IIFE
!function( name, definition ) {
// some code
}( 'bowser', function(){
// your module code
});
this calls the first function immediately with two parameters: the name of the module (here "bowser") and the actual definition function. In that definition function you create the module: You define any objects, properties and whatever else it needs to work. Important point is: You interface (the view the "outside" has on your module, has to be returned by that defintion function (in your codepen this is line 282: return bowser;).
The outer function then determines, how to publish your module:
First it looks for a CommonJS environment:
typeof module != 'undefined' && module.exports
This would be used, e.g., inside NodeJS. If it found the respective objects, it will export your module as a CommonJS module: module.exports = definition().
If this was not a CommonJS environment, the script looks, if it is an AMD (for example, requireJS):
typeof define == 'function' && define.amd
Again, if that matches, the module is exported as a AMD module: define(definition).
Finally, if this is neither CommonJS nor AMD, the script assumes it is a (vanilla) browser or something similar and just attaches the module to the global namespace:
this[name] = definition();
Note, that each time the definition function is called and the return value is exported as a module. This is why your definition function has to return the module interface.

Advice to resolve window dependency when running in node.js

I'm trying to extend my browser-side library's runtime environment to node.js. I implemented the Universal Module Definition (UMD) pattern to do that. It works with AMD implementation and <script> but doesn't work in node.js since there is no window.
The dependencies in question are WebSocket, EventSource, XMLHttpRequest, document. The detail is described in here: https://github.com/flowersinthesand/portal/issues/115 So what is the best approach to resolve window dependency in node.js? I have though the following way to do that. Since I'm new to node.js, these are somewhat unfamiliar and I don't know which way is natural. Though I'm trying to support node.js, I don't want to change too much something.
The following code snippet comes from https://github.com/flowersinthesand/portal/blob/master/portal.js
Using jsdom
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(function() {
// Passes the window
return factory(root);
});
} else if (typeof exports === 'object') {
// Node
module.exports = factory(require('jsdom').something);
} else {
// Browser globals, Window
root.portal = factory(root);
}
}(this, function(window) {
If the jsdom supports the above dependencies well, this looks best. If it works, however, I wonder why client of sockjs, socket.io and engine.io don't use jsdom. Maybe, they are for node rather than browser? performance?
Making window as a plain object of dependency
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(function() {
// Passes the window
return factory(root);
});
} else if (typeof exports === 'object') {
// Node
module.exports = factory({
WebSocket: require('package name for WebSocket').something,
EventSource: require('package name for EventSource').something,
document: require('jsdom').hmm,
// ...
});
} else {
// Browser globals, Window
root.portal = factory(root);
}
}(this, function(window) {
It looks picky and somewhat uncomfortable to make a group of dependency, window, But, I want to preserve current code if possible. Also, jsdom may be required as well to resolve document used to do HTTP request by script tag when XMLHttpRequest can't work due to cross-domain or unloading event and this situation includes IE 6. It's possible to separate logic using document to use something supported in node and script tag in browser checking what the current runtime is, but it's big change for me.
(function(root, factory) {
if (typeof define === "function" && define.amd) {
// AMD
define(function() {
return factory(root);
});
} else if (typeof exports === "object") {
// Node
module.exports = factory(function() {
// Prepare the window powered by jsdom
var window = require("jsdom").jsdom().createWindow();
window.WebSocket = require("ws");
window.EventSource = require("eventsource");
return window;
}());
// node-XMLHttpRequest 1.x conforms XMLHttpRequest Level 1 but can perform a cross-domain request
module.exports.support.corsable = true;
} else {
// Browser globals, Window
root.portal = factory(root);
}
}(this, function(window) {

JavaScript Modules, Closures and Scope

I am using the following closure pattern to modularise my code:
(function(root) {
// MODULE CODE HERE
if (typeof module !== 'undefined' && module.exports) { // CommonJS
/* var dependencies = require(...) */
module.exports = myModule;
} else if (typeof define !== 'undefined' && define.amd) { // AMD
/* var dependencies...; */
define([/* dependencies */], function(/* dependencies */) {
/* Assign closure level vars to respective arguments */
return myModule;
});
} else {
// Dependencies??
root.myModule = myModule;
}
})(this);
i.e., We use feature detection to support CommonJS modules (e.g., node.js), AMD or basic global namespace instantiation.
This works fine in node.js; I haven't tested the AMD pattern yet, as I'm still reading up on it (See Edit 2: AMD exhibits the exact same effect); but it fails in the browser if the module has any dependencies. That is, say, if myModule references something that is defined in a different module: For example, say if I had super.js and child.js with respective module definitions, as above, where super.js creates a function called root.super (root === window in the browser), if child.js tries to do super(), I will get something like super is not a function.
What's going on here?
To try to fix it, I changed the order in which super.js and child.js are loaded in <script> elements: No luck. Then I tried forcing child.js to load when the document is ready, using jQuery:
$(document).ready(function() {
$.getScript('child.js', function() {
// Do stuff with child, which calls super
});
});
...again, same problem. However, in both cases, if I enter the console, super is available and defined as I'm expecting.
Why is super in child.js presumably from a different (i.e., not the global) scope?
I should add, if I remove the dependency injection bit in the CommonJS export, it fails in node.js with the same error (if there are any dependants).
EDIT #Amberlamps' answer solved the problem, but it didn't answer the question as to why this occurs. My module pattern is now:
(function(root) {
// MODULE CODE HERE
if (typeof module !== 'undefined' && module.exports) { // CommonJS
/* var dependencies = require(...) */
module.exports = myModule;
} else if (typeof define !== 'undefined' && define.amd) { // AMD
/* var dependencies...; */
define([/* dependencies */], function(/* dependencies */) {
/* Assign closure level vars to respective arguments */
return myModule;
});
} else {
if (root.hasOwnProperty(/* dependencies */)) {
/* var dependencies = root... */
root.myModule = myModule;
}
}
})(this);
This keeps dependants with a common name, across environments. However, the question remains: Why is the global object not available within the closure's scope?
EDIT 2 I've been experimenting with RequireJS and AMD and have corrected my code, above, so that the AMDs work. Exactly the same thing happens in this case, too: You have to explicitly assign the global object to a variable within the closure for it to be available within said closure...
This pattern works just fine. If you actually tested it with a function called super and calling it via super(), you might ran into an error, because super is a reserved word. Following code works fine:
(function(root) {
root.super = function() {
console.log("hello");
};
}) (window);
(function(root) {
root.super();
}) (window);
You can call your function using window.super(). super() however will result in an error.

requireJS optional dependency

I'm adding AMD support to a javascript library I develop.
This library may use jquery but it will still work if jquery isn't loaded.
When defining the module dependency there's a way to set a dependency as 'optional' so that if that library is missing the module will still work?
I've had exactly the same problem recently, and here's how I fixed it. I defined a RequireJS plugin called optional which ignores modules that fail to load by explicitly defining them as an empty object (but I suppose you could also define it as null or anything else if you wanted).
Here is the code (tested with RequireJS 2.1.15):
define("optional", [], {
load : function (moduleName, parentRequire, onload, config){
var onLoadSuccess = function(moduleInstance){
// Module successfully loaded, call the onload callback so that
// requirejs can work its internal magic.
onload(moduleInstance);
}
var onLoadFailure = function(err){
// optional module failed to load.
var failedId = err.requireModules && err.requireModules[0];
console.warn("Could not load optional module: " + failedId);
// Undefine the module to cleanup internal stuff in requireJS
requirejs.undef(failedId);
// Now define the module instance as a simple empty object
// (NOTE: you can return any other value you want here)
define(failedId, [], function(){return {};});
// Now require the module make sure that requireJS thinks
// that is it loaded. Since we've just defined it, requirejs
// will not attempt to download any more script files and
// will just call the onLoadSuccess handler immediately
parentRequire([failedId], onLoadSuccess);
}
parentRequire([moduleName], onLoadSuccess, onLoadFailure);
}
});
You can then require a module optionally using simply
require(['optional!jquery'], function(jquery){...});
knowing that if the jquery module could not be loaded, the parameter passed to your callback function will be an empty object.
You cannot really set it optional, but you can catch the error and unload the module using undef:
require(['jquery'], function ($) {
//Do something with $ here
}, function (err) {
//The errback, error callback
//The error has a list of modules that failed
var failedId = err.requireModules && err.requireModules[0];
if (failedId === 'jquery') {
//undef is function only on the global requirejs object.
//Use it to clear internal knowledge of jQuery. Any modules
//that were dependent on jQuery and in the middle of loading
//will not be loaded yet, they will wait until a valid jQuery
//does load.
requirejs.undef(failedId);
...
}
});
Full example here.
A plugin is not needed for this.
This can be done without plugins for RequireJS. In addition, you can do this for UMD modules as well.
Using jQuery only when it's already loaded
It's actually pretty simple, using require.defined, which lets you test whether a module has already been loaded or not. If so, you require jQuery and use it, otherwise you just skip the optional part:
define(['require'], function(require){
if (require.defined('jquery') {
var $ = require('jquery');
$.fn.something = function(){};
}
});
Notice how we add 'require' as a dependency, so we get a local require function that has the defined method on it.
Also note that this code will only find jQuery if it has been loaded prior to this module. If some module loads jQuery after this module has already loaded then it will not pickup jQuery afterwards.
This will not attempt to load jQuery and hence will not cause an error message in the logs.
Bonus: UMD support
If you want your library to support AMD loaders (RequireJS), CommonJS (Node) and regular script tags, and have an optional dependency on jQuery, here is what you can do:
(function(u, m, d) {
if ((typeof define == 'object') && (define.amd)) {
// handle AMD loaders such as RequireJS
define(m, ['require'], d);
}
else if (typeof exports === 'object') {
// handle CommonJS here... Does not really make sense for jQuery but
// generally, you can check whether a dependency is already loaded
// just like in RequireJS:
var $ = null;
try {
require.resolve('jquery'));
// the dependency is already loaded, so we can safely require it
$ = require('jquery');
} catch(noJquery) {}
module.exports = d(null, $);
}
else {
// regular script tags. $ will be available globally if it's loaded
var $ = typeof jQuery == 'function' ? jQuery : null;
u[m] = d(null, $);
}
})(this, 'mymodule', function(require, $) {
// if `$` is set, we have jQuery... if not, but `require` is set, we may
// still get it here for AMD loaders
if (!$ && require && require.defined && require.defined('jquery')) {
$ = require('jquery');
}
// At this point, `$` either points to jQuery, or is null.
});
Further reading
Node.js - check if module is installed without actually requiring it
https://github.com/jrburke/requirejs/issues/856

Categories

Resources