이 글은 zerocho님의 Node.js 강의 영상을 참고하여 진행하였습니다. 아래 예제들과 설명은 이 강의에 출처가 있음을 밝힙니다.(https://osam.kr/learn/lecture/15158/%EC%9E%90%EC%9C%A0%EA%B3%BC%EC%A0%95-web%EB%B6%84%EC%95%BC-node-js-%EA%B8%B0%EB%B3%B8%EB%B6%80%ED%84%B0-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%A4%EC%8A%B5%EA%B9%8C%EC%A7%80-1/lesson/704252/72-cli-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EB%A7%8C%EB%93%A4%EA%B8%B0-cli-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-1)
이번에 node.js를 이용해 웹 서비스를 만들며 노드에 대해 더 공부해보고 싶어졌다. 그래서 CLI (Command Line Interface) 프로그램을 한 번 만들어보려한다. 강의를 따라가며 구현에 필요한 명령어들을 알려주는 프로그램을 만들어보겠다.
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);
readline의 기본적인 사용법이다.
터미널(프롬프트) 창에서 프로그램과 사용자가 입출력을 통한 상호작용 할 수 있도록 도와주는 패키지이다.
readline.createInterface({
input: process.stdin,
output: process.stdout,
});
위 코드를 통해 입력과 출력을 받으며,
readline.question('message', function); 을 통해 입력을 받고 그 값을 매개변수로 넘길 수 있다.
console.clear() 은 말 그대로 콘솔창을 깨끗하게 만들어준다.
다음은 이를 이용한 프로그램 예제입니다.
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 CLI!</h1>
</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 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 exist = () {
try {
fs.accessSync(dir, fs.constants.F_OK | fs.constants.R_OK | fs.constants.W_OK);
return true;
} catch (e) {
return false;
}
};
const makeTemplate = () => {
makdirp(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();
};
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();
처음보는 코드들이 있는건 아니라 이해가 어렵지는 않았다. html과 express-router 템플릿을 생성해주는 코드인데, CLI 프로그램의 기본적인 흐름을 볼 수 있는 것 같다.
하지만 코드가 너무 복잡하다. 이쁘게 보기 위해선 역시 프레임워크가 필요하다.
Commander 프레임워크 사용하기
Commander 는 CLI 프로그램을 만들때 유용한 npm 패키지이다.
npm install 명령어를 통해 설치하고 바로 사용해보겠다.
inquirer : 대화형 프로그램을 만드는 패키지
chalk : console에 색을 입혀주는 패키지
$ npm i commander inquirer chalk
yargs나 meow 같은 패키지도 있지만 우선은 commander만 해보자.
const program = require('commander');
program
.version('0.0.1', '-v, --version') // 버젼
.usage('[options]'); // 설명서(commander는 설명서를 자동생성해줌)
program
.command('template <type>')
.usage('--name <name> -- path [path]')
.description('템플릿을 생성합니다.')
.alias('tmpl')
.option('-n, --name <name>', '파일명을 입력하세요', 'index')
.option('-d, --directory [path]', '생성 경로를 입력하세요', '.') // 현재경로
.action((type, options) => {
console.log(type, options.name, options.directory);
});
program
.command('*', { noHelp: true }) // 도움말을 띄우지 말고,
.action(() => {
console.log('해당 명령어를 찾을 수 없습니다.');
program.help();
});
program.parse(process.argv);
if (!triggered) {
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)('터미널을 종료합니다.'));
}
});
}
// * ===================================================
// * 기호 설명
// * -- 옵션 - 단축옵션
// * <필수로 넣어야 하는 것> [선택적으로 넣어도 되는 것]
// * *: 와일드카드 (나머지 처리)
// *
// * type: 프롬프트 종류
// * name: 질문명
// * message: 메시지
// * choices: 선택지
// * default: 기본값
// * ====================================================
위 코드처럼 commander를 이용하면 프로그램의 흐름을 파악하기 쉽고, 직관적으로 만들 수 있다. 한 번 익숙해지면 원래대로 돌아가기 어려워진다고 하던데 정말 맞는 말인 것 같다. commander의 몇 가지 속성들을 살펴보면,
.command : 실행 명령어
.version : 프로그램의 버젼
.usage : 사용법 ( 자동으로 생성됨 )
.description : 해당 명령어 설명
.alias : 별명. 이 프로그램을 실행하는 명령어의 약어
.option : 기능 명령어
.action : 실행 내용
이 정도가 있겠다.
아래 쪽 코드가 inquirer을 이용해 프로그램을 짠 것이다.
이 프로그램이 어떻게 진행되는지 한 눈에 들어와서 파악하기 좋다.
중간중간 콘솔로그에 있는 속성들은 chalk를 이용해 색을 입힌 것이다. green, red 처럼 색상을 입력해도 작동하고, rgb 코드를 입력해도 작동한다. 다만 해당 프롬프트에서 글자색을 지원해야 한다는 점.
이 외에 다른건 공식문서를 참고해보며 만들어보면 되겠다.
다음 글에서는 직접 프로그램을 만들어보며 정리해보겠다.
'개발 기록' 카테고리의 다른 글
구글 클라우드 플랫폼을 이용하여 리액트 프로젝트 호스팅하기 (nginX) #2 (0) | 2020.09.11 |
---|---|
구글 클라우드 플랫폼을 이용하여 리액트 프로젝트 호스팅하기 (nginX) #1 (0) | 2020.09.10 |
게임 아이템 분석 사이트를 서비스했어요 - 메이플 추가옵션 분석기를 개발하며 (0) | 2020.03.09 |
Node.js 로 CLI 프로그램 만들기 - 2. 직접 만들어보기 (0) | 2020.03.02 |
뭐 먹을까요 (식사 메뉴 골라주는 어플리케이션) (0) | 2018.05.09 |
댓글