I'm writing some code where I need to be able to load, unload, and reload modules on the fly (without closing the program). A big issue I'm running into is that there's no way to give unique names to the modules when I reload them - that is, I'm using a generalized function to reload them:
try {
delete require.cache['./plugins/'+plugin];
console.log("Reloading " + plugin + ".");
var ??? = require('./plugins/'+plugin);
}
Given that this needs to work for an unspecified number of modules (and even modules that weren't included upon startup), how can I go about naming the new Require variable (currently ??? is a placeholder).
Thanks!
edit:
for (i in fs.readdirSync("./plugins")) {
var pluginName = plugins[i].split('.')[0]
plugins[pluginName] = pluginName;
plugins[pluginName] = require("./plugins/" + pluginName);
console.log(global.plugins[i].split('.')[0]);
};
console.log(testModule1.addi(2, 3));
console.log(testModule2.mult(2,3));
This is what I have right now and it doesn't work (testModule1.addi is just addition and testModule2.mult is just mulitplication). It works just fine when I do something like:
var testModule1 = require("./plugins/testModule1");
var testModule2 = require("./plugins/testModule2");
and then call the functions.
You can't have variable variable names like that, but fortunately you can use an object, and give it property names which are variable, something like this:
var uuid = require('node-uuid');
var myModules = {};
var moduleName = 'module_' + uuid.v1();
myModules[moduleName] = require('./plugins/' + plugin);
This will guarantee you a unique name each time under moduleName that you can use.
Related
Edit: the code below was made up on the spot to show how I was going about what I was doing. It definietely won't run, it is missing a lot of things.
Here is a working example in codepen: https://codepen.io/goducks/pen/XvgpYW
much shorter example: https://codepen.io/goducks/pen/ymXMyB
When creating a function that is using call or apply, the this value stays null when using getPerson. however, when I use apply or call with getPerson it returns the correct person.
Please critique, I am really starting to learn more and more. I am in the middle of a project section so it might be hard to change all the code, but my next project could implement this better.
call and apply are setting to the window and not the object.
I will provide code that is much simpler with the same concept of what I am talking about.
function createPerson(){
this.manager = null;
this.teamManager = null;
this.setTeamManager = function(val){
this.teamManager = val;
}
this.setManager = function(val){
console.log('setting manager to',val);
this.teamManager = val;
}
this.getTeamManager = function(){
console.log('setting team manager to',val);
return this.teamManager ;
}
this.getManager = function(){
return this.manager;
}
this.appendSelect = function(elem){
var that = this;
createOtherSelects(that,elem);
}
//some functions that create selects with managers etc
//now assume there are other selects that will filter down the teams,
//so we might have a function that creates on change events
function createOtherSelects(that){
//code that creates locations, depending on location chosen will
//filter the managers
$('#location').on('change',function(){
//do some stuff
//... then call create management
createManagement(that,elem);
});
}
function createManagement(that,elem){
var currentLocation = that.location; //works
var area = that.area;//works ... assume these are set above
//code that returns a filter and unique set of managers back
that.teamManager = [...new Set(
data.map(person=>{
if(person.area==area &&
person.currentLocation==currentLocation
){
return person;
}
})
)].filter(d=>{if(d){return d}});
if(elem.length>0){
var selectNames = ['selectManager','selectTeamManager'];
var fcns = [that.setManager,that.setTeamManager];
for(var i = 0; i < selectNames.length;i++){
//do stuff
if(certainCriteriaMet){
// filter items
if(filteredManager == 1){
fcns[i].call(null,currentManager);//
}
}
}
}
}
}
var xx = new createPerson()
In console I see setting manager and setting team manager to with the correct values.
however when I call xx in console, I see everything else set except for
xx.teamManager and xx.manager
instead it is applying to the window, so if I type teamManager in the console, it will return with the correct person.
If I straight up say
that.setManager('Steve')
or even it works just fine.
xx.setManager('steve')
the this value in setManager is somehow changing from the current instance of the object to this window. I don't know why, and I would like to learn how to use apply and call using that for future reference.
I think the issue is with your following code
fcns[i].call(null,currentManager)
If you are not supplying "this" to call, it will be replaced with global object in non-strict mode.
fcns[i].call(that,currentManager)
See mdn article here
From your codepen example, you need to change that line
fcnset[0].apply(that,[randomName]);
The first argument of the apply method is the context, if you are not giving it the context of your method it's using the global context be default. That's why you end up mutating the window object, and not the one you want !
I am working on a Preact-CLI project with a Preact-Router and it works fine on the localhost. But the production doesn't work well after the build.
I have created a one page object which gets its content dynamically from a JSON file (inside the project not external). So I've loaded the same page object 2 times for each different page.
I get the page url (using this.props.permalink) and compare it with the JSONObject.title. If they are the same I want to get the corresponding JSON content to display it on the corrrct page. Works like a charm on localhost, but not in production.
Issue:
Somehow all pages get the content of the first JSON element. First I thought it was a server issue but I was wrong. The builded files are wrong after the prerendering/build. So the prerendered html of page B contains the content of the prerendered page A.
My guess is that during the build this.props.permalink doesn't work. How should I handle this?
Additional info:
I use the prerender function but not the service worker for the build.
Thanks!
UPDATE:
I have rewritten the function. I guessed I needed to set the dynamic content through a loop, so that during the build the compiler loops through it and is able to prerender all the pages.
The iteration and setting the state works, but only the final element of the PrerenderUrls array gets stored. So now all pages gets the JSON content of the first element.
componentWillMount() {
for (var i = 0; i <= PrerenderUrls.length; i++) {
// the code you're looking for
let removeDash = new RegExp("-")
var needle = PrerenderUrls[i].title
var needle1 = needle.replace(removeDash, " ")
alert("1")
// iterate over each element in the array
if (needle1 != "Homepage") {
for (var x = 0; x < Data.length; x++) {
// look for the entry with a matching `code` value
let removeDash = new RegExp("-")
var nodash = Data[x].title.replace(removeDash, " ")
var nocaps = nodash.toLowerCase()
if (nocaps == needle1) {
alert("needle2: "+ needle1 + " nocaps: " + nocaps)
//alert("data "+ Data[x].title)
this.setState({
pageTitle: Data[x].title,
descShort: Data[x].descShort,
description: Data[x].desc,
img: Data[x].img
})
alert("state "+ this.state.pageTitle)
}
}
}
}
From your description it seems you have a standard Javascript closure problem. I noticed you use both let and var. If let is supported, use it instead of var. It will automagically solve your closure issues, because let creates variables with the block scope, instead of a function scope. Otherwise, you can try to replicate how let does it under the hood - throw the variable to the callback function. Something in the lines of:
// ...
for (var x = 0; x < Data.length; x++) {
try { throw x }
catch(iterator) {
this.setState({
pageTitle: Data[iterator].title
});
}
}
PS. It is very difficult to follow your code, when it is so specific to your functionality. You could simplify it, and focus on the troubling issue. Most of the code you provided is not relevant to your problem, but makes us going through it anyway.
In the following code example I want to somehow create a var myThingName via a functions arguments so I can avoid having to build global var names outside of the Module.
I have tinkered with window['myvarname'] = "yada"; But that's a global and feels like a complete hack.
In short, I am assuming I need to have a way to make many vars like : myThingName_1 myThingName_2 etc...
Background: I am trying to build a Canvas Element constructor to put any number of individual Canvas elements onto the screen. I am using various libraries like Paper.js Kinetic.js etc. When trying to streamline the production I built a Module wrapper but am now stuck at how to create unique var names for the libraries KLASS constructor for their various implementations of stage or scope.
Perhaps I am doing things totally incorrectly from the start.
But at the moment I am stumped as to how this goes about or what the name of the pattern I am looking.
var MagicThingModule = {
createThing : function(myThingNameAsString){
var myThingName = myThingNameAsString;
myThingName = new KLASS.Shape({ // code });
},
init : function(myThingNameAsString){
createThing(myThingNameAsString);
}
}
MagicThingModule.init("sendNameForThing_1");
How about:
var MagicThingModule = {
allMyThings: {},
createThing : function(myThingNameAsString){
var myThingName = myThingNameAsString;
myThingName = new KLASS.Shape({ // code });
this.allMyThings[myThingNameAsString] = myThingName;
},
// use me to et your thing back...
getMyThing: function(myThingName){
return this.allMyThings[myThingName];
},
init : function(myThingNameAsString){
createThing(myThingNameAsString);
}
}
and you can later reference it by:
var myThing = MagicThingModule.getMyThing("sendNameForThing_1");
Is there a way to get the ScriptNode that initiated a state in an Activiti workflow in Alfresco? I have a ScriptTask in my workflow, and it has a Alfresco Script Listener set up for the Start event. When the script is called, I'd like the ScriptNode that transitioned into the ScriptTask in the workflow to be passed as a parameter to the function defined as the listener. Is that possible?
Editing for clarity:
Here's a screenshot of Eclispe with the Activiti plugin.
http://i.imgur.com/DAKtq.jpg
This workflow gets started by another workflow with webscripts.
var props = new Object();
var dd = new Date();
props[EL_PROP_WORK_UNIT_NAME] = "testNode" + DateISOString( dd );
props[EL_PROP_WORK_UNIT_SOURCE_CODE] = "ROB";
props[EL_PROP_WORK_UNIT_DELIVERY_DATE] = dd;
node = getHome().createNode(name, EL_TYPE_WORK_UNIT, props);
var EL_WORKFLOW = "activiti$The-workflow";
var activeWfs = node.activeWorkflows;
if( activeWfs === null || activeWfs.length === 0 )
{
var workflowPackage = workflow.createPackage();
workflowPackage.addNode( node );
var workflowDef = workflow.getDefinitionByName(EL_WORKFLOW);
var workflowPath = workflowDef.startWorkflow( workflowPackage, new Object());
}
So the listener calls another javascript method...
function artPDFRename()
{
logger.log("==============================");
logger.log("<START> artPDFRename");
var workflowDef = workflow.getDefinitionByName(EL_WORKFLOW);
var activeInstance = workflowDef.getActiveInstances();
// ????
}
The goal is to have this handling be automatic. We're trying to design this with as little of manual intervention as possible, and are not assigning tasks to users to perform. Yes, there's probably another way to rename a PDF file, but I can't seem to figure out from the documentation listed here how to get a pointer to the node I put in the bpm_package object. That's the question.
Or am I so far off base on how we're developing this that it makes no sense?
As an example check the ScriptTaskListener class. Here all the workflow variables are put in a map.
The following code is interesting:
// Add all workflow variables to model
Map variables = delegateTask.getExecution().getVariables();
for (Entry<String, Object> varEntry : variables.entrySet())
{
scriptModel.put(varEntry.getKey(), varEntry.getValue());
}
So with this you could use bpm_package as an object within your script within the workflow script task.
So if you need the node were the workflow has run on, the following code should work (where task is your delegateTask from your notify method of the Listener:
delegateTask.getVariable("bpm_package");
// or like the example above
delegateTask.getExecution().getVariable("bpm_package");
This will be a list so take the first one and that will be your node.
---------update
If you're using the javascript from alfresco then you can directly use the parent object bpm_package.
So in your case it would be best to do the following:
var node = bpm_package.children[0]; //or you could check if the
package isn't null
// Then send the node into your
artPDFRename(node); //or you could just add the bpm_package code in
your js file
I am trying to copy some data from one processed web page into a new one that I want to export. The background is that I need to scrape parts of a page and need to build a new page with parts of the original page.
The problem seems that phantomJs includeJs() and evaluate() methods are sandboxed and I can't see a proper way to import DOM from one page to another.
I have some test code that looks like this, with page being the original and out the new page:
....
var title = page.evaluate(function() {
return title = document.getElementById('fooo').innerHTML;
});
console.log('page title:' + title);
//fs.write('c:/Temp/title.js', "var title = '" + title + "';", 'w');
var out = new WebPage;
out.viewportSize = page.viewportSize;
out.content = '<html><head></head><body><div id="wrapper"></div><p>done</p></body></html>';
out.includeJs('c:/Temp/title.js', function() {
var p = document.createElement('p');
p.appendChild(document.createTextNode(title));
document.getElementById('wrapper').appendChild(p);
});
...
The function in your last includeJs call here won't work - as you note, it's sandboxed, and that means that closures won't work, so title won't be defined. A method of passing variables to page.evaluate is noted as a feature request, but isn't available as of PhantomJS v.1.4.1.
The general way I get around this is by using the Function constructor, which allows you to create a function using a string:
var myVar = {some:"values", I:"want to pass into my page"},
test = new Function("window.myVar = " + JSON.stringify(myVar));
page.evaluate(test);
Now you can evaluate a function like the one you have, referencing myVar in the sandbox, and your data will be available in the client scope.