How to parse and load javascript object? - javascript

I have one js files . I load it using other javascrupt file using eval() function. I have seen eval is slow and with some other limtation. Since i need to store my JS file object in cache and use it anytime i need after apllication starts. I dont want to do eval() everytime.
Is there anyway to do it in simple way.
var evalObj;
if(evalObj) {
console.log('eval object already evaluated');
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level, categoryName, message);
}
else {
evalObj = eval(fs.readFileSync('./myJSFile', 'utf8'));
console.log('re evaluating object ..' );
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level,message);
}
myJSFile
var _sigmaAlarmHandler_ =function(args)
{
var args = Array.prototype.slice.call(arguments);
args.unshift();
console.log('Alarm : ', args);
}
Either the conditional eval is not working.

In node.js you can simple require your js-file:
var obj = require('./myJSFile');
obj.foo();
./myJSFile.js:
exports.foo = function() {
console.log('foo');
}
This file becomes a module with exported functions, that you need.
It loads once, then every require reuse already loaded module.

If it is not commonjs-compliant (i.e. using module.exports will not work), then you can run it in its own vm:
var vm = require('vm');
vm.runInNewContext(jscode,{/*globalvars*/});
where the second parameter is an object with global vars made available in the context in which the jscode is run. So if the second param is, say, {a:1,b:"foo"} then your jscode will run with the global variable a set to 1 and the global variable b set to "foo".
The jscode itself is a string that you load from a file or elsewhere.
Think of vm.runInNewContext() as "practice safe eval". Well, relatively safe, you can still do some dangerous stuff if you pass in particular vars, like process or file etc.
I used this for the declarative part of cansecurity http://github.com/deitch/cansecurity for nodejs
You can view the sample in the file lib/declarative.js
Here is the API for vm http://nodejs.org/api/vm.html
There are options to run in the same context, etc. But that is very risky.
When you actually run the code, using your example above:
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level,message);
you are looking to pass in 4 params: startTime, threadName, level, message and execute the function. The issue is that you cannot run the function on the current context. You need the function to be defined and run in the file. So you should have something like:
vm.runInNewContext(jscode,{startTime:layouts.FormatDate(startTime),threadName:threadName,level:level,message:message});
And then the jscode should look like
function _myfunctionInJSFile(startTime,threadName,level,message) {
// do whatever you need to do
}
// EXECUTE IT - the above vars are set by the global context provide in vm.runInNewContext
_myfunctionInJSFile(startTime,threadName,level,message);
If you prefer to define the function and have it loaded and run in this context, then just use the commonjs format.

I think i have found the answer for this.
Since my application is running in node js which uses v8 engine platform. When the application starts v8 engine caches all the code/configuration and can be used anytime.
Similarly in my code i will pre-load the JS code using eval and i will do it only once. So on next call i will return only the loaded JS code. Here i need to modify the code to load once.
But main point we have look is that in future if any body has similar requirement they can cache their JS codes using eval (thanks to v8 engine) and use it till your application is running.

Related

Rewrite browser JS code to transform global definitions into window properties

I support a very old PHP web framework that uses server-side rendering. I decided to implement Vue for the rendering of some modules, so I compiled a hello world app and realized deployment wouldn't be so simple.
The framework works as a giant SPA, with each module being rendered using the html output of a body() function. The output is replaced in the client's DOM without reloading the page itself.
<script> tags are banned for security reasons and will be sanitized from the resulting html. The only way to deliver JS to the client is by using an eval_js() function.
The problem is rather simple. I need to safely load JS code several times in the same DOM. I cannot load it as-is after app compilation, because from the second time onwards the code is executed (every time a user visits a module, or performs an action) the code will attempt to re-define global variables and kill the whole client.
The solution is also rather simple, just rewrite the JS code such that every global definition is transformed into a window property. This way, even if the same piece of code gets executed several times in the same DOM, it will simply replace window properties rather than attempting to re-define variables.
In example, the following input:
function Yr(t){
const b = t.prototype.hasOwnProperty;
this._init(b);
}
var hOe = sg(uOe, fOe, dOe, !1, null, "e687eb20", null, null);
const vOe = {
name: "AmmFilters",
components: {
AmmOptionSelect: pOe
}
};
new Yr({...}).$mount("#app");
Would be rewritten into:
window.Yr = function(t){
const b = t.prototype.hasOwnProperty;
this._init(b);
}
window.hOe = sg(window.uOe, window.fOe, window.dOe, !1, null, "e687eb20", null, null);
window.vOe = {
name: "AmmFilters",
components: {
AmmOptionSelect: window.pOe
}
}
new window.Yr({...}).$mount("#app");
I initially considered to write my own parser, but then realized that ES6+ syntax is no child's play. The code I will attempt to rewrite is optimized & obfuscated which means it will have all sort of complex syntax and I must be careful not to turn scoped definitions into window properties.
Any ideas on a tool that already performs this task? The resulting JS code should have no difference from the original, as global scoped variables end up in the window object anyway.
I believe it would be a fairly useful tool for various use cases, so thought about asking before attempting to reinvent the wheel.

Hide globals in Flow?

I am writing some code in JavaScript + Flow and would like to keep it as pure as possible, which also means skipping globals such as window or document, passing those as function arguments. But it’s quite easy to forget a stray document reference here or there. Is it possible to ban those globals somehow, allowing them only in the top-level file? So far I am doing this at the top of most of my documents:
const window = undefined
const document = undefined
This way only instances passed in as arguments work:
// This works
function foo(document: Document) {
document.doThisOrThat();
}
// This triggers a typecheck error πŸŽ‰
function bar() {
document.doThisOrThat();
}
Are there other solutions? (I would love a whitelist approach, disallowing all globals except those whitelisted.)
You can set Flow to ignore the flowlibs by adding no_flowlib=true in the [options] section of the flowconfig.
From there, you can make your own libs folder and only include the library definitions you want. To make them globally available, add the path to your libs folder in the [libs] section of your flowconfig.

Unit tests in JavaScript with mocked objects

So I'm working with an enterprise tool where we have javascript scripts embedded throughout. These scripts have access to certain built-in objects.
Unfortunately, the tool doesn't give any good way to unit test these scripts. So my thinking was to maintain the scripts in a repo, mock the built-in objects, and then set up unit tests that run on my system.
I'm pretty ignorant to how JavaScript works in terms of building, class loading, etc. but I've been just trying things and seeing what works. I started by trying out Mocha by making it a node project (even though it's just a directory full of scripts, not a real node project). The default test works, but when I try and test functions from my code, I get compiler errors.
Here's what a sample script from my project looks like. I'm hoping to test the functions, not the entire script:
var thing = builtInObject.foo();
doStuff(thing);
doMoreStuff(thing);
function doStuff(thing) {
// Code
}
function doMoreStuff(thing) {
// More Code
}
Here's what a test file looks like:
var assert = require('assert');
var sampleScript = require('../scripts/sampleScript.js');
describe('SampleScript', function() {
describe('#doStuff()', function() {
it('should do stuff', function() {
assert.equal(-1, sampleScript.doStuff("input"));
});
});
});
Problem happens when I import ("require") the script. I get compilation errors, because it doesn't builtInObject. Is there any way I can "inject" those built in objects with mocks? So I define variables and functions that those objects contain, and the compiler knows what they are?
I'm open to alternative frameworks or ideas. Sorry for my ignorance, I'm not really a javascript guy. And I know this is a bit hacky, but it seems like the best option since I'm not getting out of the enterprise tool.
So if I get it right you want to do the unit tests for the frontened file in the Node.js environment.
There are some complications.
First, in terms of Node.js each file has it's own scope so the variables defined inside of the file won't be accessible even if you required the file. So you need to export the vars to use them.
module.exports.doStuff = doStuff; //in the end of sample script
Second, you you start using things like require/module.exports on the frontend they'll be undefined so you'll get an error.
The easiest way to run your code would be. Inside the sample script:
var isNode = typeof module !== 'undefined' && module.exports;
if (isNode) {
//So we are exporting only when we are running in Node env.
//After this doStuff and doMoreStuff will be avail. in the test
module.exports.doStuff = doStuff;
module.exports.doMoreStuff = doMoreStuff;
}
What for the builtInObject. The easies way to mock it would be inside the test before the require do the following:
global.builtInObject = {
foo: function () { return 'thing'; }
};
The test just passed for me. See the sources.
Global variables are not good anyway. But in this case seems you cannot avoid using them.
Or you can avoid using Node.js by configuring something like Karma. It physically launches browser and runs the tests in it. :)

Nodejs Persistent Variable

Is there some sort of Session-like variable to hold an array in Nodejs?
What I meant is like something where I can define the name in other scope and be accessed in different scope (i.e: Variable("Array1") is defined in function A but accessed in function B and persists until it is destroyed).
The reason is I am using Meteor for slicing big files into small blobs and pass it back the chunk to the server. I tried to use the combination of fs.WriteFile and fs.AppendFile but somehow the file is mutilated along the way (the file is a video and playback error occurred with the copied file).
I read somewhere that blob can be rebuild by the constructor. However, I would need to pass this to a global or session-like variable in order to do so.
So...how can I use such thing in Nodejs?
There is such thing – it is called database :-)
When you're in Meteor, all files are loaded to a single running environment. Therefore, unlike in plain Node, a global variable created in one file can be accessed in any other one. So you can write
Slices = {};
in one file, and then in another say
Slices['Array1'] = ...
Notice there is no var keyword when defining the Slices object, otherwise it wouldn't be global but scoped to the file.
There is obviously one problem with the above method, and it's persistence over server reload. When the server crashes and restarts, or when you upload a new version, all such variables are recreated and you lose your data.
To prevent this, you need to store your variables in a place where they are retained permanently – a database of some kind. There are several solutions tailored for such runtime variables (such as Redis), but since you're using Meteor the natural solution would be to use the provided Mongo database. So just create a new collection on the server side
Slices = new Meteor.Collection('slices');
and use the usual find, insert, update and remove methods to access your variables.
If everything happens in the same process space, you can use a module as a singleton.
Remember, even if a module is included multiple times, the same copy is returned.
So if you have this module:
module.exports = new Array();
And you include it by several other modules, each one of them will have the same array instance.
You can also have a more complex singleton:
var blocks = {};
module.exports.addBlock = function(name, block) {
blocks[name] = block;
};
module.exports.getBlock = function(name) {
return blocks[name];
};
module.exports.delBlock = function(name) {
delete blocks[name];
};
module.exports.list = function() {
return Object.keys(blocks);
};
In your different files, you would include and use this module like:
var blocks = require('./blocks');
console.log(blocks.list());
Read about module caching here.

'This' in phonegap

What is 'this' in phonegap? I am working on an app where I have local javascript packed with the app and remote javascript pulled from a server. I am using coffeescript to generate all the javascript.
Both files are being included in the app's index header, generated through haml as such:
%script{:src=>"javascripts/file1.js"}
%script{:src=>"http://192.168.5.205:3000/assets/file2.js"}
file1.js.coffee:
#myObj1 = property: true
file2.js.coffee:
#myObj2 = property: true
myObj1 is available globally and can be referenced as just myObj1, but myObj2 is only available via document.myObj2 and can not be referenced as simply myObj2. What is happening?
Well, if you say this:
#myObj2 = property: true
and you have to reference myObj2 as document.myObj2 everywhere else, then this must be document when file2.js.coffee is executed. This sort of thing can happen if your code is executed through $(document).ready() or similar means (for example: http://jsfiddle.net/ambiguous/6DFK9/).
If you want something to be global, then you really should be explicit about it and use window:
# in file1.js.coffee:
window.myObj1 = property: true
# in file2.js.coffee:
window.myObj2 = property: true
That way you don't have to worry about the calling context and more importantly, your intent will be explicit and you won't have to puzzle over what this is or supposed to be in six months when you're trying to fix bugs. Say what you mean: if you want it global, put it in window.

Categories