Hoisted local variable masking global variable? - javascript

Came across strange behavior in node. I have an emscripten compiled program that I would like to use as a library. emscripten use a variable Module to control runtime behavior, and generates code like ./lib/g.js below. In the browser, Module is properly aliased from the global defined in index.js to the local var in ./lib/g.js. However, in node, this does not seem to be the case. The construct: var Module = Module || {}; wipes out my global Module.
index.js:
global.Module = { name: 'Module' };
var g = require ( './lib/g.js' );
./lib/g.js:
console.log ( 'Module: ', Module );
var Module = Module || {};
Output of node index.js:
Module: undefined
I assume in g.js, Module is hoisted and dereferenced only in the local scope, masking the global version (in global.Module). Can anyone suggest a work-around?
This problem can be fixed by editing the emscripten produced code to use var Module = global.Module || {}. While this is a possible workaround, I would rather not edit the code generated by emscripten.

You might take a look at using rewire
var rewire = require("rewire");
var g = rewire("./lib/g");
g.__set__("Module", {name: "Module"});

Can anyone suggest a work-around?
Just remove the var keyword.

Related

Load a javascript file into a module pattern on Client-side

I have a simple javascript module pattern that executes client-side.
var module = (function() {
var _privateVariable = 10;
function publicMethod () {
console.log("public method; private variable: " + _privateVariable);
}
return {
publicMethod: publicMethod
};
})();
Let's say I want to load in another module (which also uses a module pattern) from a separate javascript file. How do I do that, i.e. something like:
?? Load other module here ??
var _other_module = ??
var module = (function() {
var _privateVariable = 10;
function publicMethod () {
console.log("public method; private variable: " + _privateVariable);
console.log("public method; other module: " + other_module.publicMethod());
}
return {
publicMethod: publicMethod
};
})();
You can't. To load another module form another file you need to use a Module formats.
It's a long story, i will try to shorten.
Let's talk first about the old way. earlier the developer used to load alle the JS-Files in a certain order in the HTML-Page. If we have 2 JS-Files index.js and variables.js and we want to get a variable from varible.js in index.js, we had load them like that
<script src="variables.js"></script>
<script src="index.js"></script>
But this is not a good way and has many negatives.
The right way is to use a Module formats.
There are many Module formats,
Asynchronous Module Definition (AMD)
CommonJS
Universal Module Definition (UMD)
System.register
ES6 module format
and each format has own Syntax.
For example CommonJS:
var dep1 = require('./dep1');
module.exports = function(){
// ...
}
but the Browsers dont't understand that. so we need a Module bundlers or Module loaders
to convert our code to code which browsers can understand.
Module bundlers: Bundle your inter-dependent Javascript files in the correct order
Browserify
Webpack
Module loaders: a module loader interprets and loads a module written in a certain module format.
RequireJS
SystemJS
This article will help you so much to understand exactly how modules work.
Not sure which context you are doing this.
But. In node.JS this would be typically done by
module1.js
module.exports.publicMethod = function() {}
index.js
const module1 = require('./module1.js');
module1.publicMethod();
or
const {publicMethod} = require('./module1.js');
publicMethod();

Why dirname is not a module atribute? (__ notation)

I'm studying the basics of node. According to the documentation, both __dirname and __filename belong to module scope. As expected, both:
console.log(__dirname)
console.log(__filename)
Work, printing current dirname and filename.
But when i try calling them from module, only filename works:
console.log(module.dirname)
console.log(module.filename)
The first one prints undefined.
1 - Why console.log(module.dirname) prints undefined?
2 - I'm confused about __notation. If it's not a sugar sintax for module., what it is used for?
Those variables are defined as arguments to a function that is wrapped around your module code like this:
(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});
This does several things:
It provides a scope for your module (the function scope of the wrapper function). Any top level variables you declare in your module will actually be scoped to the module, not at the top, top scope.
It provides the values of require, module, __filename and __dirname as independent variables that are unique for each module and cannot be messed with by other modules.
The properties of the module object (collected with Object.getOwnPropertyNames(module) are:
'id',
'exports',
'parent',
'filename',
'loaded',
'children',
'paths'
Why dirname is not a module attribute?
The "why" would have to go into the head of the designer and discussion at the time the module system was designed. It's possible that a module object might be accessible by some other code and passing __dirname and __filename as arguments to the wrapper made it so that even something else who had access to your module object couldn't mess with __dirname and __filename. Or, it could have just been done for shortcuts in typing. Or, it could have just been a personal design choice.
Why console.log(module.dirname) prints undefined?
Because dirname is not a property of the module object itself (I have no idea why). Instead, __dirname is passed as the wrapper function argument.
I'm confused about __notation. If it's not a sugar syntax for module., what it is used for?
Usually, the _ or __ prefix is just used to make sure it doesn't accidentally collide with any regular variable declaration in the code. My guess is that the original designers of node.js envisioned existing code bases being used in modules and they wanted to lessen the chances of a variable naming collision.
Some of your question seems to be about why aren't all of these just properties of the module object. I can think of no particular reason why that wouldn't have been a perfectly normal and logical design.
To save typing, there are object lots of references to require so I can certainly see an argument for not making us all type
module.require('someModuleName') every time.
And, exports is already a property of module. For example, module.exports === exports. Using it as module.exports does have some use because you can define a whole new object for the exports:
module.exports = {
greeting: "hello",
talk: function() {...}
};
But, you cannot do that by just reassigning the exports. This will not work:
exports = {
greeting: "hello",
talk: function() {...}
};
So, I guess exports is also supplied as a shortcut when you just want to do:
exports.talk = function() {...}
But, module.exports is needed if you're assigning a whole new exports object.
Maybe this can help
const fs = require('fs');
dirname = fs.realpathSync('.');
Now, it's upon you what you are using 'dirname' of 'dirname'

Scopes in context of Modules in Node.js

I need to understand the concept of scopes in Node.js. The fact that this === global, when I try the code below
//basic1.js file
this.bar = "Bacon";
//basic2.js file
require('./basic1');
console.log(this.bar);
and run basic2.js, output is undefined instead of Bacon. Since I am assigning a property bar in global object and as global object is shared by all the node modules, why am I getting undefined as output? Can you help me understand that.
To understand how node.js interpret modules better to look at source code:
Read source code from file.
Wrap source into function call like function(exports, require, module, __dirname, __filename){ /* source code */ }
Evaluate wrapped code into v8 virtual machine (similar to eval function in browser) and get function.
Call function from previous step with overwriting this context with exports.
Simplified code:
var code = fs.readFileSync('./module.js', 'utf-8');
var wrappedCode = `function (exports, require, module, __dirname, __filename) {\n${code}\n}`;
var exports = {};
var fn = vm.runInThisContext(wrappedCode);
var otherArgs = [];
// ... put require, module, __dirname, __filename in otherArgs
fn.call(exports, exports, ...otherArgs);

JavaScript Faux Pas - Let me put global libraries on the window?

I'm using RequireJS. I absolutely hate the double variable syntax of defining a dependency and passing it in as a variable in a callback function. I am therefore attempting the implement the 'Sugar' syntax available in RequireJS.
However, I only want to 'import' global libraries like Backbone, jQuery, Underscore and Marionette once. jQuery and Backbone obviously assign themselves to the Window object but Underscore and Marionette do not.
This is my main.js file:
require.config({
paths: {
"jquery" : "vendor/jquery.min",
"underscore": "vendor/underscore-min",
"backbone" : "vendor/backbone-min",
"marionette" : "vendor/marionette",
"app" : "app/app"
}
});
define(function(require, exports, module) {
// Make these libraries available globally
var jquery = require('jquery');
window.underscore = require('underscore');
var Backbone = require('backbone');
window.marionette = require('marionette');
// Require and start our own app
var app = require('app');
app.start();
});
This obviously stops me from having to import/require each of these core libraries into every subsequent module/component for my application. Taking my code from potentially this (app.js file):
define(function (require, exports, module) {
var jquery = require('jquery'),
underscore = require('underscore'),
Backbone = require('backbone'),
Marionette = require('marionette'),
// module specific libs
mymodule = require('../js/app/module'),
logger = require('../js/app/logger');
return {
start: function () {
var testview = new mymodule();
logger.logme();
}
}
});
To this (better app.js):
define(function (require, exports, module) {
var mymodule = require('../js/app/module'),
logger = require('../js/app/logger');
return {
start: function () {
var testview = new mymodule();
logger.logme();
}
}
});
Much cleaner IMO.
So thoughts? Criticisms? Are these going to play well together? (two already do it themselves - why not for the other two if they are core to the app).
In my head I don't think it will be a problem as long as I don't start hammering every module/component/library onto the global scope but I'm interested for someone more experienced to weigh in.
If I'm doing it wrong or there is a better way let me know!
Thanks
EDIT: After reading your comments, I realized your question has two components. One component is purely syntactical - and my original answer addresses a possible solution to that component. However, to the extent that your solution also incorporates an application design component, whereby dependencies of individual modules are defined at the application level, my answer is that is "bad practice." Dependencies should be defined at the module level (or lower) so that every element of your application is decouplable. This will be an enormous benefit in writing code that is (1) reusable, (2) testable, (3) refactorable. By defining your dependencies at the application level, you force yourself into loading the entire application simply to access a single module, for example, to run a test - and you inhibit rearranging modules or reuse of the same modules in other projects. If you do this, in the long run... you're gonna have a bad time.
Now, to the extent that your question is syntactical...
ORIGINAL ANSWER: I agree that require.js syntax is ugly as hell, annoying to use, and a potential source of difficult to debug errors. My own approach was to implement the following wrapping function (pardon the coffeescript).
# Takes dependencies in the form of a hash of arguments with the format
# { path: "name"}
# Assigns each dependency to a wrapper variable (by default "deps"),
# without the need to list each dependency as an argument of the function.
PrettyRequire = (argHash, callback) ->
deps = new Array()
args = new Array()
#loops through the passed argument, sorts into two arrays.
for propt of argHash
deps.push(propt)
args.push(argHash[propt])
#calls define using the 'dependency' array
define(deps, ()->
deps = new Array()
# assigns the resulting dependencies to properties of the deps object
for arg, i in args
deps[arg] = arguments[i]
# runs callback, passing in 'deps' object
return callback(deps)
)
This code is a simple rewrite which (1) preserves scope and (2) prettifies the syntax. I simply include the function as a part of a internal library that I maintain, and include that library at the outset of any project.
Define can then be called with the following (imho) prettier syntax:
PrettyRequire({
'backbone': 'Backbone'
'vendor/marionette': 'Marionette'
'../js/app/module': 'myModule'
}, (deps)->
Backbone.Model.extend(...) # for dependencies that assign themselves to global
deps.myModule(...) # for all dependencies (including globals)
)
That's my approach, to the extent that it's responsive to your question. It's worth noting also that your apps will take a (small) performance hit as a result of the increased overhead, but as long as you're not calling too many sub modules, it shouldn't be too much of an issue, and to me, it's worth it not to have to deal with the double syntax you describe.

node.js require modules in virtual machine script

I'm creating a commandline interface with node.js that runs an external script
> myapp build "path/to/script.js"
myapp is a node.js application that executes the script passed as a commandline argument.
To keep things brief, it basically does this:
var vm = require("vm");
var fs = require("fs");
var code = fs.readFileSync(scriptPath, { encoding: "utf8" }); // read "path/to/script.js"
var script = vm.createScript(code, scriptPath);
var context = vm.createContext({ require: require });
script.runInNewContext(context);
The contents of "path/to/script.js" look something like this:
var fs = require("fs"); // this works
var date = require("./date.js"); // supposed to load "path/to/date.js" but fails
My problem is that require() doesn't work properly in the external script. It works correctly for "native" modules like fs but fails on local files, probably because it doesn't know where to look up the modules.
I've considered to simply use following code:
require(scriptPath);
but then I can't inject my own script context.
I could write my own require function that emulates the built-in require but starts looking for modules in scriptPath but that seems a bit tedious...
I've used sandboxed-module to solve a similar problem.
var Sandbox = require('./sandboxed-module')
Sandbox.require(scriptPath);
Sandbox.require loads code from disk and runs it in a new context. It provides a sandbox-specfiic require function that allows you to tweak how require works.

Categories

Resources