CLI(Command Line Interface - 명령줄 인터페이스) : 콘솔 창을 통해 프로그램을 수행하는 환경
ex) 리눅스의 셸, 브라우저의 콘솔, 명령 프롬프트
GUI(Graphic User Interface - 그래픽 사용자 인터페이스) : 그래픽을 통해 프로그램을 수행하는 환경
ex) 윈도나 맥 운영체제, 웹 어플리케이션
콘솔 명령어 : 콘솔에서 입력하여 어떠한 동작을 수행하는 문장
ex) node, npm, nodemon
1) node-cli 폴더 생성 후, package.json 생성
{
"name": "node-cli",
"version": "0.0.1",
"description": "nodejs cli program",
"main": "index.js",
"author": "ZeroCho",
"license": "ISC",
"bin": {
"cli": "./index.js"
}
}
2) index.js 생성
#!/usr/bin/env node
console.log("Hello CLI");
3) 콘솔에서 현재 패키지 전역 설치
npm i -g
4) 콘솔에 cli 입력하여 실행
cli
5) index.js 코드 수정
#!/usr/bin/env node
console.log("Hello CLI", process.argv);
6) 콘솔에 명령어 입력
cli one two three four
[사용자로부터 입력 받기]
7) index.js 코드 수정
#!/usr/bin/env node
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question("예제가 재미있습니까? (y/n) ", (answer) => {
if (answer === "y") {
console.log("감사합니다!");
} else if (answer === "n") {
console.log("죄송합니다!");
} else {
console.log("y 또는 n만 입력하세요.");
}
rl.close();
});
8) 프로그램 실행
[코드 리팩토링]
9) index.js 코드 수정
#!/usr/bin/env node
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
console.clear();
const answerCallback = (answer) => {
if (answer === "y") {
console.log("감사합니다!");
rl.close();
} else if (answer === "n") {
console.log("죄송합니다!");
rl.close();
} else {
console.clear();
console.log("y 또는 n만 입력하세요.");
rl.question("예제가 재미있습니까? (y/n) ", answerCallback);
}
};
rl.question("예제가 재미있습니까? (y/n) ", answerCallback);
10) 프로그램 실행
[html 또는 익스프레스 라우터 파일 템플릿 만들어주는 예제]
11) public, html 폴더 만들기
12) template.js 파일 생성
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const readline = require('readline');
let rl;
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 && 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) {
rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
console.clear();
rl.question('어떤 템플릿이 필요하십니까? ', typeAnswer);
} else {
makeTemplate();
}
};
program(); // 프로그램 실행부
13) package.json 코드 수정
{
...
"bin": {
"cli": "./template.js"
}
}
14) 전역 설치
npm i -g
15) 프로그램 실행
commander 라이브러리 : npm에서 제공하는 CLI 프로그램을 위한 라이브러리
inquirer 패키지 : CLI 프로그램과 사용자 간의 상호작용을 돕는 패키지
chalk 패키지 : 콘솔 텍스트에 스타일을 추가하는 패키지
1) commander, inquirer, chalk 설치
npm i commander inquirer chalk
2) command.js 파일 생성 (commander 사용법 익히기)
[program 객체의 메서드]
- version(버전, 버전을 보여줄 옵션) : 프로그램의 버전을 설정
- usage(명령어 사용법) : 명령어의 사용법 설정
- command(명령어) : 명령어를 설정
- description(명령어 설명) : 명령어에 대한 설명을 설정
- alias(명령어 별칭) : 명령어의 별칭 설정
- option(옵션 명령어, 옵션에 대한 설명, 옵션 기본값) : 명령어에 대한 부가적인 옵션을 설정
- action(함수) : 명령어에 대한 실제 동작을 정의
- help : 설명서를 보여주는 옵션
- parse(process.argv) : program 객체의 마지막에 붙이는 메서드로, process.env를 인수로 받아서 명령어와 옵션을 파싱
#!/usr/bin/env node
const { program } = require("commander");
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) => {
console.log(type, options.filename, options.directory);
});
program.command("*", { noHelp: true }).action(() => {
console.log("해당 명령어를 찾을 수 없습니다.");
program.help();
});
program.parse(process.argv);
3) package.json 코드 수정
{
...
"bin": {
"cli": "./command.js"
},
}
4) 전역 설치
npm i -g
5) 프로그램 실행
6) command.js 파일 수정
#!/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 chart="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.green(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) => {
makeTemplate(type, options.filename, options.directory);
});
program
.action((cmd, args) => {
if (args) {
console.log(chalk.bold.red('해당 명령어를 찾을 수 없습니다.'));
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: 'confirm',
name: 'confirm',
message: '생성하시겠습니까?',
}])
.then((answers) => {
if (answers.confirm) {
makeTemplate(answers.type, answers.name, answers.directory);
console.log(chalk.rgb(128, 128, 128)('터미널을 종료합니다.'));
}
});
}
})
.parse(process.argv);
[inquirer 객체의 prompt 메서드 질문 객체 속성]
- type : 질문의 종류 / input(평범한 답변), list(다중택일), confirm(Yes 또는 No)
- name : 질문의 이름 -> 답변 객체가 속성명으로 질문의 이름을, 속성값으로 질문의 답을 가지게 됨
- message : 사용자에게 표시되는 문자열, 실제 질문을 적으면 됨
- choices : type이 checkbox, list인 경우 선택지를 넣는 곳, 배열로 넣으면 됨
- default : 답을 적지 않았을 경우 적용되는 기본값
7) 프로그램 실행
[Node.js]16장 서버리스 노드 개발 (0) | 2022.01.31 |
---|---|
[Node.js] 15장 AWS와 GCP로 배포하기 (0) | 2022.01.24 |
[Node.js] 13장 실시간 경매 시스템 만들기 (0) | 2022.01.17 |
[Node.js] 12장(2) 미들웨어와 소켓 연결하기 (0) | 2022.01.10 |
[Node.js] 12장 웹소켓으로 실시간 데이터 전송하기(1) (0) | 2022.01.06 |