Run external javascript code dynamically as a part of the script - javascript

I need to execute some javascript code from a string as a part of the current script.
I tried to do it with eval, but for example there is a problem with classes declaration
let code = "class A { test() {console.log('A class');} }; new A().test();";
eval(code);
new A().test();
In this example the A class will be instantiated successfully in the code from the code variable. But the next line execution will fail with
Uncaught ReferenceError: A is not defined
I need to do it like clear code injection from client side script (i.e. I can't use string formatting on the server-side for example).
Is there a method for it? Or is there an error in my eval usage?
I want to have a code like
// Do something
executeScript(getScriptFromUrl("scipr url here"));
let obj = new ClassFromScript();
obj.doSomething();

Related

using uglyfyjs 3 output file same as original

I have some simple JavaScript file named test.js the file contain the following code:
function foo(){
console.log('hi');
}
Since all client code is exposed to the client, I am trying to 'hide' it or to make it unreadable.
I downloaded uglify-js, I tried to run the command
uglifyjs test.js --output test.min.js
Then the output file contains the following:
function foo(){console.log("hi")}
i.e almost the same code, readable code
Am I missing something?
Your function foo is defined in the global scope, so its name can't be obfuscated/minified. Changing it might break other codes that were calling this function.
All other words are either keywords (function), built in objects (console), object methods (.log) or string literals ('hi'). These can't be changed without breaking your code.
So, all in all, there is no changes because nothing can be changed.

Is there any way I can load a class in webworker instead of just plain javascript file?

I want to load a file in webworker but its not a plain javascript file. It is a class. So, instead of writing javascript file url in
new Worker(filename.js);
I am initializing the class by writing
new Worker(new ClassName());
It is reading the file and loading it properly. It even shows the console.log message in constructor. But when the control moves to postMessage method in main file, it throws error.
The application I am working on has a very complex structure. We have a common module that contains several classes which are executing some common functionalities throughout the application. The functionality I am working on can cause the performance issues if I execute it directly in the application. So, I am loading it in a webworker. Since its a class so I have to invoke it using new keyword. So instead of:
var ww = new Worker(filename.js);
I am writing:
var ww = new Worker(new ClassName());
Now, it invokes the class, it console logs the statement written in constructor but when in the main file it executes postMessage, javascript throws an error and stops the method from execution.
See the code below:
mainFile.js
var ww = new Worker(new CommonWebWorker());
ww.postMessage('LOAD');
ww.onmessage = function (e) {
console.log(e.data);
}
CommonWebWorker.js
'use strict';
class CommonWebWorker {
constructor() {
console.log("commonWebWorker invoked");
this.onmessage = function (e) {
this.postMessage((e.data === 'LOAD' ? 'Loading...' : 'Loading Error'));
}
}
}
module.exports = CommonWebWorker;
I expect that the file will load in the background through WebWorker but actually it is breaking and throwing below mentioned error
GET http://localhost:3000/[object%20Object] 404 (Not Found)
Any kind of help is much appreciated.
The reason for the error is that Worker expects a URL string as its first parameter, not an object. So it converts it to a string, and when you do that on most objects you get "[object Object]" (although I would have expected "[object CommonWebWorker]" from your code, but I assume you're using a transpiler or something outputting ES5 code, which would give you "[object Object]" instead).
Your main page and your work are completely different JavaScript environments. You can certainly use a class in your worker if you want, but you'd need to instantiate it in the worker, e.g.:
class CommonWebWorker {
// ...
}
new CommonWebWorker(); // To instantiate it
Your worker can also import the class from another JavaScript file via importScripts (before too long it'll be able to use ES2015+ module syntax instead), so if you want to use the same class in multiple workers, you could put it in its own file and do:
importScripts("common-web-worker.js");
new CommonWebWorker(); // To instantiate it
Once ES2015+ syntax is widely available in workers¹, you'd start your worker with the relevant module flag (new Worker("worker.js", {type: "module"})), and do this instead:
import CommonWebWorker from "./common-web-worker.js";
new CommonWebWorker();
¹ I checked just a month ago or so, and the only browser supporting it was Chrome behind a --enable-experimental-web-platform-features flag. But this stuff changes fast... :-)

Javascript require returns empty object

I am trying to use a library found on the web, called himalaya, which is an html parser.
https://github.com/andrejewski/himalaya
I followed their guide on importing the library, so I do
var himalaya = require('himalaya');
However when I call one of its member functions, I get an error
TypeError: himalaya.parse is not a function
I tried executing himalaya.parse() on the web browser console directly, it works. I tried commenting out the require statement in the js file, the function no longer works on web browser.
I guess this implies the require statement works? But for some reasons I cannot use it in my javascript file, only on the browser console.
Perhaps something with file scopes? Here is part of my code.
var himalaya = require('himalaya');
Template.main.onCreated(function () {
var http = new HttpGet("www.someurl.com/", "/somedirectories/", function (response) {
console.log(himalaya.parse(response.content));
});
http.sendRequest();
});
I am certain that response.content does contain a valid html string.
When you call the himalaya.parse inside the main.onCreated function it seems like the library is not completed loaded at that time. That's why it only runs in your browser console. Check if the himalaya library has a onReady function to let you know exactly when you can use it. If not, you can:
a) Call the parse function inside the main.onRendered or
b) Keep the parse call inside the main.onCreated and set a timeOut to call it after a half second like this:
var himalaya = require('himalaya');
Template.main.onCreated(function () {
var http = new HttpGet("www.someurl.com/", "/somedirectories/", function (response) {
setTimeout(function(){himalaya.parse(response.content)},500);
});
http.sendRequest();
});
If you have an issue with the setTimeout check this answer:
Meteor.setTimeout function doesn't work

How to properly restore Javascript context in v8?

I want to do the following:
execute a Javascript file with v8
open a REPL which evaluates code in the exact same context as the code
Any variables or functions defined in the code file, for instance, should be available in the REPL. (I'll note this used to work many v8 versions ago, but I can't figure out how to get it working in current v8 (node 0.12 == v8 3.28.73).)
I use a simple class JSInterpreter which has an isolate and a persistent context object as member vars. They gets set up when the class is initialized, and bindings also happen at that time.
When it's time to interpret some code, I call this method:
Str JSInterpreter::InterpretJS (const Str &js)
{ v8::Isolate::Scope isolate_scope (isolate_);
v8::HandleScope handle_scope (isolate_);
// Restore the context established at init time;
// Have to make local version of persistent handle
v8::Local <v8::Context> context =
v8::Local <v8::Context>::New (isolate_, context_);
Context::Scope context_scope (context);
Handle <String> source = String::NewFromUtf8 (isolate_, js . utf8 ());
Handle <Script> script = Script::Compile (source);
Handle <Value> result = script -> Run ();
I want to call this method over & over again, and each time, I want the context to contain any accumulated state from earlier calls. So if the code file contains (only) var x = 5; at the REPL I should be able to type > x and see the result 5.
But the actual result is x is not defined.
It turns out that this code actually does work as expected. The problem was that I was using browserify before running the code, and the code (e.g. var x = 5;) was getting wrapped into a function scope.

JavaScript Factory class throws errors if function name is not a 'constructed string'

I have a Factory class that I use in JavaScript to dynamically load a class file over AJAX and then return an object. I have run into a VERY peculiar bug in the system though that throws errors in EVERY browser, but under a condition that is beyond my ability to explain.
Here is a simplified version of my Factory class (I removed a lot of type checking and error handling to cut it down to bare minimum).
function Factory(){
// This holds which files have already been loaded
var loaded=new Object();
// Returns a new object
this.getObject=function(className,methodName,methodData){
if(loadFile('class.'+className+'.js')){
// Making sure that the object name is defined
if(window[className]!=null){
// Has to be an object
if(typeof(window[className])=='function'){
// Creating a temporary object
return new window[className];
}
}
}
}
// Loads a file over AJAX
var loadFile=function(address){
// Loads as long as the file has not already been loaded
if(loaded[address]==null){
// Required for AJAX connections (without ASYNC)
var XMLHttp=new XMLHttpRequest();
XMLHttp.open('GET',address,false);
XMLHttp.send(null);
// Result based on response status
if(XMLHttp.status===200 || XMLHttp.status===304){
// Getting the contents of the script
var data=XMLHttp.responseText;
// Loading the script contents to the browser
(window.execScript || function(data){
window['eval'].call(window,data);
})(data);
// makes sure that file is loaded only once
loaded[address]=true;
}
}
}
This is what the user does:
var Factory=new Factory();
var alpha=Factory.getObject('example');
alpha.set(32);
alpha.get();
var beta=Factory.getObject('example');
beta.set(64);
alpha.get();
beta.get();
This fails, it says 'object is not a function' when the function is run for the second time (at the return new window[className]; line). I understand if I am missing something here, BUT here's the kicker:
If I prefix className in my window[] calls, then it works. For example, if I change my 'example' class filename to 'test_example' and then have these lines:
... if(window['test_'+className]!=null){ ...
... if(typeof(window['test_'+className])=='function'){ ...
... return new window['test_'+className]; ...
Then it works and both alpha and beta objects work as expected. When I refer to them purely through a variable, they fail. I tried things like className.toString() without success and even this fails:
className+''
This is really weird, I don't know where to look and what to try out anymore, does anyone know why this happens?
EDIT: Here is an example of the 'example.js' script that is being loaded:
function example(){
var myVar=16;
this.set=function(value){
myVar=value;
}
this.get=function(){
alert(myVar);
}
}
(and if I rename this to test_example() and load the functions as shown above with constructed strings, then it again works)
I figured out where the error was, which my above, cut-down version does not show. Apparently I named my new variable the same that the name of the class itself was, thus after first initialization it got overwritten.

Categories

Resources