pattern for module targeting browser and nodejs - node.js

backbone and underscore are usable in both the browser and nodejs.
they use the following pattern:
(function(){
// The top-level namespace. All public Backbone classes and modules will
// be attached to this. Exported for both CommonJS and the browser.
var Backbone;
if (typeof exports !== 'undefined') {
Backbone = exports;
} else {
Backbone = this.Backbone = {};
}
// ...
})();
is this the best way to achieve this?

"Best"? Well, that's a subjective thing; it's certainly a good way.
Something you left out that's quite important is that the function should use this as the reference to the global context — what code targeted at browsers would call "window":
(function() {
var global = this; // like "window"
That way, it's possible for the code to "export" symbols:
global.Foo = someFunction;
Another similar trick is to do this:
(function(global) {
// ...
})(this);
That has pretty much the same effect.

With ECMAScript 5 strict mode (and thus future versions of JavaScript), only Pointy’s version will work, because "this" does not point to the global object in non-method functions, any more. Instead:
(function() {
"use strict";
console.log("This is "+this); // "This is undefined"
}());

Related

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.

Configuring $.ajax with backbone on node for testing with vows

(Edited to greatly simplify)
On node I have the following server.js file.
var Backbone = require('backbone');
var Tweet = Backbone.Model.extend({});
var Tweets = Backbone.Collection.extend({
model : Tweet,
url: function () {
return 'http://search.twitter.com/search.json?q=backbone'
}
});
var myTweets = new Tweets();
myTweets.fetch();
When I run this, I get an error that says. "Cannot call method 'ajax' of undefined" (1359:14)
basically that is the result of $ being undefined. Why is it undefined? Well there are a number of intermediate steps but when the file is loaded, it is expecting "this" to be "window" in browser or "global" on server. executed on node "this" = {}.
So the question, "How do I set 'this' to global" inside the backbone.js file?
On Backbone >= 1.x, you can simply assign Backbone.$ rather than using Backbone.setDomLibrary.
Solution for Backbone < 0.9.9
The first issue you need to address is how you are running this on Node anyway. Nodejs is a server-side JS environment, but it does not include any logic for controlling a DOM. For that you need to load something like JSDom.
When you have some DOM environment set up, you can load jQuery and your code into it and it should work just like a browser.
To answer your question specifically though, loading jQuery into the global is a bit of an ugly way to do it. You should use Backbone's setDomLibrary function to set $ to what you want.
Try something like this:
if (typeof exports !== 'undefined') {
MyModels = exports;
Backbone.setDomLibrary(require('jquery'));
server = true;
} else {
MyModels = this.MyModels = {};
}
This will fail if you try to do any DOM functions though.

Namespaces in node.js with require

I am playing around and learning about vows with a personal project. This is a small client side library, with testing done in vows. Therefore, I must build and test a file that is written like this:
(function(exports) {
var module = export.module = { "version":"0.0.1" };
//more stuff
})(this);
In my testing (based off of science.js, d3, etc.) requires that module like so:
require("../module");
I continued to get a "module not defined error" when trying to run the tests, so I went to a repl and ran:
require("../module")
and it returned:
{ module: { version: "0.0.1" } }
I realize I could do something like:
var module = require("../module").module;
but feel like I am creating a problem by doing it that way, especially since the libraries that I based this project on are doing it in the format I described.
I would like for my project to behave similar to those which I based it off of, where:
require("../module");
creates a variable in this namespace:
module.version; //is valid.
I have seen this in a variety of libraries, and I am following the format and thought process to the T but believe I might be missing something about require behavior I don't know about.
There is no problem creating it this way. Modules define what they return in the module.exports object. By the way, you don't actually need self executing functions (SEF), there is no global leakage like in browsers :-)
Examples
module1.js:
module.exports = {
module: { 'version': '0.1.1' }
};
main.js:
var module1 = require( './module1.js' );
// module1 has what is exported in module1.js
Once you've understood how this works, you can easily export the version number right away if you want to:
module1.js:
module.exports = '0.1.1';
main.js:
var module1 = require( './module1.js' );
console.log( module1 === '0.1.1' ); // true
Or if you want some logic, you can easily extend your module1.js file like this:
module.exports = ( function() {
// some code
return version;
} () ); // note the self executing part :-)
// since it's self executed, the exported part
// is what's returned in the SEF
Or, as many modules do, if you want to export some utility functions (and keep others "private"), you could do it like this:
module.exports = {
func1: function() {
return someFunc();
},
func2: function() {},
prop: '1.0.0'
};
// This function is local to this file, it's not exported
function someFunc() {
}
So, in main.js:
var module1 = require( './module1.js' );
module1.func1(); // works
module1.func2(); // works
module1.prop; // "1.0.0"
module1.someFunc(); // Reference error, the function doesn't exist
Your special case
About your special case, I wouldn't recommend doing it like they're doing.
If you look here: https://github.com/jasondavies/science.js/blob/master/science.v1.js
You see that they're not using the var keyword. So, they're creating a global variable.
This is why they can access it once they require the module defining the global variable.
And by the way, the exports argument is useless in their case. It's even misleading, since it actually is the global object (equivalent of window in browsers), not the module.exports object (this in functions is the global object, it'd be undefined if strict mode were enabled).
Conclusion
Don't do it like they're doing, it's a bad idea. Global variables are a bad idea, it's better to use node's philosophy, and to store the required module in a variable that you reuse.
If you want to have an object that you can use in client side and test in node.js, here is a way:
yourModule.js:
// Use either node's export or the global object in browsers
var global = module ? module.exports : window.yourModule;
( function( exports ) {
var yourModule = {};
// do some stuff
exports = yourModule;
} ( global ) );
Which you can shorten to this in order to avoid creating the global variable:
( function( exports ) {
var yourModule = {};
// do some stuff
exports = yourModule;
} ( module ? module.exports : window.yourModule ) );
This way, you can use it like this on the client-side:
yourModule.someMethod(); // global object, "namespace"
And on the server side:
var yourModule = require( '../yourModule.js' );
yourModule.someMethod(); // local variable :-)
Just FYI, .. means "parent directory". This is the relative path of where to get the module. If the file were in the same directory, you'd use ..

Make a script work nice with the browser and node (npm)

I have a javascript lib, basically this is how it is structured so far:
var Ns = (function(){
var that = {};
// add stuff to 'that'
return that;
})();
//use Ns.foo() and Ns.bar()
The thing is that now, I wanted the same lib to be available with node and npm. So far this is what I could come up with:
this.Ns = (function(){ //same as previous snippet })()
//use Ns.foo() and Ns.bar()
The problem is that, while this works in the browser, in node I need to do this:
var Ns = require('ns').Ns
Problem: I'd love to be able to do var Ns = require('ns') but in order to do that I have to export this.foo and this.bar which will break the browser inclusion. Ideas?
// create local scope.
(function () {
var myModule = ...
// check for node module loader
if (typeof module !== "undefined" && typeof require !== "undefined") {
module.exports = myModule;
} else {
window["name"] = myModule;
}
})();
Creating a scope is probably the best route to go (so you don't have name collision issues), but an easier way to do this, by polluting the global scope, looks like this:
instead of
var x = require('x');
write
var x = (typeof require !== "undefined") ? require('x') : window;
and similarly, before added to exports, check if that object exists:
if (typeof exports !== "undefined)
exports.my_func = my_func;
The consequences of this, though, is that in the browser version everything gets dumped into global scope. Also, it assumes that the browser version loads the necessary scripts into the page. Easy to get working on a small scale... but I'm guessing it won't scale well.

How to work with jQuery no-conflict mode and multiple script locations

What a crappy title. Maybe someone can edit it for me. Here's the scoop:
I need to work in jQuery no-conflict mode, but I'd still like to take advantage of the $ shortcut, so all of my functions etc are defined within the typical closure of (function($){ ... })(jQuery);
All this is defined in an external source.js file that is included at the top of my HTML web page.
A little later on, I need to add some inline <script> that uses one of the utility functions I defined within the closure. Obviously I've namespaced myself into a box and can't access that function.
What's the right pattern to use here?
To control how much and what you expose in the global namespace, it is custom to expose what you need through one global object, usually in all capital letters.
FOO.module1.init();
FOO.module2.init();
You would do this by making sure FOO exists, and if it doesn't: create it.
var FOO = this.FOO || {};
The same for your module namespaces:
FOO.module1 = FOO.module1 || {};
and then inside of the anonymous function, expose what you want.
Complete example
module1.js:
var FOO = this.FOO || {};
FOO.module1 = FOO.module1 || {};
(function ($) {
var my, local, data;
function init() {
// use my, local and data here.
}
FOO.module1.init = init;
}(jQuery));
module2.js:
var FOO = this.FOO || {};
FOO.module2 = FOO.module2 || {};
(function ($) {
var some, other, data;
function init() {
// use some, other and data here.
}
FOO.module2.init = init;
}(jQuery));
controller.js:
FOO.module1.init();
FOO.module2.init();
Magnar's answer is the way to go for anything complex. But just for the sake of completeness, for something very simple you can just make it global like this:
$.noConflict();
(function($){
window.doSomething = function(){
$("body").css("background-color","red");
}
})(jQuery);
doSomething();
by adding the function to window it becomes global.
http://jsfiddle.net/cxTYV/

Resources