Binding the require function in Node.js - javascript

I would like to include functions from a module into the current namespace. I was hoping I could utilize the bind function towards this goal, but I haven't got it working so far. Here's what I'm working with:
The module:
//exampleModule.js
this.fn = function(){return 7;}
The file which uses the module:
var example = require('./exampleModule.js')
console.log(example.fn())
What I'd like to do:
require.bind(this)('./exampleModule.js')
console.log(this.fn())
I was hoping that binding the 'this' from the non-module code would cause the module to load fn into that object, but that does not seem to be the case.

This isn't going to work, as I was confusing the 'this' within the context of my module with the 'this' within the context of the actual require function. Without knowing more about the internals of require, I don't know what binding would actually accomplish. This isn't the exact same thing, but omitting the var keyword allows modules to affect the global scope. (I'm sure this is obvious for those experienced with js..)
//exampleModule.js
fn = function(){return 7}
And the main file:
require ('./exampleModule')
console.log(fn())

Related

How do I get my helper functions to load first? (Meteor, Node framework)

In my Meteor projects I have several helper functions of the sort
helpers.js
var tagStr = function () { return this.tags.join(', '); };
articles.js
Template.articles.tags = tagStr;
listing.js
Template.listing.tags = tagStr;
Now, I can define the function in either articles.js or listing.js, and it won't work in the other one. Or i can define it in helpers.js and it will work in neither..
So, how would I go about loading my helper functions before the rest of the scripts? Preferably in "the right way".
Thanks!
i think what you are looking for is a globally available handlebars helper - i keep mine in client/lib/handlebars.js - the contents of the 'lib' folder will get loaded first
define each helper like so:
Handlebars.registerHelper("joinArray", function(array) {
if(array)
return array.join(', ');
});
you would then use this in any template html file like so:
{{joinArray tags}}
you can read more about handlebars helpers here handlebarsjs.com/block_helpers.html
this is the 'right' way IMO, but if you want to use normal javascript functions and not handlebars helpers, that works also
you'll need to place the commonly used javascript function in a file like client/lib/helpers.js and do NOT use the 'var' declaration prefix
like so:
thisIsAGloballyAvailableFunction = function(){...};
not like:
var thisFunctionIsOnlyAvailableInThisFile = function(){...};
meteor does a slightly strange thing to control scoping. anything with 'var' is local to the scope of the file it occurs in, anything declared without 'var' is globally available across the app
The answer by nate-strauser was correct and helped me find the right solution but now (Meteor 1.0) Handlebars.registerhelper() is deprecated.
Now it works this way (if anyone is still interested):
Template.registerHelper()
The rest as explained by nate-strauser.

Tell the Closure Compiler not to rename any function

I want to compile part of my JS code which is based on Mootools library.
I want all the variables be renamed but none of the function, the called and defined ones. Because most of the called one are from mootools and those defined are called from outside:
code to be compiled:
// textnum is safe to be renamed, all variables are
textnum = 0;
// loadText can't be ranmed because is called from outside
function loadText()
{
textnum++;
document.body.setStyle("font", "12px");
// here setSyle can't be renamed
}
Is there a way to tell it to rename only vars?
I found out this is an open source project, Is there a way to manipulate it somehow that it doesn't touch function at all!?
Put the code to be compiled in a namespace or anonymous function wrapper and use simple optimizations. This renames all internal vars and functions but not global ones such as setStyle.
Functions which should not be renamed are defined in the global scope. This is not as much of a pain compared to defining externs and exports.

After modifying attributes on a node.js vm context (sandbox), the modifications aren't seen by code in the context

Background
I'm working on tests for the Backbone.dualStorage plugin for Backbone.js that replaces Backbone.sync.
This is a browser plugin, but I'm using jasmine-node to test it. I load the coffeescript source into the node environment to simulate the browser window using vm.createContext:
vm = require 'vm'
fs = require 'fs'
coffee = require 'coffee-script'
backboneDualstoragePath = './backbone.dualstorage.coffee'
source = fs.readFileSync(backboneDualstoragePath, 'utf8')
window = require('./global_test_context.coffee').window
context = vm.createContext window
coffee.eval source, sandbox: context, filename: backboneDualstoragePath
exports.window = context
This works great - in my tests, I can access window.foo, where foo is an attribute exported on the window object in global_test_context.coffee.
I can use Jasmine spies on and redefine methods on any object nested under the window sandbox. Eg:
spyOn(window.Store.prototype, 'create').andReturn(true)
window.Store.create() # The spy is called
window.localsync.create() # This function instantiates a Store object and calls create on it
# The spy is called
However if I try to spy on or otherwise modify the context's direct attributes, the change is not seen inside the sandbox context:
spyOn(window, 'localsync').andReturn(true)
window.localsync() # The spy is called
window.dualsync() # This function references the global localsync
# The original localsync is called
The vm.createContext documentation says:
A (V8) context comprises a global object together with a set of
build-in objects and functions. The optional argument initSandbox
will be shallow-copied to seed the initial contents of the global object used by the context.
So it sounds like it copies the attributes from my window variable into the vm context. When I spy on or otherwise modify window after this point, I am working with the vm context, which I export as an attribute named window. Therefore I think that the paragraph above is irrelevant, but I wanted to include it in case I'm wrong.
The Question
The flow of events boils down to this:
window = vm.createContext({globalVariables: forTesting...})
# similiar to vm.runInContext(backboneDualstorageSource, window)
coffee.eval(backboneDualstorageSource, sandbox: window)
# localsync and dualsync are both defined in the backboneDualstorageSource
spyOn(window, 'localsync')
window.dualsync() # calls the original localsync instead of the spy
Why is it that after modifying attributes on the vm context, references to those "global" attributes/functions inside the vm don't change? I want to understand this.
How can I work around this so that I can modify/spyOn globals in the browser script I'm testing?
Feel free to look at the source to get a better idea of how things are actually written compared to the snippets in this question.
Edit
I was able to work around this issue by creating the spy inside an eval that runs in the context, like the rest of the tested code. See https://github.com/nilbus/Backbone.dualStorage/commit/eb6c2b21
Could someone explain why I'm able to modify global variables within the context but not outside the context, even though I have access to them?
Modifying context after eval is not affecting already evaluated scripts, if I understand your issue correctly. If you don't need to add new members to context, and just need to modify existing ones, use getters, which is working fine in latest node (0.8.x for now).
don't go down one level with the global key, try this:
window = vm.createContext({variablesForTesting.. })

break js to files with $(document).ready() but keep scope

I would like to break my javascript code to several .js files. Each of those .js has code that need to be inside the $(document).ready(..). So in each file a new $(document).ready(..) will start.
How could I call from filea.js functions declared in fileb.js (both inside a $(document).ready block) ?
If this is not possible, can you propose an alternative?
Thank you.
Edit: I would like to clarify that I would like to avoid using the global scope. I was hoping something in the line of using named functions as handlers for the event but I can't really see how to do it.
You can make a local variable global with
window.globalname = localname;
Remember that functions are variables.
You really can't get away from declaring a global. Creating a single global isn't so bad, you can then namespace all your functions under it.
Put this in something like a main.js file, so you can keep your shared functions here:
// name this something unique to your page/site/app
var MYAPP = {};
// now we can attach functions to it
MYAPP.funcA = function() { /* ... */ };
MYAPP.funcB = function() { /* ... */ };
Then, in each of your anonymous functions you can access MYAPP.funcA(), MYAPP.funcB(), etc. You can also modify MYAPP on the fly to add functions, properties, etc.
In the end you have a single global (darn it!), but if you've named it properly you are creating a global namespace where your app code can safely reside.
As long as the files are loaded in order (i.e. functions in filea.js get loaded before fileb.js calls them, you should be fine.
In order to make sure files load their dependencies first, you could consider require.js or head.js
I've had luck with the latter: http://headjs.com/

Explanation of define of the RequireJS library

I started to read several tutorials about RequireJS. In none of them was the "define" keyword explained satisfactorily for me. Could someone help me with the following :
define(
["Models/Person", "Utils/random", "jquery"],
function (Person, randomUtility, $) {..}
)
What is "define"? Is define a function with an array and an anonymous function inside of it? Or is it something else? Can someone give me more information about this kind of definitions?
Addition: Thank you nnnnnn and pradeek for your answers. Here in Europe it was 2:30 in the night when I was posting the question. Maybe therefore I didn't recognize it was a simple function call.
define is not specific to RequireJS, it is part of the AMD specification. Burke will note that RequireJS doesn't implement exactly how AMD specifies it, since AMD didn't really keep browsers in mind.
define doesn't have an anonymous function in it. define is a method made available to AMD based JavaScript files for loading their data. Libraries like RequireJS make this available to you. The specific implementation probably isn't valuable to you. So I'll go over the one you provided as it's the most common way to declare a module.
define( [array], object );
Array is a list of modules that this module depends on. There is a 1 to 1 relationship between modules and files. You can not have multiple modules in a file nor multiple files for one module.
Object is the module you are defining. This can be anything, a struct, or a function that returns a struct. Read the docs on RequireJS for more details.
If object is a function, the arguments passed to the function are the modules listed as dependencies in the first define argument. It is also important to note than when you pass a function as object, it will only run one time. The methods or properties created on this one instantiation can be accessed at any time though, can then be accessed by other modules that list this module as a dependency.
Good luck, I recommend playing around with this and reading the docs when things don't make sense. RequireJS docs are great as a quick start on how AMD modules work.
I found define defined near the bottom of require.js (I too was wondering what kind of a thing this define word is, and this is the answer I was looking for):
/**
* The function that handles definitions of modules. Differs from
* require() in that a string for the module should be the first argument,
* and the function to execute after dependencies are loaded should
* return a value to define the module corresponding to the first argument's
* name.
*/
define = function (name, deps, callback) {
var node, context;
//Allow for anonymous modules
if (typeof name !== 'string') {
//Adjust args appropriately
callback = deps;
deps = name;
name = null;
}
//This module may not have dependencies
if (!isArray(deps)) {
callback = deps;
deps = null;
}
//If no name, and callback is a function, then figure out if it a
//CommonJS thing with dependencies.
if (!deps && isFunction(callback)) {
deps = [];
//Remove comments from the callback string,
//look for require calls, and pull them into the dependencies,
//but only if there are function args.
if (callback.length) {
callback
.toString()
.replace(commentRegExp, '')
.replace(cjsRequireRegExp, function (match, dep) {
deps.push(dep);
});
//May be a CommonJS thing even without require calls, but still
//could use exports, and module. Avoid doing exports and module
//work though if it just needs require.
//REQUIRES the function to expect the CommonJS variables in the
//order listed below.
deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
}
}
//If in IE 6-8 and hit an anonymous define() call, do the interactive
//work.
if (useInteractive) {
node = currentlyAddingScript || getInteractiveScript();
if (node) {
if (!name) {
name = node.getAttribute('data-requiremodule');
}
context = contexts[node.getAttribute('data-requirecontext')];
}
}
//Always save off evaluating the def call until the script onload handler.
//This allows multiple modules to be in a file without prematurely
//tracing dependencies, and allows for anonymous module support,
//where the module name is not known until the script onload event
//occurs. If no context, use the global queue, and get it processed
//in the onscript load callback.
(context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
};
I found this page Why AMD? very helpful. To summarize from this page, AMD specification is helpful in overcoming "write a bunch of script tags with implicit dependencies that you have to manually order" problem. It is helpful in loading the dependencies before executing the required functions, similar to import in other programming languages like python. AMD also prevents the global namespace pollution problem. Check "It is an improvement over the web's current "globals and script tags" because" section.
I think the RequireJs API specification sums it up pretty well:
If the module has dependencies, the first argument should be an array of dependency names, and the second argument should be a definition function. The function will be called to define the module once all dependencies have loaded. The function should return an object that defines the module.
They list examples of all the various syntactic forms of defines.

Categories