Is it possible to overwrite "global" variable via Webpack? - javascript

I am finding a way to make MathJax be able to run on a specific JS runtime with lots of limitations.
MathJax use global to access the MathJax object, and this is compiled by Webpack into the following snippet:
function (e, t) {
var n;
n = function () {
return this;
}();
try {
n = n || new Function("return this")()
} catch (e) {
"object" == typeof window && (n = window)
}
e.exports = n
}
The code above will try to assign the global this to e.exports, and the usage of global in MathJax's source code will be replaced with e.exports. However, in my JS runtime, window/global are not available, function () { return this; } returns undefined, new Function is restricted and only returns an empty object instead of a function.
My question is that, is it possible to configure Webpack to replace global with some other variable I specify (like limitedGlobal.someVar)?
For referrence, I found that the snippet above is defined in GlobalRuntimeModule.js, and I want to change its implementation.

Sure, please have a look at globalObject
Its default is global="window"
You can override it like this in your webpack configurations:
output: {
globalObject: 'this' // or limitedGlobal.someVar in your case
}

Related

Execute within an environment in javascript

I would like to allow my user to execute a series of functions while applying a certain object as the environment. For example, I have some object which contains data and operations.
environment = {
member1 = 0
operation1 = ->
member1 += 1
}
I want to allow the user to send commands into the environment as if it were the global object, without referencing it with this
i.e.
environment.evaluate("operation1()")
It would also be nice if I could create operations outside the environment, but allow them to be sent into this hypothetical 'evaluate' function.
Is it possible to build something like this? Does it have native javascript support?
changing now. just realized what you needed
this calls a member of the private methods object.
// create a closure which is your environment using the module pattern
var environment = (function() {
// local variables to the environment
var member1 = 0;
// public interface
var methods = {
operation: function(num) {
return member1 += (num || 1);
},
evaluate: function evaluate(name) {
var rest = Array.prototype.slice.call(arguments, 1);
// call your function by name passing in the rest of the arguments
return typeof methods[name] === 'function' && methods[name].apply(this, rest);
}
}
return methods;
})();
console.assert(typeof member1 === 'undefined', 'member1 is out of scope');
console.assert((environment.evaluate("operation", 2) === 2), 'member1 === 2');
console.log(environment.evaluate("operation", 2));
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
old answer
I just noticed you requested coffee script. This is javascript you could use. I have never used coffee script but it shouldn't be hard to change to coffee and coffee compiles to js anyway.
The key is having a closure around the entire environment and using eval to modify the internal state. You are really better off having specific getters and setters to limit the api to just the things you allow, otherwise the end user has access to modify anything in the scope, so nothing is private.
// create a closure which is your environment using the module pattern
var environment = (function() {
// local variables to the environment
var member1 = 0;
// return the public interface
return {
// this function evals the code in the context of the environment
evaluate: function evaluate(operation) {
// eval a closure so anything you put in there is run and returned to the outer environment
return eval('(function(){ return ' + operation + '})()');
}
}
})();
console.assert( typeof member1 === 'undefined', 'is member1 out of scope' );
console.log( environment.evaluate("++member1") );
<!-- begin snippet: js hide: false -->
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
var es6environment = (function() {
let member1 = 0;
const methods = {
operation: (num = 1) => member += num,
evaluate: (name, ...rest) => typeof methods[name] === 'function' && methods[name].apply(this, rest);
}
return methods;
})();
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>

How to check that ES6 "variable" is constant?

Does anyone know some tricks how to do it? I tried to use try-catch:
"use strict";
const a = 20;
var isConst = false;
try {
var temp = a; a = a+1; a = temp;
} catch (e) {
isConst = true;
}
But unfortunately it works only in "strict" mode. Without "use strict" it perform all statements silently, without modification of a. Also I cannot wrap this code into some handy function (isConstant(someConst) for example) as any argument I'll pass to that function will be a new variable. So anyone know how to create isConstant() function?
I don't think there is, but I also don't think this is a big issue. I think it might be useful to have the ability to know if a variable is const, and this exists in some other languages, but in reality since you (or someone on a team) will be defining these variables, you'd know the scope and the type of the variables. In other words, no you can't, but it's also not an issue.
The only case where it might be useful is if you could change the mutable property during runtime, and if changing this property had actual performance benefits; let, const, and var are treated roughly equally to the compiler, the only difference is that the compiler keeps track of const and will check assignments before it even compiles.
Another thing to note is that just like let, const is scoped to the current scope, so if you have something like this:
'use strict';
const a = 12;
// another scope
{
const a = 13;
}
it's valid. Just be careful that it will look up in higher scopes if you don't explicitly state const a = 13 in that new scope, and it will give a Read Only or Assignment error:
'use strict';
const a = 12;
{
a = 13; // will result in error
}
Based on some of the answers here I wrote this code snippet (for client side JS) that will tell you how a "variable" was last declared--I hope it's useful.
Use the following to find out what x was last declared as (uncomment the declarations of x to test it):
// x = 0
// var x = 0
// let x = 0
// const x = 0
const varName = "x"
console.log(`Declaration of ${varName} was...`)
try {
eval(`${varName}`)
try {
eval(`var ${varName}`);
console.log("... last made with var")
} catch (error) {
try {
eval(`${varName} = ${varName}`)
console.log("... last made with let")
} catch (error) {
console.log("... last made with const")
}
}
} catch (error) {
console.log("... not found. Undeclared.")
}
Interestingly, declaring without var, let or const, i.e x = 0, results in var getting used by default. Also, function arguments are re-declared in the function scope using var.
Just check if your reassignment actually did something:
var isConst = function(name, context) {
// does this thing even exist in context?
context = context || this;
if(typeof context[name] === "undefined") return false;
// if it does exist, a reassignment should fail, either
// because of a throw, or because reassignment does nothing.
try {
var _a = context[name];
context[name] = !context[name];
if (context[name] === _a) return true;
// make sure to restore after testing!
context[name] = _a;
} catch(e) { return true; }
return false;
}.bind(this);
You need the try/catch because reassign Could throw an exception (like in Firefox), but when it doesn't (like in Chrome), you just check whether your "this always changes the value" reassignment actually did anything.
A simple test:
const a = 4;
var b = "lol";
isConst('a'); // -> true
isConst('b'); // -> false
And if you declare the consts in different context, pass that context in to force resolution on the correct object.
downside: this won't work on vars declared outside of object scopes. upside: it makes absolutely no sense to declare them anywhere else. For instance, declaring them in function scope makes the const keyword mostly useless:
function add(a) {
return ++a;
}
function test() {
const a = 4;
console.log(add(a));
}
test(); // -> 5
Even though a is constant inside test(), if you pass it to anything else, it's passed as a regular mutable value because it's now just "a thing" in the arguments list.
In addition, the only reason to have a const is because it does not change. As such, constantly recreating it because you're calling a function that makes use of it more than once, means your const should live outside the function instead, so again, we're forced to put the variable in an object scope.
The question refers to incompliant behaviour in earlier ES6 implementations, notably V8 (Node.js 4 and legacy Chrome versions). The problem doesn't exist in modern ES6 implementations, both in strict and sloppy modes. const reassignment should always result in TypeError, it can be caught with try..catch.
There can't be isConstant function because const variable cannot be identified as such by its value.
It's preferable to run a script in strict mode and thus avoid problems that are specific to sloppy mode.
Even if a variable was defined in sloppy mode, it's possible to enable strict mode in nested function scope:
const foo = 1;
// ...
let isConst = false;
(() => {
'use strict';
try {
const oldValue = foo;
foo = 'new value';
foo = oldValue;
} catch (err) {
isConst = true;
}
})();
It's beneficial to use UPPERCASE_CONSTANT convention which is used in JavaScript and other languages. It allows to unambiguously identify a variable as a constant without aid from IDE and avoid most problems with accidental reassignments.

Function scope is lost in returned methods when strigifying/parsing js objects with JSON

I have such a bit crazy example, but it looks like a good exercise for those who are experts in javascript function scopes:
(function (global) {
// our module number one
var body = function () {
var someVar = 'some test text';
return {
method: function () {
return someVar; // this will undefined when call this method in second module
}
};
};
var f = new Function([' return (', body, ')();'].join(''));
global.r = f();
})(window);
(function (global) {
// our module two
var body = function () {
// dep variable is injected on the fly with `new Function`
dep.method(); // will throw `Reference Error: someVar is not defined`
};
// helper to propertly transform functions in JSON.stringify
function transformFuncs (key, val) {
if (typeof val === 'function') {
return val.toString().replace(/(\t|\n|\r)/gm, '').replace(/("|')/gm, '\\"');
}
return val;
}
// injecting our first module inside
var vars = ['var ', 'dep', ' = JSON.parse(\'', JSON.stringify(global.r, transformFuncs), '\', function (key, value) { if (value && typeof value === "string" && value.substr(0,8) == "function") { var startBody = value.indexOf("{") + 1; var endBody = value.lastIndexOf("}"); var startArgs = value.indexOf("(") + 1; var endArgs = value.indexOf(")"); return new Function(value.substring(startArgs, endArgs), value.substring(startBody, endBody)); } return value; });'].join('');
// as variable
var f2 = new Function([vars, ' return (', body, ')();'].join(''));
global.r2 = f2();
})(window);
If you'll run this code somewhere you'll see an exception thrown ReferenceError: someVar is not defined.
So basically what's happening here - we create some module and then trying to inject it inside another one as variable. Function that is used in JSON.parse to correctly get stringified functions looks like this (if you're curious):
function (key, value) {
if (value && typeof value === "string" && value.substr(0,8) == "function") {
var startBody = value.indexOf("{") + 1;
var endBody = value.lastIndexOf("}");
var startArgs = value.indexOf("(") + 1;
var endArgs = value.indexOf(")");
return new Function(value.substring(startArgs, endArgs), value.substring(startBody, endBody));
}
return value;
}
So.. the question is it possible to workaround such scope behavior? As I understand global.r is assigned with f result in one scope, but resulted object with method function is not saving the variable instance because while JSON parsing another scope is created for that function.
Any ideas?
P.S. Please don't ask why I need this :) just think about possible solutions. The main idea is to somehow inject module number one (look top body var) as variable inside second module (body var of second function) saving the original scope of methods that are returned.
Thanks!
is it possible to workaround such scope behavior?
No. Scopes are inaccessible from outside, and they are necessarily lost on serialisation of a function. You can only stringify "pure" functions like body that do not reference any free variables.
That's also the reason why the JSON format does not include functions.
The main idea is to somehow inject module number one as variable inside second module saving the original scope of methods that are returned.
Inject the reference, not a string. Dependency injection is no magic, all kinds of module loaders for JavaScript do it.

How to force Google Closure Compiler to rename methods even when using objects

It seems that the google closure compiler (http://closure-compiler.appspot.com/home) preserves all of the method names when I use 'this.' or when using a revealing module pattern. It only seems to rename methods to letters when they are not in an object that might be referenced by other external methods. I've tried wrapping both my (Utility) object and the anonymous method that uses it, but this doesn't seem to help. How do you create objects (and separate script files) that might be shared with each other and still have it abbreviate all the method names?
I'm read several posts on SO and do not see anything addressing this, only posts about stuff not getting renamed due to conflicts with external variables.
var Utility = (function () {
this.isDefined = function (v) {
/// <summary>Checks to see if a variable is defined.</summary>
return typeof v !== 'undefined';
}
this.isObj = function (v) {
/// <summary>Checks to see if a variable is an object.</summary>
return typeof v === 'object';
}
...
})();
Then I want to be able to do:
(function(u) {
u.isDefined();
})(Utility);
I've also tried:
var Utility = (function () {
var utility = {};
utility.isDefined = function (v) {
/// <summary>Checks to see if a variable is defined.</summary>
return typeof v !== 'undefined';
}
utility.isObj = function (v) {
/// <summary>Checks to see if a variable is an object.</summary>
return typeof v === 'object';
}
return utility;
...
The revealing object pattern does not work well with closure compiler. Nor does the extra closure you are using which aliases the window and document global variables. The final use case itself is problematic with Closure-compiler as well. Currently, the compiler doesn't handle aliases well especially when passing namespaces as function arguments.
// ==ClosureCompiler==
// #compilation_level ADVANCED_OPTIMIZATIONS
// ==/ClosureCompiler==
var Utility = {};
Utility.isDefined = function (v) {
/// <summary>Checks to see if a variable is defined.</summary>
return typeof v !== 'undefined';
};
Utility.isObj = function (v) {
/// <summary>Checks to see if a variable is an object.</summary>
return typeof v === 'object';
};
(function() {
function myPrivateFunction(x) {
}
Utility.SomeMethod = function(x) {
return myPrivateFunction(x);
};
})();
Utility.isDefined(x);
window['Utility'] = Utility;
Compilation and renaming of this example can be tested at http://closure-compiler.appspot.com/
You can protect your local variables from bleeding into the global scope by using the output_wrapper flag and properly exporting your symbols.
The compiler also specifically disallows usage of the this keyword in non-constructor, non-prototype functions. You should always use the full namespace. The compiler can then flatten the namespace methods (which is why the restriction occurs).
See Which Compilation Level is Right for Me?

Setting this to a var causes possible strict violation: [duplicate]

I think this may be a duplicate of Strict Violation using this keyword and revealing module pattern
I have this code:
function gotoPage(s){
if(s<=this.d&&s>0){this.g=s; this.page((s-1)*this.p.size);}
}
function pageChange(event, sorter) {
var dd = event.currentTarget;
gotoPage.call(sorter, dd[dd.selectedIndex].value);
}
And JSHINT (JSLINT) is complaining. It says "Strict violation." for the highlighted line:
Is my use of Function.call() and then referencing the instance, somehow inappropriate?
Is this considered to be bad style?
JSHint says "Possible strict violation" because you are using this inside something that, as far as it can tell, is not a method.
In non-strict mode, calling gotoPage(5) would bind this to the global object (window in the browser). In strict mode, this would be undefined, and you would get in trouble.
Presumably, you mean to call this function with a bound this context, e.g. gotoPage.bind(myObj)(5) or gotoPage.call(myObj, 5). If so, you can ignore JSHint, as you will not generate any errors. But, it is telling you that your code is unclear to anyone reading it, because using this inside of something that is not obviously a method is quite confusing. It would be better to simply pass the object as a parameter:
function gotoPage(sorter, s) {
if (s <= sorter.d && s > 0) {
sorter.g = s;
sorter.page((s - 1) * sorter.p.size);
}
}
function pageChange(event, sorter) {
var dd = event.currentTarget;
gotoPage(sorter, dd[dd.selectedIndex].value);
}
I've had this message for a function that did not start with a capital letter.
"use strict";
// ---> strict violation
function something() {
this.test = "";
}
// ---> just fine (note the capital S in Something)
function Something() {
this.test = "";
}
If you declare the function as a variable instead of using the standard function declaration, jshint will not flag this as a strict violation. So you may do the following -
var gotoPage = function (s){
if(s<=this.d&&s>0){this.g=s; this.page((s-1)*this.p.size);}
};
var pageChange = function (event, sorter) {
var dd = event.currentTarget;
gotoPage.call(sorter, dd[dd.selectedIndex].value);
};
If you're trying to implement a method, you might want to assign to the prototype instead:
ExampleClassName.protytpe.gotoPage = function gotoPage(s){
// code using this
};
JSHint won't warn when the function is being assigned.

Categories

Resources