How to add async callbacks in node to a function call? - node.js

Question is too broad / unclear. Anyone interested in this answer would be better served by visiting: Creating Callbacks for required modules in node.js
Basically I have included a CLI package in my node application. I need the CLI to spin up a new project (this entails creating a folder for the project). After the project folder is created, I need to create some files in the folder (using fs writeFile). The problem is right now, my writeFile function executes BEFORE the folder is created by the CLI package (This is detected by my console.log. This brings me to main main question.
Can I add an async callback function to the CLI.new without modifying the package I included?
FoundationCLI.new(null, {
framework: 'sites', // 'apps' or 'emails' also
template: 'basic', // 'advanced' also
name: projectName,
directory: $scope.settings.path.join("")
});
try{
if (!fs.existsSync(path)){
console.log("DIRECTORY NOT THERE!!!!!");
}
fs.writeFileSync(correctedPath, JSON.stringify(project) , 'utf-8');
} catch(err) {
throw err;
}
It uses foundation-cli. The new command executes the following async series. I'd love to add a callback to the package - still not quite sure how.
async.series(tasks, finish);
Anyone interested in this can probably get mileage out of:
Creating Callbacks for required modules in node.js

The code for the new command seem to be available on https://github.com/zurb/foundation-cli/blob/master/lib/commands/new.js
this code was not written to allow programmatic usage of the new command (it uses console.log everywhere) and does not call any callback when the work is finished.
so no there is no way to use this package to do what you are looking for. Either patch the package or find another way to do what you want to achieve.

Related

Understanding node modules

How do I work with node modules?
tldr; How do I look at a node module I've installed and know where to go and what I'm looking for
If I use npm i googleapis for example, it downloads the node module for Googles APIs but how do I browse the module and work out what's useful for me?
To try and eliminate any ambiguity from the question, I'll use this use case.
I'm developing a Discord bot and I want to add statistics to one of
the commands. Here is the supplied code from Google:
<script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for youtube.channels.list
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/code-samples#javascript
*/
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/youtube.readonly"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function loadClient() {
gapi.client.setApiKey("YOUR_API_KEY");
return gapi.client.load("https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded and sign-in is complete before calling this method.
function execute() {
return gapi.client.youtube.channels.list({
"part": [
"snippet,contentDetails,statistics"
],
"id": [
"UC_x5XG1OV2P6uZZ5FSM9Ttw"
]
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client:auth2", function() {
gapi.auth2.init({client_id: "YOUR_CLIENT_ID"});
});
</script>
<button onclick="authenticate().then(loadClient)">authorize and load</button>
<button onclick="execute()">execute</button>
Now Google offers a supported library which means I can replace the external script tags and import from the node package, specifically the parts I need.
So I'll need to import or require whatever gives me access to things like:
gapi.auth2.getAuthInstance
gapi.client.setApiKey
gapi.client.youtube.channels.list
For someone who is new to nodejs, instead of copy and pasting from every piece of documentation and hoping it works, how do I comfortably look at a node package and find the things I need and can use?
Edit #1
I think my use of the google apis case threw off the direction of the question and changed the scope of what I asked so I'm going to correct the best I can.
The assumption should be made that there is no documentation on the package whether it's so poorly written, doesn't exist at all or the documentation is down for an extended period of time during a time sensitive development.
At that point, is there any possible way to look at the node_modules folder, the specific package that needs to be worked with and work out what's going on? Is there any way to look at the structure of a package and recognise "well most likely what I need is in this folder or file"
That's what documentation is for.
When someone writes an API for a package; to make things clearer for the consumer, he should document the exported functions well enough.
The best way to get the documentations for node packages is to search for the package at www.npmjs.com .
For google apis you can go to that page here to see the "get started" and some examples. And you can go here to see the full detailed APIs of that package.
Answering Edit #1
Well, in that case, it could be a difficult task, depends on the how structured and organized the package is.
Since we are talking about nodejs, you should look for the package.json file and search for the path of the main file "main": "<PATH HERE>".
Then, you can go to that main file and try to locate what exactly is being exported. You can search for module.exports or the export keyword.
Everything that is explicitly exported is intended to be used as an API.
I'm not familiar with any other way other than go deeper in the package's files and identify what exactly is being exported.

Best way to copy a directory from an external drive to a local folder with electronjs?

Just wondering if anyone has ever attempted to copy a directory from an external drive (connected via USB) to a local folder.
I am using ElectronJS so I can use my JavaScript, HTML/CSS skills to create a desktop application without utilising a C language. (i.e. C# or C++) With ElectronJS there's a lot less to worry about.
Here is the list of things I've tried so far:
basic fs.copyFile (using copyFile intially and will then loop round the directory to copy all files)
var fs = require('fs');
window.test = () => {
fs.moveSync("targetFile","destDir", function(err) {
if(err){
console.log(err);
}else{
console.log("copy complete")
}
});
}
fs.moveSync is not a function even though Visual Studio Code brought up moveSync as a suggestion when I entered fs. (ctrl + space)
using child_process functions to copy files using the command line.
Code is:
var process = require('child_process')
window.test = function(){
process.exec('ipconfig', function(err, stdout, stderr){
if(err){
console.log(err);
}else{
console.log(stdout)
}
})
}
Then bundled with browserify. Bundle.js is then imported into the html file and the test function is called on the click of a button. I'm aware the command is ipconfig for now, this was merely used to see if a command could be executed. It appears it could because I was getting process.exec is not defined.
use the node-hid node module to read and trasfer data from the external drive.
The exposed functions within this module were also reported as being undefined. And I thought about the use case longer I thought a simple copy process would suffice because external drive can be accessed like any other folder in the file explorer.
Unfortunately, all of the above have failed and I've spent the most part of the day looking for alternative modules and/or solutions.
Thanks in advance because any help to achieve this would be much appreciated.
Thanks
Patrick
The npm package fs-extra should solve your problem.
It has the move function, which
Moves a file or directory, even across devices
Ended up adding this to my preload.js for:
window.require = require;
It will work for now but is due to be depreciated.
I'll use this for now and make other updates when I have to.

Retrieve file contents during Gatsby build

I need to pull in the contents of a program source file for display in a page generated by Gatsby. I've got everything wired up to the point where I should be able to call
// my-fancy-template.tsx
import { readFileSync } from "fs";
// ...
const fileContents = readFileSync("./my/relative/file/path.cs");
However, on running either gatsby develop or gatsby build, I'm getting the following error
This dependency was not found:
⠀
* fs in ./src/templates/my-fancy-template.tsx
⠀
To install it, you can run: npm install --save fs
However, all the documentation would suggest that this module is native to Node unless it is being run on the browser. I'm not overly familiar with Node yet, but given that gatsby build also fails (this command does not even start a local server), I'd be a little surprised if this was the problem.
I even tried this from a new test site (gatsby new test) to the same effect.
I found this in the sidebar and gave that a shot, but it appears it just declared that fs was available; it didn't actually provide fs.
It then struck me that while Gatsby creates the pages at build-time, it may not render those pages until they're needed. This may be a faulty assessment, but it ultimately led to the solution I needed:
You'll need to add the file contents to a field on File (assuming you're using gatsby-source-filesystem) during exports.onCreateNode in gatsby-node.js. You can do this via the usual means:
if (node.internal.type === `File`) {
fs.readFile(node.absolutePath, undefined, (_err, buf) => {
createNodeField({ node, name: `contents`, value: buf.toString()});
});
}
You can then access this field in your query inside my-fancy-template.tsx:
{
allFile {
nodes {
fields { content }
}
}
}
From there, you're free to use fields.content inside each element of allFile.nodes. (This of course also applies to file query methods.)
Naturally, I'd be ecstatic if someone has a more elegant solution :-)

How to use properly promises in node.js project using classes?

(solution at the bottom)Project construction
I am converting a 'simple' node.js project into full object project node.js. I have found ressources to better organize my files but i still have a problem with classes. I have done php project in object, but the node JS structure seems to be particular.
I consulted :
Node Modular Architecture
How to correctly modularize a node.js project?
For what I understand :
app.js is my router from where I will define what controller I need to respond to the client request.
/routes is where I have my controllers where I instantiate my objects and use their methods.
project organization
My classes are in a folder at the root but I could move it to the public/javascript folder. My problem is about to confine application tier code in the classes that are supposed to access the database.
For exemple, only the class User has a method to update the user name in the database. So in my controlers (/routes) I dont want any sql queries (using sequelize by the way).
I don't know how to do
I tried to do a promise in the controller in which I call the class's method who does the query and return the result.
var user = new User();
var users = new Promise(function(resolve, reject) {
user.select();
});
Promise.all([users]).then(function(values){
console.log(values);
}
console.log(users);
)
In my class I do
models.user.findAll({
attributes: ['user_login','user_points','user_id']
}).then(
users => {
resolve(users);
}
)
Here as expected, resolve is not define. But if I put the resolve just after I call the class method like this:
var users = new Promise(function(resolve, reject) {
user.select();
resolve(result);
});
result is not defined and it will resolve without waiting for the query to be done.
Questions
As I am not experimented and dont find any detailed or recent topic on this subject I don't have any clue on how to proceed.
My first question is : does the problem could come from files organization (or more generaly is mine a usual/good practice).
My second question is how do I handle this type of structure with classes and node.js so my exemple should work.
Thank you for your help.
I will add that since I dont find recent topic on this subject I am verry interested in making a step by step guide to build a full object project in node.js with app/routes/classes and ES6 js. The objective is to better understand it and give it to my supervisor so he can correct it and use it for future recruits and publish it.
Solution
Thanks to #estus, I now unerstand that you can store a Promise in a variable.
It allow me to use a .then on this variable.
var result = a.select();
result.then(function(result) {
console.log('my result : ', result);
});
In the class you only return the result as you dont want to resolve the Sequelize promise :
users => {
return users;
}

using streamlinejs with nodejs express framework

I am new to the 'nodejs' world.So wanting to explore the various technologies,frameworks involved i am building a simple user posts system(users posting something everybody else seeing the posts) backed by redis.I am using express framework which is recommended by most tutorials.But i have some difficulty in gettting data from the redis server i need to do 3 queries from the redis server to display the posts.In which case have to use neested callback after each redis call.So i wanted to use streamline.js to simplify the callbacks.But i am unable to get it to work even after i used npm install streamline -g and require('streamline').register(); before calling
var keys=['comments','timestamp','id'];
var posts=[];
for(var key in keys){
var post=client.sort("posts",'by','nosort',"get","POST:*->"+keys[key],_);
posts.push(post);
}
i get the error ReferenceError: _ is not defined.
Please point me in the right direction or point to any resources i might have missed.
The require('streamline').register() call should be in the file that starts your application (with a .js extension). The streamline code should be in another file with a ._js extension, which is required by the main script.
Streamline only allows you to have async calls (calls with _ argument) at the top level in a main script. Here, your streamline code is in a module required by the main script. So you need to put it inside a function. Something like:
exports.myFunction = function(_) {
var keys=['comments','timestamp','id'];
var posts=[];
for(var key in keys){
var post=client.sort("posts",'by','nosort',"get","POST:*->"+keys[key],_);
posts.push(post);
}
}
This is because require is synchronous. So you cannot put asynchronous code at the top level of a script which is required by another script.

Resources