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

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.

Related

Dynamic require in Nodejs

I'm requiring a library in NodeJS which has a self-invoking function, that results an error because it looks for an object which is not initialized at that moment .
I want to dynamically require this library when that object is initialized.
Is there any way to dynamically require/ load a library ?
This is the part of library required :
https://github.com/sakren/node-google-maps/blob/develop/lib/Google.js#L5
Actually I want to require when the window object is present (client-side rendering).
So something like this :
'use strict';
var React = require('react');
var Map = require('./map.jsx');
var Common = require('../common/common');
var MapStatic = require('./map-static.jsx');
exports.type = function() {
return 'map';
};
exports.jsx = function(data) {
if (Common.isServerSide()) {
return (<MapStatic data={data}/>);
} else {
return (
<Map data={data}/>
);
}
};
exports.transform = require('./map-transform.js');
The reason the code looks weired is that I'm using react.
In nodeJS require can be used anywhere at anytime whithout much limitations AFAIK.
Which error is thrown once you require at runtime ?
In your else branch.
Try the following.
requires = {}
function getter(key) {
if(!requires[key]){
requires[key] = require(key)
}
return requires[key]
}

How to include a file which is not a module in Node.js (to make a module of it)?

Purpose: making a Node.js module or a Requirejs AMD module, from a plain old JavaScript file like this:
var foo = function () {};
I have no control and I can't edit foo.js.
Whyfoo is is a plain empty object inside the first if? How can I "include" a plain JavaScript file in my module? File mymodule.js:
(function(root) {
if(typeof exports === 'object') { // Node.js
var foo = require('./foo');
console.log(foo); // { }
} else if (typeof define === 'function' && define.amd) { // RequireJS AMD
define(['foo'], function () {
return foo;
});
}
}());
Node modules loaded with require must populate an exports object with everything that the module wants to make public. In your case, when you require the file nothing is added to exports, hence it shows up as empty. So the short answer is that you need to modify the contents of foo.js somehow. If you can't do it manually, then you need to do it programmatically. Why do you have no control over it?
The easiest being that you programmatically wrap the contents if foo.js in the code needed to make it a proper module.
// Add an 'exports' line to the end of the module before loading it.
var originalFoo = fs.readFileSync('./foo.js', 'utf8');
fs.writeFileSync('./foo-module.js', originalFoo + "\nexports.foo = foo;");
var foo = require('./foo-module.js');
You Could Try:
var fs = require('fs');
var foo = fs.readFileSync('foo.js', 'utf8') // Or request it somehow, just get it as a string
foo += "module.exports.foo = module.exports = foo;";
fs.writeFileSync('fooModule.js',foo);
var foo = require('./fooModule');
// foo() and foo.foo() are both the same
Note: This requires node.

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.

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/

pattern for module targeting browser and nodejs

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"
}());

Resources