์์
ํ๋ ํ๊ฒฝ์ด ์ด๋๊ฑด ์์ฃผ ์ฌ์ฉํ๊ฑฐ๋, ํ๊ฒฝ์ค์ ํ๋๋ฐ ์ค๋๊ฑธ๋ฆฌ๋ ์ฝ๋๋ค์ด ์กด์ฌํ๋ค. ๋์ ๊ฒฝ์ฐ๋ ์นํฉ์ด ๊ทธ๋ฌ๋ค.
ํ๋์ ํ๋ก์ ํธ๋ฅผ ์์ํ ๋ ํ๋ฒ ์ค์ ํ๋ฉด ๊ทธ์ธ์๋ ๋ณ๊ฒฝํ์ง ์๋ ๋ถ๋ถ์ด์ง๋ง, ๊ฐ๋จํ๊ฒ JS๋ TS ์ฝ๋๋ฅผ ์์ฑํด์ ๋๋ ค๋ณด๊ณ ์ถ์๋ฐ ํฌ๋กฌ๊ฐ๋ฐ์๋๊ตฌ ์ฝ์์ฐฝ์์๋ ํ๊ณ๊ฐ ์์ ๋๋ง๋ค ์์ ์นํฉ ์ค์ ์ ํด๋ก ํด์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๊ฑฐ๋ ์ฝ๋๋ฅผ ์ผ์ผํ ๋ณต๋ถํด์ ์ฌ์ฉํ๊ณคํ๋ค.
์๋ฐ ๋ฐฉ์์ ๋๋ฌด ๋นํจ์จ์ ์ด๊ณ , ์์ผ๋ก๋ ์ด๋ฐ ๊ฒฝ์ฐ๊ฐ ์์ฃผ ์๊ธธ ๊ฒ ๊ฐ์์ ์ง์ ย ๋ณด์ผ๋ฌํ๋ ์ดํธ ์์ฑ๊ธฐ๋ฅผ ๋ง๋ค์ด๋ณด๊ธฐ๋ก ํ์๋ค!!
1. ํ๋ก์ ํธ ์ค์
ํ๋ก์ ํธ ๊ตฌ์กฐ๋ ์ด๋ ๊ฒ ์ค์ ํ๋ค.
- bin : ํ๋ก์ ํธ ์ค์น, ์คํ์ ์คํ๋ ์คํฌ๋ฆฝํธ๊ฐ ๋ค์ด๊ฐ ๋๋ ํ ๋ฆฌ
- dist : ๋น๋๋ ํ๋ก๊ทธ๋จ ๋๋ ํ ๋ฆฌ
- lib : ๋ณด์ผ๋ฌํ๋ ์ดํธ๋ค
- src : ๋ณด์ผ๋ฌํ๋ ์ดํธ ์์ฑ๊ธฐ ์์ค
๋จผ์ package.json์ย binย ์, ํจํค์ง๋ฅผ ์ค์นํ ๋, ์คํ๋ ์คํฌ๋ฆฝํธ ๊ฒฝ๋ก๋ฅผ ๋ฃ์ด์ฃผ์๋ค.
๊ทธ๋ฆฌ๊ณ ย
run
ย ์คํฌ๋ฆฝํธ์์๋ ์ค์ ์คํ๋ ํ์ผ์ ์คํ์์ผ์ฃผ๋๋ก ์ฝ๋๋ฅผ ์์ฑํด์ฃผ์๋ค.#!/usr/bin/env node require("../dist")().run();
์ด ๋,ย
run
ย ์คํฌ๋ฆฝํธ๋ ์ด๋ ํ ์ฌ์ฉ์๋ ๋ชจ๋ ์คํํ ์ ์๋๋ก ๊ถํ์ ๋ณ๊ฒฝํด์ฃผ์๋ค. (๊ถํ ์ค์ ์ ํ์ง ์์๊ฒฝ์ฐ, ์คํฌ๋ฆฝํธ ์คํ์, permission ์ค๋ฅ๊ฐ ๋ฌ๋ค.)chmod 755 run chmod 755 run.cmd
๊ทธ๋ฆฌ๊ณ typescript์ directory๋ฅผ ๋ณต์ฌํ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํย
fs-extra
ย ํจํค์ง, ์์ ํฐ๋ฏธ๋์
์ถ๋ ฅ์ ๋์์คย terminal-kit
ย ํจํค์ง๋ฅผ ์ถ๊ฐ๋ก ์ค์นํด์ฃผ์๋ค.2. index.ts
์ํธ๋ฆฌํฌ์ธํธ์ธย
index.ts
ย ์์๋ run ๋ฉ์๋๋ง ๊ฐ์ง๋ ๋ชจ๋์ ํํ๋ก ์์ฑํด์ฃผ์๋ค.๊ทธ๋ฆฌ๊ณ ๋ณ๊ฒฝ๊ฐ๋ฅํ ๋ฐ์ดํฐ(๋ณด์ผ๋ฌํ๋ ์ดํธ ์ ๋ณด, ์
์ถ๋ ฅ, ์๋ฌ๋ฉ์์ง ๋ฑ)์ ๋ชจ๋ ๋ฐ๋ก ๋นผ๊ณ , ๋ฐ์ดํฐ๋ฅผย
createPrompt
ย ๋ผ๋ ํจ์์ ์ ๋ฌํ๋ ์ญํ ๋ง ์ฃผ์๋ค.const run = () => { const selectItemMap: SelectItemMap = new Map(selectItems) const options: PromptOptions = { DEFAULT_DEST_DIR_NAME, QUESTION_MESSAGE1, QUESTION_MESSAGE2, } createPrompt(selectItemMap, options) } module.exports = () => { return { run, } }
๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ์์๋ฅผ ๊ฐ๋ ๊ฐ์ฒด์ ํํ๋ฅผ ์ํดย
Map
ย ์ ์ฌ์ฉํ๋ค.3. data.ts
๋ณด์ผ๋ฌํ๋ ์ดํธ ์ ๋ณด๋ type, dirName, description ์ธ๊ฐ์ key๋ฅผ ๊ฐ๊ฒ ํ์๋ค.
- type : ๋ณด์ผ๋ฌํ๋ ์ดํธ์ธ์ง, quit์ธ์ง์ ๋ํ ์ ๋ณด (โboiler-plateโ | โquitโ)
- dirName : ๋ณด์ผ๋ฌํ๋ ์ดํธ์ ๊ฒฝ์ฐ ๋๋ ํ ๋ฆฌ์ด๋ฆ
- description : ํฐ๋ฏธ๋์ ์ถ๋ ฅ๋ ๋ฌธ์์ด
๊ทธ๋ฆฌ๊ณ ๊ทธ ์ธ ์
์ถ๋ ฅ๋ฉ์์ง๋, ๋ง๋ค์ด์ง default ๋๋ ํ ๋ฆฌ๋ช
, ์๋ฌ๋ฉ์์ง ๋ฑ๋ ์ ์ด์ฃผ์๋ค.
export const selectItems: SelectItems = [ [ 0, { type: 'boiler-plate', dirName: 'ts-webpack', description: '- TypeScript + Webpack', }, ], [ 1, { type: 'boiler-plate', dirName: 'js-webpack', description: '- JavaScript + Webpack', }, ], [ 2, { type: 'quit', description: '- quit', }, ], ] export const defaultDestDirName = 'my-app' export const QUESTION_MESSAGE1 = '์์ฑํ ํ๋ก์ ํธ๋ช ์ ์ ๋ ฅํ์ธ์(default : my-app, ํ์ฌ์์น: . ) > ' export const QUESTION_MESSAGE2 = '\n\n์์ฑํ ๋ณด์ผ๋ฌ ํ๋ ์ดํธ๋ฅผ ์ ํํด์ฃผ์ธ์.\n' export const SUCCESS_MESSAGE = '\n์์ฑ๋์์ต๋๋ค!\n' export const FAILURE_MESSAGE = '\n์๋ฌด์ผ๋ ์ผ์ด๋์ง ์์์ต๋๋ค!\n' export const QUIT_MESSAGE = '\n์ข ๋ฃ๋์์ต๋๋ค!\n' export const EXIST_DEST_ERROR_MESSAGE = '\n๋๋ ํ ๋ฆฌ๊ฐ ์กด์ฌํฉ๋๋ค.\n"' export const EXIST_TARGET_ERROR_MESSAGE = '\nํ์ฌ ๋๋ ํ ๋ฆฌ์ ํ์ผ๋ค์ด ์กด์ฌํฉ๋๋ค\n'
ํ๋ก๊ทธ๋จ ๋ก์ง๊ณผ ๋ฐ์ดํฐ(์ ์์๋ค)์ ๋ถ๋ฆฌํ๋ ๊ฒ ์ข์ ๊ฒ ๊ฐ์์ ๋ฐ๋ก ๋ถ๋ฆฌํด์ฃผ์๋ค.
4. types.ts
types.ts
์์๋ ๋ฐ์ดํฐ์ ๋ค์ด๊ฐ QuitSelectItem (quit ์ ๋ณด), BoilerSelectItem (๋ณด์ผ๋ฌํ๋ ์ดํธ ์ ๋ณด) ์ options์ ๋ค์ด๊ฐ ์ ๋ณด์ ๋ํ ํ์
์ ์ง์ ํด์ฃผ์๋ค.interface QuitSelectItem { type: 'quit' description: string } interface BoilerSelectItem { type: 'boiler-plate' dirName: string description: string } export type SelectItems = Array<[number, QuitSelectItem | BoilerSelectItem]> export type SelectItemMap = Map<number, QuitSelectItem | BoilerSelectItem> export interface PromptOptions { defaultDestDirName?: string QUESTION_MESSAGE1?: string QUESTION_MESSAGE2?: string SUCCESS_MESSAGE?: string FAILURE_MESSAGE?: string QUIT_MESSAGE?: string EXIST_DEST_ERROR_MESSAGE?: string EXIST_TARGET_ERROR_MESSAGE?: string } export type DefaultPromptOptions = Required<PromptOptions>
์ฌ์ค type์ด ๊ผญ ํ์ํ ํ๋ก๊ทธ๋จ์ ์๋์๋ ์์ง๋ง ํ์
์คํฌ๋ฆฝํธ ๊ณต๋ถ๊ฒธ ๊ฒธ์ฌ๊ฒธ์ฌ ํ์
๋ค๋ ์ง์ ํด์ฃผ์๋ค. ใ
ใ
; ๊ทธ๋๋ ํ์
์ ์ง์ ํด์ฃผ๋๊น ์คํ๋ ค ์์
ํ๋ฉด์๋ ์ด๋ค ์ธํฐํ์ด์ค์ธ์ง ํ์ธ์ด ๊ฐ๋ฅํด์ ๊ฐ๋ฐ๋ ๋น ๋ฅด๊ฒ ํ ์ ์๊ณ ์ข๋ ์์ ์ ์ผ ๊ฒ์ด๋ผ๋ ์๊ฐ์ ํ๋ก๊ทธ๋จ์ ์ ์ ๋ ๋ ์๊ฒผ๋ ๊ฒ ๊ฐ๋ค.
5. prompt.ts
prompt.ts
ย ์์๋ ์ค์ ์์ฑ๊ธฐ์์ ๋์ํ ๋ด์ฉ๋ค์ ๋ด์์ฃผ์๋ค.๋จผ์ ์ธ์๋ก ๋์ด์จ options์ ํค๊ฐ์ด ์์ ๊ฒฝ์ฐ์๋ default๋ก ์ ์ฉํ๊ณ ํค๊ฐ์ด ์์ผ๋ฉด ํด๋น ํค๊ฐ์ ์ฌ์ฉํ๋๋ก ์ค์ ํด์ฃผ์๋ค.
const { defaultDestDirName, QUESTION_MESSAGE1, QUESTION_MESSAGE2, SUCCESS_MESSAGE, FAILURE_MESSAGE, QUIT_MESSAGE, EXIST_DEST_ERROR_MESSAGE, EXIST_TARGET_ERROR_MESSAGE, } = { ...defaultOptions, ...options }
๊ทธ๋ฆฌ๊ณ ย
getDestDirName
ย ํจ์์ย getSelectItemType
ย ํจ์๋ฅผ ๋ง๋ค์ด ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ๊ณ term.cyan(QUESTION_MESSAGE1) const destDirName = await getDestDirName(defaultDestDirName) const selectItemValues = selectItemMap.values() const descriptions = Array.from(selectItemValues).map( value => value.description ) term.cyan(QUESTION_MESSAGE2) const selectedItem = await getSelectItemType(descriptions)
๋ฐ์ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋กย
createDirectory
ย ํจ์๋ฅผ ์คํํด ๋ณด์ผ๋ฌํ๋ ์ดํธ๋ฅผ ๋ง๋ค๋๋ก ํด์ฃผ์๋ค.const selectedItemType = await createDirectory( selectItemMap, selectedItem.selectedIndex, destDirName )
๊ทธ๋ฆฌ๊ณ ์ ์ ์ฉ์ด ๋์๋์ง, ์๋ฌ๊ฐ ์์๋์ง์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์๋ค.
if (selectedItemType === 'exist-dest') { term.red(EXIST_DEST_ERROR_MESSAGE) createPrompt(selectItemMap, options) } if (selectedItemType === 'exist-target') { term.red(EXIST_TARGET_ERROR_MESSAGE) createPrompt(selectItemMap, options) } if (selectedItemType === 'boiler-plate') { term.cyan(SUCCESS_MESSAGE) process.exit(0) } if (selectedItemType === 'quit') { term.red(FAILURE_MESSAGE) process.exit(0) } if (!selectedItemType) { term.white(QUIT_MESSAGE) process.exit(0) }
6. ๋ฐฐํฌ
npm run dev
ย ๋ก ์์ฑ๊ธฐ๊ฐ ์๋๋๋ก ์ ์๋ํ๋์ง ํ์ธํ๊ณ , version์ ์ฌ๋ ค์ค ๋ค,ย npm publish
ย ๋ก ๋ฐฐํฌํด์ฃผ์๋ค.{ "name": "@taenykim/generator", "version": "0.0.3", "scripts": { "dev": "tsc && ./bin/run", "build": "tsc" } }
7. ์ฌ์ฉ
์ฌ์ฉ์ย
npx @taenykim/generator
ย ๋ก ์ฌ์ฉํ ์ ์๋ค.npx๋ย node_moduleย ๋ก ํจํค์ง๊ฐ ์ ์ฅ๋์ง ์๊ณ , ํจํค์ง ์คํ ํ, ์ ๊ฑฐ๋๋ค.
8. ํ๊ธฐ
๋ฏธ๋ฃจ๊ณ ๋ฏธ๋ฃจ๋ค๊ฐ ํ๋ฑ ๋ง๋ค์ด์ ๋ฐฐํฌ๊น์ง ํด๋ดค๋๋ฐ ์์ผ๋ก ์ ์ฉํ๊ฒ ๋ง์ด ์ธ ์ ์์ ๊ฒ ๊ฐ๋ค. nodeJS fs ๋ชจ๋๊ณผ npm๊ณผ ์ชผ๋๋ ์นํด์ง ๊ฒ ๊ฐ์์ ๋๋ฌด ์ข์๊ณ ์์ผ๋ก ๋กค์
๋ณด์ผ๋ฌํ๋ ์ดํธ๋ ๋ฆฌ์กํธ ๋ฑ๋ฑ ๋ ์ถ๊ฐํด๋๊ฐ ๋ณด์์ผ๊ฒ ๋ค.
Loading Comments...