I am trying to create a webpack plugin, that will parse the code for a certain function and replace it with another function, that plugin will also expose the new function as a global.
class someName {
constructor(local, domain, translationFile, options) {
}
apply(compiler) {
// exposing ngt function as a global
compiler.plugin('make', function(compilation, callback) {
var childCompiler = compilation.createChildCompiler('someNameExpose');
childCompiler.apply(new webpack.DefinePlugin({
ngt: function(singular , plural, quantity) {
return quantity == 1 ? singular : plural;
}
}));
childCompiler.runAsChild(callback);
});
// searching for the getValue function
compiler.parser.plugin(`call getValue`, function someNameHandler(expr) {
// create a function to replace getValue with
let results = 'ngt('+ expr.arguments +')';
const dep = new ConstDependency(results, expr.range);
dep.loc = expr.loc;
this.state.current.addDependency(dep);
return true;
});
}
}
module.exports = someName;
update / rephrase
I have an issue here, when compiler.parser.plugin('call getValue', function someNameHandler(expr) {...} block is commented the ngt function exist as a global.
when its not commented, i get an error, ngt is undefined.
commented i mean /**/
I found a workaround for that but its far then idea. right now what I do is I export an anonymous function that does what i want.
You can see the plugin here:
Github
You can override the method based on environment. Let's say you have a method
function a(){
//original defination
}
Now based on the environment, if it's a production you could do something like this
if (environment.production) {
function a(){
//overridden defination
}
}
You can use the webpack-merge plugin, it's very useful to do exactly what do you want.
https://github.com/survivejs/webpack-merge
Related
Some months ago I created a Js library that I published on Npm.
Now I would like to rename some functions.
I read this post and I think it's very useful.
Suppose I have a file A:
export function function1(param1, param2) {
return param1 + param2
}
The exported functions that are usable from library users are in index.js file:
export { function1 } from './A'
and I want to rename it as sum(param1, param2).
I create this obsolete function:
function obsolete(newFunction, oldFnName, newFnName) {
const wrapper = function () {
console.warn(
`Obsolete function called. Function '${oldFnName}' has been deprecated, please use the new '${newFnName}' function instead.`
)
newFunction.apply(this, arguments)
}
wrapper.prototype = newFunction.prototype
return wrapper
}
Now what I have to do?
I suppose I have to modify the A file in this way:
/** #deprecated since version 2.0 */
export function function1(param1, param2) {
return sum(param1, param2)
}
export function sum(param1, param2) {
return param1 + param2
}
and add the sum function to the index file:
export { function1, sum } from './A'
And then? How can I use the obsolete function?
Ok, so this question seems to have been prompted by your comment (now deleted it seems):
Suppose I have a function fun1 that I want to make it deprecated and
the new function is fun2. How can I use this obsolete function? It
seems interesting
From this question.
So firstly, your getting a JSdoc (/** #deprecated since version 2.0 */) annotation and this function mixed up.
JSDoc is a markup language used to annotate JavaScript source code files
source
So this is only useful if your planning on creating a JSdoc annotation. Which I'm presuming your not. If your using JSdoc then this should work as is?
So ignoring that I'm going to go back to your question on this code.
Looking at the code you could use it like (not 100% sure as I didn't write it):
// the function from the previous question
function obsolete(oldFunc, newFunc) {
const wrapper = function() {
console.warn(`WARNING! Obsolete function called. Function ${oldFunc.name} has been deprecated, please use the new ${newFunc.name} function instead!`)
newFunc.apply(this, arguments)
}
wrapper.prototype = newFunc.prototype
return wrapper
}
// this is the function that is the replacement for obsfunc
function newfunc(){
console.log('new called');
}
// this is the function that is being made "obsolete"
function obsfunc(p) {
return obsolete(obsfunc, newfunc)();
}
// when you call the obsolete function it's actually the new function
// that gets triggered and an error is displayed in the console.
obsfunc();
in my case functions have parameters and a return value
this code doesn't support that. There is no official way to "obsolete" a function in the Js spec. TBH this is the correct (now deleted) answer to that question IMO. So you'll need to write your own solution. It's not really clear what your definition of "obsolete" is either? Decorators is a good option
There is no way of "setting" a function as deprecated. You just make a function similar to this:
function function1 () {
obsolete(function1(), "function1", "newFunction1")
}
I realize this might not be super useful, but if you are working with babel you might want to look into es7 decorators, they are meant exactly for use-cases like this one. although they still have no native browser support, hence Babel
function obsolete(newFuncGetter)
{
return (prototype, key, descriptor) => {
descriptor.value = (...args) => {
const newFunc = newFuncGetter();
console.warn(`'${key}' has been deprecated, please use '${newFunc.name}' instead!`);
return newFunc(...args);
};
return descriptor;
};
}
class Foo
{
static newfunc()
{
return 'new called';
}
#obsolete(() => Bar.newfunc)
static obsfunc()
{
return 'old value';
}
}
console.log(Bar.obsfunc());
I discovered babel only allows decorators on classes and their items, but I believe the actual decorators should also allow separate functions
The usage of your obsolete function is very simple:
All you have to do is to pass the new function to it:
/** #deprecated since version 2.0 */
export const function1 = obsolete(function function1(param1, param2) {
return param1 + param2
}, 'function1', 'sum')
One more minor tweak you could add to your obsolete declaration is a name setting so that the obsolete function will look the same as the original (that would avoid breaking anyone's code - or not anyone's?):
function obsolete(newFunction, oldFnName, newFnName) {
const wrapper = function () {
console.warn(
`Obsolete function called. Function '${oldFnName}' has been deprecated, please use the new '${newFnName}' function instead.`
)
newFunction.apply(this, arguments)
}
wrapper.prototype = newFunction.prototype
Object.defineProperty(wrapper, 'name', {
value: oldName,
enumerable: true,
configurable: true
}
return wrapper
}
However, if you just rename a method, you can avoid redefinition by passing the reference of the new one to the obsolete:
export function sum(param1, param2) {
return param1 + param2
}
/** #deprecated since version 2.0 */
export const function1 = obsolete(sum, 'function1', 'sum')
With the name fix from above, this will even rename your deprecated version of the new function to its old name, without manually creating a wrapper.
What is the equivalent code of window["functionName"](arguments) in NodeJS server-side?
If you need such a capability within a module, one hack is to store such module functions in variables within the module and then call them by accessing them from the module object properties. Example:
var x = { }; // better would be to have module create an object
x.f1 = function()
{
console.log('Call me as a string!');
}
Now, within the module, you can call it using the value from a string:
var funcstr = "f1";
x[funcstr]();
I am learning the ropes with Node myself, the above is probably all sorts of wrong :-). Perhaps a marginally better way to write this example would be (for the module m.js):
module.exports =
{
f1: function() { console.log("Call me from a string!"); },
f2: function(str1) { this[str1](); }
}
Now you can:
var m = require('m.js');
m.f2('f1');
Or even just:
var m = require('m.js');
m['f1']();
FWIW!
you're looking for global
Note, however, that in modules nothing is ever exposed to this level
1) If methods are in same js file
define all methods as properties of Handler:
var Handler={};
Handler.application_run = function (name) {
console.log(name)
}
Now call it like this
var somefunc = "application_run";
Handler[somefunc]('jerry codes');
Output: jerry codes
2) If you want to keep methods in a different js file
// Handler.js
module.exports={
application_run: function (name) {
console.log(name)
}
}
Use method defined in Handler.js in different.js:
// different.js
var methods = require('./Handler.js') // path to Handler.js
methods['application_run']('jerry codes')
Output: jerry codes
If you want to call a class level function using this then following is the solution and it worked for me
class Hello {
sayHello(name) {
console.log("Hello " + name)
}
callVariableMethod() {
let method_name = 'sayHello'
this[`${method_name}`]("Zeal Nagar!")
}
}
If You need it in module scope, You can use something like this
var module = require('moduleName');
module['functionName'](arguments);
Honestly, looking at all these answers they seem a bit too much work. I was playing around to look for other ways around this. You can use the eval() command to print a variable as text then call it as a function
I.e
let commands = ['add', 'remove', 'test'];
for (i in commands) {
if (commands[i] == command) {
var c = "proxy_"+command;
eval(c)(proxy);
}
}
eval(string)(arg1, arg2);
This example script would execute the function proxy_test(proxy)
You know, the OP's code inspired me to try this:
global.test = function(inVal){
console.log(inVal);
}
global['test']('3 is the value')
But now that I think about it, it's no better than #Ravi' s answer.
I use this for node, see if this approach works for you
var _ = require('lodash');
var fnA1 = require('functions/fnA1');
var fnA2 = require('functions/fnA2');
module.exports = {
run: function(fnName, options, callback) {
'use strict';
var nameSpace = fnName.toString().split('.');
// if function name contains namespace, resolve that first before calling
if (nameSpace.length > 1) {
var resolvedFnName = this;
_.forEach(nameSpace, function(name){
resolvedFnName = resolvedFnName[name];
});
resolvedFnName(options, callback);
} else {
this[fnName](options, callback);
}
},
fnA1: fnA1,
fnA2: fnA2
};
call this like
importVariable.run('fnA1.subfunction', data, function(err, result){
if (err) {return callback(err);}
return callback(null, result);
});
That is not specific to the window object. In JavaScript any property of the object can be accessed this way. For example,
var test = {
prop1 : true
};
console.log(test.prop1); // true
console.log(test["prop1"]); // also true
Read more here : https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects
I'm getting the error while running the following code in Node.js
var assert = require('assert');
var request = require('request');
var index = require('./index');
it('verify javascript function', function(done) {
var v2 = index.AddNumbers(5, 6);
assert.equal(11, v2);
done();
});
The index.js file contain the following code:
function AddNumbers(a,b){
return a+b;
}
What am I doing wrong?
This happened to me many times because of circular dependency, check if you have 2 classes that are requiring each other, remove one of them from requiring the other and the issue should be solved
With NodeJS modules, to make something public, you have to export it. Add this to the end of index.js:
module.exports.AddNumbers = AddNumbers;
(That's using the old CommonJS modules. For ESM, it would be export AddNumbers;)
Here it is running on my machine:
$ cat index.js
function AddNumbers(a,b){
return a+b;
}
module.exports.AddNumbers = AddNumbers;
$ cat example.js
var index = require('./index');
var v2 = index.AddNumbers(5,6);
console.log(v2);
$ node example.js
11
I'm fairly a beginner at Node JS so I managed to get this error by importing a function like so:
const { functionName } = require('./function')
instead of like so:
const functionName = require('./function')
Editing my post to add an explanation since I've learned more node since I wrote it. If a module exports an object containing multiple functions functions like so:
module.exports = { functionName, otherFunction }
Then the function has to be deconstructed out of the object during the import, as in the first code snippet. If the module exports a single function or a default function, like so:
module.exports = functionName
Then tt must be imported directly, as in the second code snippet.
If you need to expose a specific component, function or a variable to public. You have to exports those components using JavaScript modules.
let add = (a,b)=>{
return ( a+b);
}
module.exports.add=add;
or if you want to expose multiple functions, you can do as follows.
let add = (a,b)=>{
return (a+b);
}
let subtract = (a, b)=>{
return (a-b);
}
module.exports={
add : add,
subtract : subtract
};
This is happening because two files are referencing each other i.e You are calling function (s) from file A in file B and vice versa which is called Circular Dependency.
Your "AddNumbers" function in the "index.js" file should be as follows,
function AddNumbers(a,b){
var addition = function(a, b){
return (a + b) ;
};
module.exports = {
additionResult: addition
};
}
And you need to call it in your "Node.js" file as follows
var assert = require('assert');
var request = require('request');
var index = require('./index');
it('verify javascript function', function(done) {
var v2 = index.additionResult(5, 6);
assert.equal(11, v2);
done();
});
This should work. Please note that you call the function by whatever the token name you exported the return value by (I use a different name here just for clarity). Almost everybody uses the same name as the function name so there are no confusion. Also in ES6, if you use the same name you can export as just,
module.exports = {
addition
};
instead of,
module.exports = {
addition: addition
};
since you use the same name. It is an ES6 feature.
I ran into the same problem while trying to follow a Nodejs tutorial by w3schools.
I copied the following code from them:
exports.myDateTime = function () {
return Date();
};
That, however, wouldn't work for me. What resolved the problem for me was adding module. before the exports keyword like this:
module.exports.myDateTime = function () {
return Date();
};
The most correct answer was from #shimi_tap. I want to reply it as comment, but doesn't have enough reputation, so I am gonna answer it using a simple example, like in this case below:
File A has 3 functions to process database activity: function
addDB, updateDB, and delData;
File B has 2 functions to process User activity on smartphone:
function addHistory, and editHistory;
Function updateDB in file A is calling function editHis in file B, and function editHistory is calling function updateDB in file A. This is what we called circular-dependency. And we need to prevent it by only giving output of state from editHistory and the rest will be processed inside file A.
//ORIGINAL FUNCTIONS which caused CIRCULAR DEPENDENCY
function updateDB() {
//process update function here
//call function in fileB
const history = require("fileB.js");
await history.editHistory(data).then((output) => {
if(output["message"] === "success"){
response = {
state: 1,
message: "success",
};
}
});
return response;
}
//THIS is the WRONG ONE
function editHistory() {
//process function to edit History here
//call function in fileA
const file = require("fileA.js");
await file.updateDB(data).then((output) => { //You should not call it here
if(output["message"] === "success") {
output = {
state: 1,
message: "success",
};
}
});
return output;
}
//==================================================//
//THE FIX
function updateDB() {
//process function here
const history = require("fileB.js");
await history.editHistory(data).then((output) => {
if(output["message"] === "success"){
await updateDB(data).then((output) => {
response = {
state: 1,
message: "success",
};
});
} else {
log("Error");
}
});
return response;
}
function editHistory() {
//process function to edit History here
// No more calling to function inside the file A
output = {
state: 1,
message: "success",
};
return output;
}
https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de
this post visualizes the circular dependency injection
like a child or nested file tried to import parent or top-level file
repo.js
service.js
there are 2 files
service.js uses repo.js file by importing
it works
but check in repo.js that it tried to import service.js file
it shows circular dependency injection warning
In my case the problem was the missing semicolon at the end of the lines.
const codec = JSONCodec()
(async () => {
for await (const message of subscription) {
const payload = codec.decode(message.data)
stompServer.send('/topic/update-event', {}, payload)
}
})()
This produced the following error:
TypeError: JSONCodec(...) is not a function
I was so used to writing code without semicolons, which led me to this problem with the bare NodeJs. As soon as I had put the semicolons, the problem disappeared.
A simple way I debugged this (After about 2 days of troubleshooting) was to actually see why 'x' is not a function. Basically, console.log(x) to see the actual object returned. Turned out I was conflicting x with another declared variable (happens especially when you use axios.res and req,res args.
Require the other file in function level.
fileOne.js
function main() {
const fileTwo = require('./fileTwo');
console.log("hello from file one");
}
module.exports = main;
main();
fileTwo.js
function main() {
const fileOne = require('./fileOne');
console.log("hello from file two");
}
module.exports = main;
main();
Now execute > node fileOne.js
Output:
hello from file two
hello from file one
One silly mistake I did was while exporting was:
module.exports = [module_name_1, module_name_2, ..., module_name_n]
The right way is:
module.exports = {module_name_1, module_name_2, ..., module_name_n}
I've got a slightly unusual pattern I'm trying to achieve and have not quite figured it out. My goal is to create a function called debugLog as a flexible console.log replacement, which can be called as follows:
debugLog('thing to log #1', 'thing to log #2', objectToLog1, objectToLog2);
^^ the number of params should be arbitrary, just as is possible with console.log
That is what I'll call the "default" functionality. Now I'd also like to add some additional functionality through property functions.
Examples:
debugLog.setDebugFlag(true); // sets the internal this.debugFlag property to true or false depending on param
I'm trying to do this in Node and what I have so far does not quite let me achieve this pattern:
var debugLog = function () {
this.debugFlag = this.debugFlag || true;
if (this.debugFlag) {
console.log.apply(null, arguments);
} else {
// production mode, nothing to log
}
};
debugLog.prototype.setDebugFlag = function (flagBool) {
this.debugFlag = flagBool;
}
module.exports = new debugLog();
This module would be including in a Node app using the standard require pattern:
var debugLog = require('./debugLog.js');
The question is how can I achieve this pattern of a function object with default functionality, but also extended "property" style functions? Please note I am already aware of the typical pattern where ALL functionality comes from function properties (such as debugLog.log() and debugLog.setDebugFlag()). But that patterns does NOT achieve my key goal of a shorthand for the default functionality that simply involves calling the function directly.
Is it even possible to do?
You could do it this way
var debugLog = (function() {
var debugFlag = true;
function log() {
if (debugFlag) {
console.log.apply(null, arguments);
} else {
// production mode, nothing to log
}
};
log.setDebugFlag = function(flag) {
debugFlag = flag;
}
return log;
})();
module.exports = debugLog;
You could use closure, like so:
// debugLog.js
var debugFlag = true;
function debugLog() {
if (debugFlag) {
console.log.apply(null, arguments);
} else {
// production mode, nothing to log
}
}
debugLog.setDebugFlag = function (newFlag) {
debugFlag = newFlag;
}
module.exports = debugLog;
and use it like this:
// otherFile.js
var debugLog = require('./debugLog');
debugLog('Hey!');
debugLog.setDebugFlag(false);
debugLog('This wont appear!');
What is the equivalent code of window["functionName"](arguments) in NodeJS server-side?
If you need such a capability within a module, one hack is to store such module functions in variables within the module and then call them by accessing them from the module object properties. Example:
var x = { }; // better would be to have module create an object
x.f1 = function()
{
console.log('Call me as a string!');
}
Now, within the module, you can call it using the value from a string:
var funcstr = "f1";
x[funcstr]();
I am learning the ropes with Node myself, the above is probably all sorts of wrong :-). Perhaps a marginally better way to write this example would be (for the module m.js):
module.exports =
{
f1: function() { console.log("Call me from a string!"); },
f2: function(str1) { this[str1](); }
}
Now you can:
var m = require('m.js');
m.f2('f1');
Or even just:
var m = require('m.js');
m['f1']();
FWIW!
you're looking for global
Note, however, that in modules nothing is ever exposed to this level
1) If methods are in same js file
define all methods as properties of Handler:
var Handler={};
Handler.application_run = function (name) {
console.log(name)
}
Now call it like this
var somefunc = "application_run";
Handler[somefunc]('jerry codes');
Output: jerry codes
2) If you want to keep methods in a different js file
// Handler.js
module.exports={
application_run: function (name) {
console.log(name)
}
}
Use method defined in Handler.js in different.js:
// different.js
var methods = require('./Handler.js') // path to Handler.js
methods['application_run']('jerry codes')
Output: jerry codes
If you want to call a class level function using this then following is the solution and it worked for me
class Hello {
sayHello(name) {
console.log("Hello " + name)
}
callVariableMethod() {
let method_name = 'sayHello'
this[`${method_name}`]("Zeal Nagar!")
}
}
If You need it in module scope, You can use something like this
var module = require('moduleName');
module['functionName'](arguments);
Honestly, looking at all these answers they seem a bit too much work. I was playing around to look for other ways around this. You can use the eval() command to print a variable as text then call it as a function
I.e
let commands = ['add', 'remove', 'test'];
for (i in commands) {
if (commands[i] == command) {
var c = "proxy_"+command;
eval(c)(proxy);
}
}
eval(string)(arg1, arg2);
This example script would execute the function proxy_test(proxy)
You know, the OP's code inspired me to try this:
global.test = function(inVal){
console.log(inVal);
}
global['test']('3 is the value')
But now that I think about it, it's no better than #Ravi' s answer.
I use this for node, see if this approach works for you
var _ = require('lodash');
var fnA1 = require('functions/fnA1');
var fnA2 = require('functions/fnA2');
module.exports = {
run: function(fnName, options, callback) {
'use strict';
var nameSpace = fnName.toString().split('.');
// if function name contains namespace, resolve that first before calling
if (nameSpace.length > 1) {
var resolvedFnName = this;
_.forEach(nameSpace, function(name){
resolvedFnName = resolvedFnName[name];
});
resolvedFnName(options, callback);
} else {
this[fnName](options, callback);
}
},
fnA1: fnA1,
fnA2: fnA2
};
call this like
importVariable.run('fnA1.subfunction', data, function(err, result){
if (err) {return callback(err);}
return callback(null, result);
});
That is not specific to the window object. In JavaScript any property of the object can be accessed this way. For example,
var test = {
prop1 : true
};
console.log(test.prop1); // true
console.log(test["prop1"]); // also true
Read more here : https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects