# A node CLI to start new projects

I was annoyed to manually start new projects each time so I made a Node CLI that automate the process. I'm really not comfortable yet with node, so I wanted some advice. It works but I don't know if I did it the node way or not.

Basically the code under here is my whole application. The file structure is like so:

- app.js
- seed


It's not really complicated. What I do in the app is copy the seed and change the project name in package.json. The seed is a template project, with nothing in it beside a starter-repo. I could have upload it to git but this is more fun.

#!/usr/bin/env node

const spawn = require('child_process').spawn;
const fs = require("fs");
const path = require('path');
const through2 = require('through2');
const copydir = require('copy-dir');

const name = process.argv[2] || "unnamed project";
const projPath = path.join(process.cwd(), name);
// path to my seed project
const seed = path.join(__dirname, "seed");

if (!fs.existsSync(name)) {
fs.mkdirSync(name);
} else {
throw new Error(directory ${name} already exist); } copydir(seed, path.join(process.cwd(), name), function(err) { if (err) { console.log(err); process.exit(1); } const package = path.join(projPath, "package.json"); // in my seed project package.json, I have name: "-your-app-name-here-" replaceInFile(package, "-your-app-name-here-", name, onCopyDone); }); function onCopyDone(err) { if (!err) install(projPath) else console.log(err) } function replaceInFile(someFile, rep, by, cb) { fs.readFile(someFile, 'utf8', function(err, data) { if (err) { return console.log(err); } let result = data.replace(rep, by); fs.writeFile(someFile, result, 'utf8', cb); }); } function install(where) { console.log('installing dependencies...') const i = spawn('npm', ['install', '--prefix', where]); i.stdout.on('data', (data) => { console.log(stdout:${data});
});
}


Primarily what I'd like to know is how I can do it more the Node way, if that makes sense.

• Do you use ECMAScript 5 or 6 for Node? – Phrancis Mar 10 '17 at 2:18
• @Phrancis well, the first couple of things I tried to do I used typescript. Then when trying in pure js I had trouble using imports, so I decided to use the require. To answer you question ES6. I assume you asked that because of my use of require with const. – Ced Mar 10 '17 at 2:29
• Yup, I added the ES6 tag. That will influence the type of answer you're likely to get, since if you can use new ES6 things then there is usually more that can be improved. :-) – Phrancis Mar 10 '17 at 3:04
• You should check out yeoman.io – konijn Mar 10 '17 at 13:02

### Avoiding else

If you can avoid else then it can simplify indentation. For example:

if (!fs.existsSync(name)) {
fs.mkdirSync(name);
} else {
throw new Error(directory ${name} already exist); }  The error can be thrown the error if the name exists, but if not just go ahead with the call to fs.mkdirSync(): if (fs.existsSync(name)) { throw new Error(directory${name} already exist);
}
fs.mkdirSync(name);


In some cases you may have to manually return or exit if the statement inside the first conditional doesn't return early or terminate the process - e.g. inside onCopyDone().

### Use const instead of let when appropriate

It is wise to get in the habit of using const for any value that doesn't get re-assigned. Then if you need to have a variable that changes, switch to using let. This affects variables like result in the callback inside replaceInFile().

### Arrow functions

The parentheses are not necessary on arrow functions with only one argument. Also, a single line doesn't need to have brackets - while this would lead to the return value of the statement getting returned, it shouldn't matter in most cases - so this:

i.stdout.on('data', (data) => {
console.log(stdout: ${data}); });  can be simplified to: i.stdout.on('data', data => console.log(stdout:${data}));