I have a large project I am working on, first thing that really contains sensitive data, and I am realizing that my variables are largely accessible to the global scope.
I am having some trouble privatizing them. My project is pure html5, and uses several script pages to keep things tidy.
Example A
let x = 0;
window.onload = function(){
console.log(x)
}
Example B
window.onload = function(){
let x = 0;
console.log(x)
}
These both works fine, However, the variable is accessible via console. Moving it into the function helps none, using var, nothing. I can't seem to make my variable read only, and yet available to the project. Would love some advice here.
Related
I'm new to Node and the virtual machine vm2. In the documentation for the latter, it gives an example of its usage:
let functionInSandbox = vm.run("module.exports = function(who) { console.log('hello '+ who); }");
functionInSandbox('world');
Question: what is this actually doing?
Firstly, why is module.exports used here at all? Ie, why not omit it as below?
let functionInSandbox = vm.run("function(who) { console.log('hello '+ who); }");
functionInSandbox('world');
Secondly, another way of looking at it: in regular node programming, it is beginner's knowledge that require(inc) is used in one file to assign to a variable, what, in another file (chosen by inc), is assigned to module.exports. How is that different to the above usage with vm2?
Specifically: is require(...) being implicitly called in the above? How could multiple modules be defined (as above) and referred to, within one sandbox?
It's hard to know what questions to even ask - really I'm just hoping for an explanation of ways in which module.exports can be used with vm2 in ways that differ to regular node programming, highlighting differences.
I am using the environment variable and arguments parsing module called nconf for my node.js Express web server.
https://github.com/indexzero/nconf
I decided that the best way to make the nconf data global was to simply attach it to the process variable (as in process.env), is this a good idea or bad idea? Will it slow down execution in weighing down "process"?
Here is my code:
var nconf = require('nconf');
nconf.argv()
.env()
.file({ file: './config/config.json' });
nconf.defaults({
'http': {
'port': 3000
}
});
process.nconf = nconf;
//now I can retrieve config settings anywhere like so process.nconf.get('key');
frankly, I kind of like this solution. Now I can retrieve the config data anywhere, without having to require a module. But there may be downsides to this...and it could quite possibly be a very bad idea. IDK.
It won't slow down the execution, but feels "smelly". It's hard to discover, and it will be difficult to test, if you ever decide you need to.
A better solution would be to attach settings to a module and use require() to import it wherever needed.
The best solution would be to just pass your settings object to the classes or modules that need it. Either directly, or as part of some kind of "global context".
Eg.
var global = {
settings: {
port: 8080
}
}
//...
global.api = new Api(global);
//...
function Api(global) {
var port = global.settings.port;
}
UPDATE: more info on why the original pattern is bad:
1) Discoverability
You attach your settings to process.settings and go off to a different project. A year later, someone else takes over or you need to update things. Will you remember you attached your settings to process.nconf? Or was it process.settings?
Now imagine you have 10 different global things, attached under different names, on different places.
It's not as bad as attaching directly to the global context, but it's certainly better to clearly see where the stuff you're using is coming from (constructor or module).
2) Testing
You decide you need to test your module. So now you need to tweak your settings for each test instead of loading them from a file or argv. How do you do that?
In case of the global process.nconf or require("settings") patterns, you need to do something like this:
function canOpenAPIOnTheConfiguredPort(done) {
var nconfSaveApiPort = process.nconf.api.port;
process.nconf.api.port = '1234';
var api = new Api();
test.assertEqual(api.port, '1234');
process.nconf.api.port = nconfSaveApiPort;
done();
}
As your application grows, this quickly becomes annoying (eg. imagine having to mock 10 things). In comparison, here's how you do it using the dependency injection (constructor) pattern.
function canOpenAPIOnTheConfiguredPort(done) {
var api = new Api({
port: '1234'
});
test.assertEqual(api.port, '1234');
done();
}
Notice that nconf is a singleton.
I use to configure at the very beginning of the program and then when I need a setting in another file I do:
var nconf = require ('nconf');
nconf.get('x');
I'm new to Node but I figured I'd jump right in and start converting a PHP app into Node/Express. It's a bilingual app that uses gettext with PO/MO files. I found a Node module called node-gettext. I'd rather not convert the PO files into another format right now, so it seems this library is my only option.
So my concern is that right now, before every page render, I'm doing something like this:
exports.home_index = function(req, res)
{
var gettext = require('node-gettext'),
gt = new gettext();
var fs = require('fs');
gt.textdomain('de');
var fileContents = fs.readFileSync('./locale/de.mo');
gt.addTextdomain('de', fileContents);
res.render(
'home/index.ejs',
{ gt: gt }
);
};
I'll also be using the translations in classes, so with how it's set up now I'd have to load the entire translation file again every time I want to translate something in another place.
The translation file is about 50k and I really don't like having to do file operations like this on every page load. In Node/Express, what would be the most efficient way to handle this (aside from a database)? Usually a user won't even be changing their language after the first time (if they're changing it from English).
EDIT:
Ok, I have no idea if this is a good approach, but it at least lets me reuse the translation file in other parts of the app without reloading it everywhere I need to get translated text.
In app.js:
var express = require('express'),
app = express(),
...
gettext = require('node-gettext'),
gt = new gettext();
Then, also in app.js, I create the variable app.locals.gt to contain the gettext/translation object, and I include my middleware function:
app.locals.gt = gt;
app.use(locale());
In my middleware file I have this:
mod
module.exports = function locale()
{
return function(req, res, next)
{
// do stuff here to populate lang variable
var fs = require('fs');
req.app.locals.gt.textdomain(lang);
var fileContents = fs.readFileSync('./locales/' + lang + '.mo');
req.app.locals.gt.addTextdomain(lang, fileContents);
next();
};
};
It doesn't seem like a good idea to assign the loaded translation file to app, since depending on the current request that file will be one of two languages. If I assigned the loaded translation file to app instead of a request variable, can that mix up users' languages?
Anyway, I know there's got to be a better way of doing this.
The simplest option would be to do the following:
Add this in app.js:
var languageDomains = {};
Then modify your Middleware:
module.exports = function locale()
{
return function(req, res, next)
{
// do stuff here to populate lang variable
if ( !req.app.locals.languageDomains[lang] ) {
var fs = require('fs');
var fileContents = fs.readFileSync('./locales/' + lang + '.mo');
req.app.locals.languageDomains[lang] = true;
req.app.locals.gt.addTextdomain(lang, fileContents);
}
req.textdomain = req.app.locals.gt.textdomain(lang);
next();
};
};
By checking if the file has already been loaded you are preventing the action from happening multiple times, and the domain data will stay resident in the server's memory. The downside to the simplicity of this solution is that if you ever change the contents of your .mo files whilst the server is running, the changes wont be taken into account. However, this code could be extended to keep an eye on the mtime of the files, and reload accordingly, or make use of fs.watchFile — if required:
if ( !req.app.locals.languageDomains[lang] ) {
var fs = require('fs'), filename = './locales/' + lang + '.mo';
var fileContents = fs.readFileSync(filename);
fs.watchFile(filename, function (curr, prev) {
req.app.locals.gt.addTextdomain(lang, fs.readFileSync(filename));
});
req.app.locals.languageDomains[lang] = true;
req.app.locals.gt.addTextdomain(lang, fileContents);
}
Warning: It should also be noted that using sync versions of functions outside of server initialisation is not a good idea because it can freeze the thread. You'd be better off changing your sync loading to the async equivalent.
After the above changes, rather than passing gt to your template, you should be able to use req.textdomain instead. It seems that the gettext library supports a number of requests directly on each domain object, which means you hopefully don't need to refer to the global gt object on a per request basis (which will be changing it's default domain on each request):
Each domain supports:
getTranslation
getComment
setComment
setTranslation
deleteTranslation
compilePO
compileMO
Taken from here:
https://github.com/andris9/node-gettext/blob/e193c67fdee439ab9710441ffd9dd96d027317b9/lib/domain.js
update
A little bit of further clarity.
Once the server has loaded the file into memory the first time, it should remain there for all subsequent connections it receives (for any visitor/request) because it is stored globally and wont be garbage collected — unless you remove all references to the data, which would mean gettext would need to have some kind of unload/forget domain method.
Node is different to PHP in that its environment is shared and wraps its own HTTP server (if you are using something like Express), which means it is very easy to remember data globally as it has a constant environment that all the code is executed within. PHP is always executed after the HTTP server has received and dealt with the request (e.g. Apache). Each PHP response is then executed in its own separate run-time, which means you have to rely on databases, sessions and cache stores to share even simple information and most resources.
further optimisations
Obviously with the above you are constantly running translations on each page load. Which means the gettext library will still be using the translation data resident in memory, which will take up processing time. To get around this, it would be best to make sure your URLs have something that makes them unique for each different language i.e. my-page/en/ or my.page.fr or even jp.domain.co.uk/my-page and then enable some kind of full page caching using something like memcached or express-view-cache. However, once you start caching pages you need to make certain there aren't any regions that are user specific, if so, you need to start implement more complicated systems that are sensitive to these areas.
Remember: The golden rule of optimisation, don't do so before you need to... basically meaning I wouldn't worry about page caching until you know it's going to be an issue, but it is always worth bearing in mind what your options are, as it should shape your code design.
update 2
Just to illustrate a bit further on the behaviour of a server running in JavaScript, and how the global behaviour is not just a property of req.app, but in fact any object that is further up the scope chain.
So, as an example, instead of adding var languageDomains = {}; to your app.js, you could instantiate it further up the scope of wherever your middleware is placed. It's best to keep your global entities in one place however, so app.js is the better place, but this is just for illustration.
var languageDomains = {};
module.exports = function locale()
{
/// you can still access languageDomains here, and it will behave
/// globally for the entire server.
languageDomains[lang]
}
So basically, where-as with PHP, the entire code-base is re-executed on each request — so the languageDomains would be instantiated a-new each time — in Node the only part of the code to be re-executed is the code within locale() (because it is triggered as part of a new request). This function will still have a reference to the already existing and defined languageDomains via the scope chain. Because languageDomains is never reset (on a per request basis) it will behave globally.
Concurrent users
Node.js is single threaded. This means that in order for it to be concurrent i.e. handle multiple requests at the "same" time, you have to code your app in such a way that each little part can be executed very quickly and then slip into a waiting state, whilst another part of another request is dealt with.
This is the reason for the asynchronous and callback nature of Node, and the reason to avoid Sync calls whilst your app is running. Any one Sync request could halt or freeze execution of the thread and delay handling for all other requests. The reason why I state this is to give you a better idea of how multiple users might interact with your code (and global objects).
Basically once a request is being dealt with by your server, it is it's only focus, until that particular execution cycle ends i.e. your request handler stops calling other code that needs to run synchronously. Once that happens the next queued item is dealt with (a callback or something), this could be part of another request, or it could be the next part in the current request.
I'm writing a node module to consume a REST API for a service. For all intents and purposes we might as well say it's twitter (though it's not).
The API is not small. Over a dozen endpoints. Given that I want to offer convenience methods for each of the endpoints I need to split up the code over multiple files. One file would be far too large.
Right now I am testing the pattern I will outline below, but would appreciate any advice as to other means by which I might break up this code. My goal essentially is to extend the prototype of a single object, but do so using multiple files.
Here's the "model" I'm using so far, but don't think is really a good idea:
TwitterClient.js
function TwitterClient(){
this.foo = "bar";
}
require("fs").readdirSync("./endpoints").forEach(function(file) {
require("./endpoints/" + file)(TwitterClient);
});
var exports = module.exports = TwitterClient;
endpoints/endpointA.js etc
module.exports = function(TwitterClient){
TwitterClient.prototype.someMethod = function(){
//do things here
}
}
The basic idea obviously is that any file in the endpoints folder is automatically loaded and the TwitterClient is passed in to it, so that it's prototype can be accessed/extended.
I don't plan to stick with this pattern because for some reason it seems like a bad idea to me.
Any suggestions of better patterns are very much appreciated, cheers
Did anyone set up something like this for himself using the existing
node.js REPL? I didn't think of a quick way to do it.
The way I do it today is using emacs and this:
https://github.com/ivan4th/swank-js
This module is composed of:
A SLIME-js addon to emacs which, in combination with js2-mode, lets
you simply issue a C-M-x somewhere in the body of a function def - and
off goes the function's string to the ..
Swank-js server (yes, you could eval from your local-machine
directly to a remote process) written in Node.js - It receives the
string of the function you eval'ed and actually evals it
A whole part that lets you connect to another port on that server
with your BROWSER and then lets you manipulate the DOM on that browser
(which is pretty amazing but not relevant)
My solution uses SLIME-js on the emacs side AND I require('swank-
js') on my app.js file
Now.. I have several issues and questions regarding my solution or
other possible ones:
Q1: Is this overdoing it? Does someone have a secret way to eval stuff
from nano into his live process?
Q2: I had to change the way swank-js is EVALing.. it used some
kind of black magic like this:
var Script = process.binding('evals').Script;
var evalcx = Script.runInContext;
....
this.context = Script.createContext();
for (var i in global) this.context[i] = global[i];
this.context.module = module;
this.context.require = require;
...
r = evalcx("CODECODE", this.context, "repl");
which, as far I understand, just copies the global variables to the
new context, and upon eval, doesn't change the original function
definitions - SOOO.. I am just using plain "eval" and IT
WORKS.
Do you have any comments regarding this?
Q3: In order to re-eval a function, it needs to be a GLOBAL function -
Is it bad practice to have all function definitions as global (clojure-like) ? Do you think there is another way to do this?
Actually, swank.js is getting much better, and it is now much easier to set up swank js with your project using NPM. I'm in the process of writing the documentation right now, but the functionality is there!
Check this out http://nodejs.org/api/vm.html
var util = require('util'),
vm = require('vm'),
sandbox = {
animal: 'cat',
count: 2
};
vm.runInNewContext('count += 1; name = "kitty"', sandbox, 'myfile.vm');
console.log(util.inspect(sandbox));
// { animal: 'cat', count: 3, name: 'kitty' }
Should help you a lot, all of the sandbox things for node uses it :) but you can use it directly :)
You might take a look at jsapp.us, which runs JS in a sandbox, and then exposes that to the world as a quick little test server. Here's the jsapp.us github repo.
Also, stop into #node.js and ask questions for a quicker response :)