
간단한 콘솔 명령어 만들기
- package.json
{
"name": "node-cli",
"version": "0.0.1",
"description": "nodejs cli program",
"main": "index.js",
...
"bin": {
"cli": "./index.js"
},
}
- index.js
#!/usr/bin/env node
console.log('Hello CLI', process.argv);
`#!/usr/bin/env node`는 맥과 리눅스에서 /usr/bin/env에 등록된 node 명령어로 이 파일을 실행하라는 의미다.
process.argv는 실행한 명령어의 인자들을 볼 수 있다.
- 해당 모듈 전역 설치
npx i -g
- 모듈 실행
npx cli
CLI로 입력받기
- index.js
#!/usr/bin/env node
// console.log("Hello CLI", process.argv);
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
console.clear();
const answerCallback = (answer) => {
if (answer === "y") {
console.log("감사링~");
} else if (answer === "n") {
console.log("아쉬운거죵");
} else {
console.clear();
console.log("y 또는 n만 입력하세요.");
rl.question("예제가 재밌습니까? (y/n)", answerCallback);
}
rl.close();
};
rl.question("예제가 재밌습니까? (y/n)", answerCallback);
`readline`은 노드의 내장 모듈 input과 output을 콘솔 기본 입출력 (stdin, stdout)으로 설정한다.
`console.clear` 명령어는 콘솔창을 내용을 지운다.
`rl.question`의 명령어로 출력와 입력을 받는다.
- 템플릿을 만드는 template.js
#!/usr/bin/env node
const fs = require("fs");
const path = require("path");
const readline = require("readline");
// npx cli html main .
let li;
let type = process.argv[2];
let name = process.argv[3];
let directory = process.argv[4] || ".";
const htmlTemplate = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Template</title>
</head>
<body>
<h1>Hello</h1>
<p>CLI</p>
</body>
</html>
`;
const routerTemplate = `
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
try {
res.send('ok');
} catch (error) {
console.error(error);
next(error);
}
});
module.exports = router;
`;
const exist = (dir) => {
// 폴더 존제 확인 함수
try {
fs.accessSync(
dir,
fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK
);
return true;
} catch (e) {
return false;
}
};
const mkdirp = (dir) => {
// 경로 생성 함수
const dirname = path
.relative(".", path.normalize(dir))
.split(path.sep)
.filter((p) => !!p);
dirname.forEach((d, idx) => {
const pathBuilder = dirname.slice(0, idx + 1).join(path.sep);
if (!exist(pathBuilder)) {
fs.mkdirSync(pathBuilder);
}
});
};
const makeTemplate = () => {
mkdirp(directory);
if (type === "html") {
const pathToFile = path.join(directory, `${name}.html`);
if (exist(pathToFile)) {
console.error("이미 해당 파일이 존재합니다.");
} else {
fs.writeFileSync(pathToFile, htmlTemplate);
console.log(pathToFile, " 생성 완료");
}
} else if (type === "express-router") {
const pathToFile = path.join(directory, `${name}.js`);
if (exist(pathToFile)) {
console.error("이미 해당 파일이 존재합니다.");
} else {
fs.writeFileSync(pathToFile, routerTemplate);
console.log(pathToFile, " 생성 완료");
}
} else {
console.error("html 또는 express-router 둘 중 하나를 입력하세요.");
}
};
const dirAnswer = (answer) => {
directory = answer?.trim() || ".";
rl.close();
makeTemplate();
};
const nameAnswer = (answer) => {
if (!answer || !answer.trim()) {
console.clear();
console.log("name을 반드시 입력하셔야 합니다.");
return rl.question("파일명을 설정하세요.", nameAnswer);
}
name = answer;
return rl.question(
"저장할 경로를 설정하세요.(설정하지 않으면 현재경로)",
dirAnswer
);
};
const typeAnswer = (answer) => {
if (answer !== "html" && answer !== "express-router") {
console.clear();
console.log("html 또는 express-router만 지원됩니다.");
return rl.question("어떤 템플릿이 필요하십니까?", typeAnswer);
}
type = answer;
return rl.question("파일명을 설정하세요", nameAnswer);
};
const program = () => {
if (!type || !name) {
console.error("사용 방법: cli html|express-router 파일명 [생성 경로]");
rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
console.clear();
rl.question("어떤 템플릿이 필요하십니까?", typeAnswer);
} else {
makeTemplate();
}
};
program();
Commander, Inquirer 모듈로 CLI 프로그램 만들기
- command.js <- commander 적용
#!/usr/bin/env node
const { program } = require("commander");
const fs = require("fs");
const path = require("path");
...
program.version("0.0.1", "-v, --version").name("cli");
program
.command("template <type>")
.usage("<type> --filename [filename] --path [path]")
.description("템플릿을 생성합니다.")
.alias("tmpl")
.option("-f --filename [filename]", "파일명을 입력하세요", "index")
.option("-d --directory [path]", "생성 경로를 입력하세요", ".")
.action((type, options, command) => {
console.log(type, options.filename, options.directory);
makeTemplate(type, options.filename, options.directory);
});
program.action((options, command) => {
if (command.args.length !== 0) {
console.log("해당 명령어를 찾을 수 없습니다.");
program.help();
} else {
...
}
});
program.parse(process.argv);
`version`: 프로그램의 버전을 설정한다.(-v --version)
`name`: 명령어의 이름을 등록한다.
`usage`: 명령어의 사용법을 적는다(-h, --help)
`command`: 명령어를 설정한다. <>는 필수라는 의미이고 []는 선택사항이다.
`description`: 명령어에 대한 설명을 설정한다.
`alias`: 명령어의 별칭을 설정한다.
`option`: 명령어에 대한 부가적인 옵션을 설정한다. 첫번째 인수는 명령어 옵션이고, 두번째 인수는 옵션에 대한 설명, 세번째 인수는 기본 값이다.
`action`: 명령어의 실제 동작을 정의하는 메서드다. 필수 옵션을 제외한 부가전인 옵션은 options 객체에 들어있다. command 객체에는 명령어에 대한 내용이 담겨있다.
`help`: 해당 모듈의 설명서를 보여주는 매서드다.
`parse`: program 객체의 마지막에 붙이는 매서드다. 인수를 받아 파싱한다.
- commander.js <- inquirer 적용
#!/usr/bin/env node
const { program } = require("commander");
const fs = require("fs");
const path = require("path");
const inquirer = require("inquirer");
...
program.action((options, command) => {
if (command.args.length !== 0) {
console.log("해당 명령어를 찾을 수 없습니다.");
program.help();
} else {
inquirer
.prompt([
{
type: "list",
name: "type",
message: "템플릿 종류를 선택하세요.",
choices: ["html", "express-router"],
},
{
type: "input",
name: "name",
message: "파일의 이름을 입력하세요.",
default: "index",
},
{
type: "input",
name: "directory",
message: "파일이 위치할 폴더의 경로를 입력하세요,",
default: ".",
},
{
type: "confrirm",
name: "confirm",
message: "생성하시겠습니까?",
},
])
.then((answers) => {
if (answers.confirm) {
makeTemplate(answers.type, answers.name, answers.directory);
console.log(chalk.hex("#123fff")("터미널을 종료합니다."));
}
});
}
});
program.parse(process.argv);
`type`: 질문의 종류
`name`: 질문의 이름
`message`: 사용자에게 보이는 문자열
`choices`: 선택지
`default`: 기본값
- commander.js <- chalk 적용
#!/usr/bin/env node
const { program } = require("commander");
const fs = require("fs");
const path = require("path");
const inquirer = require("inquirer");
const chalk = require("chalk");
const htmlTemplate = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Template</title>
</head>
<body>
<h1>Hello</h1>
<p>CLI</p>
</body>
</html>
`;
const routerTemplate = `
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
try {
res.send('ok');
} catch (error) {
console.error(error);
next(error);
}
});
module.exports = router;
`;
const exist = (dir) => {
// 폴더 존제 확인 함수
try {
fs.accessSync(
dir,
fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK
);
return true;
} catch (e) {
return false;
}
};
const mkdirp = (dir) => {
// 경로 생성 함수
const dirname = path
.relative(".", path.normalize(dir))
.split(path.sep)
.filter((p) => !!p);
dirname.forEach((d, idx) => {
const pathBuilder = dirname.slice(0, idx + 1).join(path.sep);
if (!exist(pathBuilder)) {
fs.mkdirSync(pathBuilder);
}
});
};
const makeTemplate = (type, name, directory) => {
mkdirp(directory);
if (type === "html") {
const pathToFile = path.join(directory, `${name}.html`);
if (exist(pathToFile)) {
console.error(chalk.bold.red("이미 해당 파일이 존재합니다."));
} else {
fs.writeFileSync(pathToFile, htmlTemplate);
console.log(chalk.bold.red(pathToFile, " 생성 완료"));
}
} else if (type === "express-router") {
const pathToFile = path.join(directory, `${name}.js`);
if (exist(pathToFile)) {
console.error(chalk.bold.red("이미 해당 파일이 존재합니다."));
} else {
fs.writeFileSync(pathToFile, routerTemplate);
console.log(chalk.green(pathToFile, " 생성 완료"));
}
} else {
console.error(
chalk.bold.red,
"html 또는 express-router 둘 중 하나를 입력하세요."
);
}
};
program.version("0.0.1", "-v, --version").name("cli");
program
.command("template <type>")
.usage("<type> --filename [filename] --path [path]")
.description("템플릿을 생성합니다.")
.alias("tmpl")
.option("-f --filename [filename]", "파일명을 입력하세요", "index")
.option("-d --directory [path]", "생성 경로를 입력하세요", ".")
.action((type, options, command) => {
console.log(type, options.filename, options.directory);
makeTemplate(type, options.filename, options.directory);
});
program.action((options, command) => {
if (command.args.length !== 0) {
console.log("해당 명령어를 찾을 수 없습니다.");
program.help();
} else {
inquirer
.prompt([
{
type: "list",
name: "type",
message: "템플릿 종류를 선택하세요.",
choices: ["html", "express-router"],
},
{
type: "input",
name: "name",
message: "파일의 이름을 입력하세요.",
default: "index",
},
{
type: "input",
name: "directory",
message: "파일이 위치할 폴더의 경로를 입력하세요,",
default: ".",
},
{
type: "confrirm",
name: "confirm",
message: "생성하시겠습니까?",
},
])
.then((answers) => {
if (answers.confirm) {
makeTemplate(answers.type, answers.name, answers.directory);
console.log(chalk.hex("#123fff")("터미널을 종료합니다."));
}
});
}
});
program.parse(process.argv);
참고
Node.js 교과서 : 네이버 도서
네이버 도서 상세정보를 제공합니다.
search.shopping.naver.com
[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지 강의 | 제로초(조현영) - 인프런
제로초(조현영) | 노드가 무엇인지부터, 자바스크립트 최신 문법, 노드의 API, npm, 모듈 시스템, 데이터베이스, 테스팅 등을 배우고 5가지 실전 예제로 프로젝트를 만들어 나갑니다. 클라우드에 서
www.inflearn.com
'Node.js' 카테고리의 다른 글
[Node.js 교과서] 섹션 16 - 서버리스 노드 개발 (0) | 2025.01.11 |
---|---|
[Node.js 교과서]섹션 15 - AWS에 배포해보기 (0) | 2025.01.07 |
[Node.js 교과서] 섹션 13- 실시간 경매 시스템 만들기 (0) | 2024.12.13 |
[Node.js 교과서] 섹션 12 - 웹 소켓으로 실시간 데이터 전송하기 (0) | 2024.12.08 |
[Node.js 교과서] 섹션 11 - 노드 서비스 테스트 하기 (3) | 2024.12.05 |