Custom Yeoman Generator can't overwrite files - javascript

I'm trying to create a simple generator to standardize creation of node projects. In my generator I make calls to copyTpl like:
generator.fs.copyTpl(
sourcePath,
destinationPath
context,
//ignore ES6 constructs in our templates
{
interpolate: /<%=([\s\S]+?)%>/g
}
);
This works great as long as no files exist in my target directory. Unfortunately, if a file exists and I choose to overwrite it I get the following error:
Error: no writecb in Transform class
at afterTransform (/Users/gerrard00/projects/generator-mine/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:95:33)
at TransformState.afterTransform (/Users/gerrard00/projects/generator-mine/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:79:12)
at Object.callback (/Users/gerrard00/projects/generator-mine/node_modules/yeoman-generator/lib/base.js:787:7)
at /Users/gerrard00/projects/generator-mine/node_modules/yeoman-generator/lib/util/conflicter.js:79:18
at Conflicter.<anonymous> (/Users/gerrard00/projects/generator-mine/node_modules/yeoman-generator/lib/util/conflicter.js:193:12)
at PromptUI.onCompletion (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/inquirer/lib/ui/prompt.js:57:10)
at AnonymousObserver.Rx.AnonymousObserver.AnonymousObserver.completed (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/rx-lite/rx.lite.js:1550:12)
at AnonymousObserver.Rx.internals.AbstractObserver.AbstractObserver.onCompleted (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/rx-lite/rx.lite.js:1489:14)
at Subject.Rx.Subject.addProperties.onCompleted (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/rx-lite/rx.lite.js:5871:19)
at Subject.tryCatcher (/usr/local/opt/nvm/versions/node/v5.0.0/lib/node_modules/yo/node_modules/rx-lite/rx.lite.js:63:31)
This means that my generator only works in empty folders. I've re-read the "Creating a generator" docs about twenty times, but I can't figure out what I'm missing. What do I need to add to my generator to prevent this error?
Update: The files are actually overwritten, despite the error.

It turns out that the issue was with the fact that my code was walking a directory asynchronously using the node-walk package. The calling method used the generator async method, but called the done callback synchronously. I modified it to call the done callback in the walk end event handler and the error went away.

Related

How to edit an object within a very simple JS file using Node.js

Whilst this question is related to Workbox and Webpack, it does not require any prior knowledge of either library.
Background (skip if not familiar with Workbox)
I am currently utilising the InjectManifest plugin from Workbox 4.3.1 (workbox-webpack-plugin). This version of the library offers an option called manifestTransforms, but unfortunately, the transformations are not applied to assets within the webpack compilation (this is a known issue).
Whilst this has been fixed in Workbox v5+, I am unable to upgrade due to another library in my build process requiring webpack v3 (Dynamic Importing in Laravel Mix)
The reason I mention the above is because unforunately the solution is not to upgrade to workbox v5+.
The Problem
I have an auto-generated file that looks like this:
self.__precacheManifest = (self.__precacheManifest || []).concat([
{
"revision": "68cd3870a6400d76a16c",
"url": "//css/app.css"
},
// etc...
]);
I need to somehow extract the the contents of the object stored within self.__precacheManifest, apply my own transformations, and then save it back to the file.
What I have Tried...
This is as far as I have got:
// As the precached filename is hashed, we need to read the
// directory in order to find the filename. Assuming there
// are no other files called `precache-manifest`, we can assume
// it is the first value in the filtered array. There is no
// need to test if [0] has a value because if it doesn't
// this needs to throw an error
let manifest = fs
.readdirSync(path.normalize(`${__dirname}/dist/js`))
.filter(filename => filename.startsWith('precache-manifest'))[0];
require('./dist/js/' + manifest);
// This does not fire because of thrown error...
console.log(self.__precacheManifest);
This throws the following error:
self is not defined
I understand why it is throwing the error, but I have no idea how I am going to get around this because I need to somehow read the contents of the file in order to extract the object. Can anyone advise me here?
Bear in mind that once I have applied the transformations to the object, I then need to save the updated object to the file...
Since self refers to window and window does not exist in node.js a way around is needed.
One thing that should work is to define the variable self in Node's global scope and let the require statement populate the content of the variable, like this:
global['self'] = {};
require('./dist/js/' + manifest);
console.log(self.__precacheManifest);
To save the modified contents back to the file
const newPrecacheManifest = JSON.stringify(updatedArray);
fs.writeFileSync('./dist/js/' + manifest, `self.__precacheManifest = (self.__precacheManifest || []).concat(${newPrecachedManifes});`, 'utf8');

NodeJS require script with different behaviour

I'm writing a serverless application which contains a file, for simplicity let's call it icecream.js. Now I have multiple build and deployment methods.
One simply takes this file, icecream.js, and moves it into lots of other code needed for the purpose of that build. Let's call the script which was built, containing the same code (at some point) as icecream.js, hotfudgesundae.js (Ice burried by delicious hot fudge). I can't control the hot fudge that makes up the rest of the built script. I also can't control the build process.
Build process number two executes a script (Let's call it sundaepie.js) which needs the module.exports value of icecream.js (We all know there must be some ice cream buried in there somewhere). It mustn't execute any of the code hotfudgesundae.js needs when requiring it.
Now there's a fourth script, SearchingSolutions.js, which require's the hotfudgesundae.js script.
The only thing I can control is sundaepie.js and icecream.js, so I can change the way that sundaepie requires icecream.js and what icecream.js includes.
PROBLEM: I need to write icecream.js in a way that the code it contains IS executed for hotfudgesundae.js, but not executed when required with sundaepie.js. The module.exports can stay the same.
What I tried: I can't just check if module.parent exists, because while hotfudgesundae.js doesn't require the script (icecream.js is baked into it when built), hotfudgesundae.js itself is required by SearchingSolutions.js.
I tried to make module.exports a function with one parameter, and if this parameter is given, return something, else execute the code that hotfudgebrownie.js needs. I would then call it like so require('icecream.js')(true) from sundaepie.js and require hotfudgesundae.js in the regular fashion from SearchingSolutions.js (since I can't control it), but it wouldn't execute the function when required without passing the brackets to invoke the function.
module.exports = function(isexport) {
if (isexport) {
return "For sundaepie";
} else {
console.log("Executing code in hotfudgesundae.js");
...
}
}
How can I get this to work? If you have any questions go leave a comment ;)
You could use a global variable (yes, that hurts):
// inside the module
if(global.isCold) /*...*/
// before you require it
global.isCold = true

How can I attach an event handler to the process's exit in a native Node.js module?

I'm working on implementing correct memory management for a native Node.js module. I've ran into the problem described in this question:
node.js native addon - destructor of wrapped class doesn't run
The suggested solution is to bind the destructors of native objects to process.on('exit'), however the answer does not contain how to do that in a native module.
I've taken a brief look at the libuv docs as well, but they didn't contain anything useful in this regard, either.
NOTE: I'm not particularly interested in getting the process object, but I tried it that way:
auto globalObj = NanGetCurrentContext()->Global();
auto processObj = ::v8::Handle<::v8::Object>::Cast(globalObj->Get(NanNew<String>("process")));
auto processOnFunc = ::v8::Handle<::v8::Function>::Cast(processObj->Get(NanNew<String>("on")));
Handle<Value> processOnExitArgv[2] = { NanNew<String>("exit"), NanNew<FunctionTemplate>(onProcessExit)->GetFunction() };
processOnFunc->Call(processObj, 2, processOnExitArgv);
The problem then is that I get this message when trying to delete my object:
Assertion `persistent().IsNearDeath()' failed.
I also tried to use std::atexit and got the same assertion error.
So far, the best I could do is collecting stray ObjectWrap instances in an std::set and cleaning up the wrapped objects, but because of the above error, I was unable to clean up the wrappers themselves.
So, how can I do this properly?
I was also getting the "Assertion persistent().IsNearDeath()' failed" message.
There is a node::AtExit() function that runs just before Node.js shuts down - the equivalent of process.on('exit').
Pass a callback function to node::AtExit from within your add-on's init function (or where ever is appropriate).
The function is documented here:
https://nodejs.org/api/addons.html#addons_atexit_hooks
For example:
NAN_MODULE_INIT(my_exports)
{
// other exported stuff here
node::AtExit(my_cleanup);
}
NODE_MODULE(my_module, my_exports) //add-on exports
//call C++ dtors:
void my_cleanup()
{
delete my_object_ptr; //call object dtor, or other stuff that needs to be cleaned up here
}

QtWebKit bridge: call JavaScript functions

I am writing a hybrid application with HTML interface and Python code.
I can access Python functions via a shared object:
pythonPart.py:
class BO(QObject):
def __init__(self, parent=None):
super(BO, self).__init__(parent)
#Slot(str)
def doStuff(self, txt):
print(txt)
bridgeObj = BO()
# init stuff and frame...
frame.addToJavaScriptWindowObject( 'pyBridge', bridgeObj )
frame.evaluateJavaScript('alert("Alert from Python")')
frame.evaluateJavaScript('testMe()')
frame.evaluateJavaScript('alert("Starting test");testMe();alert("Test over")')
jsPart.js:
function testMe() { alert('js function testMe called'); }
pyBridge.doStuff("bla");
testMe();
Calling Python functions from JS works, as does calling testMe from JS. Calling "standard" JS functions like alert from Python works, too.
The last two Python lines won't:
evaluateJavaScript("testMe()") doesn't do anything at all.
The last line executes the first alert and won't continue after that.
EDIT: I already tried having some time.sleep() between loading and calling the evaluateJavaScript and I'm loading the webpage from the local machine.
The most likely problem is that the JavaScript just isn't loaded yet. Adding time.sleep() calls doesn't help for that, those will also block the Qt event loop from continuing, not just your Python code.
Try waiting for the page to have fully loaded instead, for example (using the loadFinished signal:
def onLoad():
frame.evaluateJavaScript('testMe()')
frame.loadFinished.connect(onLoad)
Aditionally, for getting more debug information in situations like this, you might want to implement QtWebKit.QWebPage.javaScriptConsoleMessage.
There are at least two errors in the example code.
Firstly, when you add the object to the javascript window, you call it "pyBridge", but you then try to reference it in the javascript as "bridgeObj". Obviously, this will throw a ReferenceError which will prevent any further execution of the script.
Secondly, the doStuff method is missing a self argument, which will cause a TypeError to be raised by PySide.
Dealing with those two issues should be enough to fix your example code, so long as you make sure that the bridge object is added to the javacsript window before the html is loaded. This step is required if you want to reference the bridge object in top-level javascript code. However, if the bridge object is only ever referenced in function-level code, it can be safely added to the javascript window after the html has loaded.

how should I write my define to work with curl.js?

I'm reading Addy Osmani's excellent blog post about writing AMD modules. I start with a simple chunk of js that I lifted from his post:
define('modTest', [],
// module definition function
function () {
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
}
);
I took out the dependencies on foo and bar. Just want a simple object that logs to the console.
So I save that in /js/modTest.js and then try to load it:
curl(['/js/modTest.js'])
.then(function(mt) {
console.log("Load complete");
console.log("mt:");
console.log(mt);
mt.doStuff()
}, function(ex) {alert(ex.message);})
Result: error: Multiple anonymous defines in URL. OK that didn't work. Tried adding in a namespace: define('myCompany/modTest', [],, same result. Tried adding an empty string in the dependency array, same result.
Also tried curl(['modTest.js'], function(dep){console.log(dep)}); with the same result.
Is the code in Addy's blog post incorrect? Am I doing something wrong? Maybe a bug in curl?
Update 5/24: I ditched curl.js in favor of require.js. Zero odd errors, very little work to change over. I did have to deal with amdefine a bit to get my code running client and server side (one object is in both places, so grunt had to be configured to take care of that). My defines generally look like:
define(->
class AlphaBravo
...
And never have any trouble loading.
You asked curl() to fetch a module called "/js/modTest.js". It found the file and loaded it and found a module named "modTest", so it complained. :) (That error message is horribly wrong, though!)
Here's how you can fix it (pick one):
1) Remove the ID from your define(). The ID is not recommended. It's typically only used by AMD build tools and when declaring modules inside test harnesses.
2) Refer to the module by the ID you gave it in the define(). (Again, the ID is not recommended in most cases.)
curl(['modTest'], doSomething);
3) Map a package (or a path) to the folder with your application's modules. It's not clear to me what that would be from your example since modTest appears to be a stand-alone module. However, if you were to decide to organize your app's files under an "app" package, you packages config might look like this:
packages: [ { name: 'app', location: 'app' } ]
Then, when you have code that relies on the modTest module, you can get to it via an ID of "app/modTest".
curl(['app/modTest'], doSomething);
I hope that helps clear things up!
Fwiw, Addy's example could actually work with the right configuration, but I don't see any configuration in that post (or my eyes missed it). Something like this might work:
packages: [ { name: 'app', location: '.' } ]
-- John
I've just had a similar problem which turned out to be the include order I was using for my other libraries. I'm loading handlebars.js, crossroads.js, jquery and a few other libraries into my project in the traditional way (script tags in head) and found that when I place the curl.js include first, I get this error, but when I include it last, I do not get this error.
My head tag now looks like this:
<script type="text/javascript" src="/js/lib/jquery.js"></script>
<script type="text/javascript" src="/js/lib/signals.js"></script>
<script type="text/javascript" src="/js/lib/crossroads.js"></script>
<script type="text/javascript" src="/js/lib/handlebars.js"></script>
<script type="text/javascript" src="/js/lib/curl.js"></script>
<script type="text/javascript" src="/js/main.js"></script>
You have a problem with your define call. It is NAMED
See AMD spec for full story on how to write defines, but here is what I would expect to see in your js/modTest.js file:
define(/* this is where the difference is */ function () {
// return a value that defines the module export
// (i.e the functionality we want to expose for consumption)
// create your module here
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
}
return myModule;
}
);
Now, the boring explanation:
CurlJS is awesome. In fact, after dealing with both, RequireJS and CurlJS, I would say CurlJS is awesome-er than RequireJS in one category - reliability of script execution ordering. So you are on the right track.
On of the major things that are different about CurlJS is that it uses "find at least one anonymous define per loaded module, else it's error" logic. RequireJS uses a timeout, where it effectively ignores cases where nothing was defined in a given file, but blows up on caught loading / parsing errors.
That difference is what is getting you here. CurlJS expects at least one anonymous (as in NOT-named) define per loaded module. It still handles named defines fine, as expected. The second you move the contents of "js/modTest.js" into inline code, you will have to "name" the define. But, that's another story.

Categories

Resources