TypeScript CLI Framework
Deepkit App은 함수 시그니처가 곧 커맨드 정의가 되는 TypeScript CLI 프레임워크입니다. Argument, 플래그, 기본값, 유효성 검사는 모두 TypeScript 타입에서 가져오므로 같은 내용을 두 번 선언할 필요가 없습니다.
import { App, Flag } from '@deepkit/app'; import { Logger } from '@deepkit/logger'; import { Maximum } from '@deepkit/type'; class Greeter { constructor(private logger: Logger) {} greet(name: string) { this.logger.log(`Hello ${name}`); } } function greet( name: string, times: number & Maximum<5> & Flag = 1, greeter: Greeter, ) { for (let i = 0; i < times; i++) greeter.greet(name); } new App({ providers: [Greeter] }) .command('greet', greet) .run();
name은 필수 Argument가 되고, times는 기본값이 1인 --times 플래그가 되며, greeter는 의존성 주입 컨테이너가 제공합니다.
$ ts-node app.ts greet Peter --times 2 Hello Peter Hello Peter $ ts-node app.ts greet Peter --times 9 Invalid value for option --times: 9. Number needs to be smaller than or equal to 5 $ ts-node app.ts greet Peter --times abc Invalid value for option --times: abc. Cannot convert abc to number [type] $ ts-node app.ts greet --help Usage: ts-node app.ts greet [OPTIONS] [name] Arguments: name [required] Options: --times number [default=1]
Commander, Yargs, oclif와의 비교
| 옵션 정의 방식 | 커맨드의 TypeScript 타입 | .option() 호출 | Builder 호출 | Class의 정적 flags |
| 유효성 검사 | 타입에서 도출 (예: Maximum<5>) | 직접 작성한 파서 함수 | choices, coerce, check | 플래그 옵션과 파서 |
| 의존성 주입 | 내장 | 없음 | 없음 | 없음 |
| 설정, 모듈 | 내장 | 없음 | 설정 파일만 지원 | 플러그인 |
Deepkit은 런타임에 타입을 읽기 때문에 빌드 과정에 Deepkit 타입 컴파일러가 필요합니다. 빌드 단계가 없는 작은 스크립트라면 Commander 같은 라이브러리가 더 간단한 선택입니다.
Deepkit App에 포함된 기능
Deepkit App은 Deepkit 애플리케이션의 가장 기본적인 구성 요소이며, 라이브러리를 단독으로 사용하지 않는다면 보통 여기에서 시작합니다. Node.js 같은 런타임으로 실행하는 일반 TypeScript 파일이며, 다음 기능을 제공합니다.
- CLI 커맨드
- 모듈 시스템
- 서비스 컨테이너
- 의존성 주입
- 이벤트 시스템
- Logger
- 설정 로더 (env, dotenv, json)
커맨드는 DI 컨테이너에 대한 전체 접근 권한을 가지므로 모든 프로바이더와 설정 옵션에 접근할 수 있습니다. Deepkit 전용 전역 CLI 도구는 없습니다. HTTP/RPC 서버, 마이그레이션, 직접 작성한 커맨드는 모두 같은 파일에서 시작합니다.
@deepkit/framework를 사용하는 Deepkit Framework는 HTTP/RPC용 애플리케이션 서버, 디버거/프로파일러 등을 더해 이를 한층 더 확장합니다.
간편 설치
가장 쉽게 시작하는 방법은 NPM init으로 새 Deepkit 프로젝트를 만드는 것입니다.
npm init @deepkit/app@latest my-deepkit-app이 명령은 모든 의존성과 기본 app.ts 파일이 포함된 새 폴더 my-deepkit-app을 생성합니다.
cd my-deepkit-app npm run app
이 명령은 ts-node로 app.ts 파일을 실행하고 사용 가능한 커맨드를 보여 줍니다. 여기서부터 직접 커맨드, 컨트롤러 등을 추가해 나갈 수 있습니다.
수동 설치
Deepkit App은 Deepkit Runtime Types를 기반으로 하므로 모든 의존성을 설치합니다.
mkdir my-project && cd my-project npm install typescript ts-node npm install @deepkit/app @deepkit/type @deepkit/type-compiler
다음으로, 아래 명령을 실행하여 Deepkit의 타입 컴파일러가 node_modules/typescript에 설치된 TypeScript 패키지에 설치되도록 합니다.
./node_modules/.bin/deepkit-type-install
모든 peer dependency가 설치되어 있는지 확인하세요. NPM 7 이상에서는 기본적으로 자동 설치됩니다.
애플리케이션을 컴파일하려면 TypeScript 컴파일러가 필요하며, 앱을 쉽게 실행하기 위해 ts-node 사용을 권장합니다.
ts-node를 사용하는 대신 TypeScript 컴파일러로 소스 코드를 컴파일한 뒤 JavaScript 소스 코드를 직접 실행할 수도 있습니다. 이 방법은 짧은 커맨드의 실행 속도를 크게
높여 준다는 장점이 있습니다. 하지만 컴파일러를 수동으로 실행하거나 watcher를 설정해야 하므로 워크플로에 추가 부담이 생깁니다. 이러한
이유로 이 문서의 모든 예제에서는 ts-node를 사용합니다.
첫 번째 애플리케이션
Deepkit 프레임워크는 설정 파일이나 특별한 폴더 구조를 사용하지 않으므로 프로젝트를 원하는 대로 구성할 수 있습니다. 시작하는 데 필요한 파일은 TypeScript 파일 app.ts와 TypeScript 설정 파일 tsconfig.json 두 개뿐입니다.
프로젝트 폴더에 다음 파일들이 있도록 구성하는 것이 목표입니다.
. ├── app.ts ├── node_modules ├── package-lock.json └── tsconfig.json
기본 tsconfig 파일을 설정하고 reflection을 true로 설정하여 Deepkit의 타입 컴파일러를 활성화합니다.
이는 의존성 주입 컨테이너와 기타 기능을 사용하는 데 필요합니다.
{ "compilerOptions": { "outDir": "./dist", "experimentalDecorators": true, "strict": true, "esModuleInterop": true, "target": "es2020", "module": "CommonJS", "moduleResolution": "node" }, "reflection": true, "files": [ "app.ts" ] }
import { App } from '@deepkit/app'; import { Logger } from '@deepkit/logger'; const app = new App(); app.command('test', (logger: Logger) => { logger.log('Hello World!'); }); app.run();
이 코드에서는 test 커맨드를 정의하고 새 앱을 생성한 뒤 run()으로 바로 실행합니다. 이 스크립트를 실행하면 앱이 시작됩니다.
그런 다음 바로 실행합니다.
$ ./node_modules/.bin/ts-node app.ts VERSION Node USAGE $ ts-node app.ts [COMMAND] COMMANDS test
이제 test 커맨드를 실행하려면 다음 명령을 실행합니다.
$ ./node_modules/.bin/ts-node app.ts test
Hello World이제 Deepkit에서는 모든 작업이 이 app.ts를 통해 이루어집니다. 파일 이름은 원하는 대로 바꿀 수 있으며 더 많은 파일을 만들 수도 있습니다. 사용자 정의 CLI 커맨드, HTTP/RPC 서버, 마이그레이션 커맨드 등은 모두
이 진입점에서 시작됩니다.
Argument와 플래그
Deepkit App은 함수 Parameter를 CLI Argument와 플래그로 자동 변환합니다. Parameter의 순서가 CLI Argument의 순서를 결정합니다.
Parameter에는 어떤 TypeScript 타입이든 사용할 수 있으며 자동으로 유효성 검사와 역직렬화가 수행됩니다.
자세한 내용은 Argument와 플래그 장을 참고하세요.
의존성 주입
Deepkit App은 서비스 컨테이너를 설정하고, 가져온 각 모듈마다 부모로부터 상속받는 자체 의존성 주입 컨테이너를 설정합니다. 서비스, 컨트롤러, 이벤트 리스너에 자동으로 주입할 수 있는 다음 프로바이더를 기본으로 제공합니다.
- 로깅을 위한
Logger - 이벤트 처리를 위한
EventDispatcher - 등록된 CLI 커맨드를 위한
CliControllerRegistry - 등록된 미들웨어를 위한
MiddlewareRegistry - 현재 인젝터 컨텍스트를 위한
InjectorContext
Deepkit Framework를 가져오면 추가 프로바이더를 사용할 수 있습니다. 자세한 내용은 Deepkit Framework를 참고하세요.
종료 코드
종료 코드의 기본값은 0이며, 이는 커맨드가 성공적으로 실행되었음을 의미합니다. 종료 코드를 변경하려면 execute Method 또는 커맨드 콜백에서 0이 아닌 숫자를 반환해야 합니다.
import { cli } from '@deepkit/app'; @cli.controller('test') export class TestCommand { async execute() { console.error('Error :('); return 12; } }