Typescript2 서버 튜토리얼 - 1/4

TL;DR

시작하며

Python 으로만 서버 개발하다가 지난주부터 nodejs 를 공부하게 되었는데 너무나 다양한 (형태의) 예제들이 오히려 압박이었다.

본 글은 나처럼 다른(Python) 언어로 서버 개발하다가 넘어오는 개발자들을 위해(즉 node 환경에 익숙하지 않은 서버개발자) 작성했다.

글 순서는 아래와 같으며, 전체 시리즈의 끝에는 간단한 채팅 서비스를 만들게 될 것이다.

  1. hello world (당연하게도)
  2. express + Typescript 로 간단한 REST API 개발
  3. mongoose + Typescript 로 앞서 만든 REST API 에 CRUD 추가
  4. socket.io + Typescript 로 실시간 채팅 서비스 개발

node 기본과 Typescript 는 알고 있다고 가정하고 진행하겠다.

내 개발 환경은 osx + terminal + vim 이며 IDE 쓰는 사람은 알아서…

프로젝트 생성 및 설정

프로젝트 폴더를 생성한다.

$ mkdir cinnamon
$ cd cinnamon

Typescript 를 이용해 서버를 돌리려면 무조건 2개를 init 해줘야한다.

npmtsc 이다. npm 은 패키지 매니저이고 tsc 는 타입스크립트 컴파일러다.

이건 무조건 해야하므로 걍 받아들여라.

NPM: package.json

최근 python 서버에는 가상환경(virtualenv 모듈) 이 필수고 node 도 마찬가지다.

node 에서 pip 에 해당하는 패키지 매니저는 npm 이며 requirements.txt 의 역할을 하는 것은 package.json 이다.

npm 환경을 설정하기 위해 아래 명령을 입력한다.

$ npm init

해당 명령은 package.json 파일을 생성해준다. 일단은 입력할 내용이 없다. 엔터만 치면 된다.

package.json 의 모양은 다음과 같을 것이다.

{
    "name": "cinnamon",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
            "test": "echo \"Error: no test specified\" && exit 1"
        },
        "author": "",
        "license": "ISC"
}

TSC: tsconfig.json

이제 타입스크립트를 설지하자.

$ npm install --save typescript @types/node

–save 옵션은 package.json 에 자동으로 설치되는 패키지의 의존성을 붙여준다. @types/패키지 은 패키지의 선언(declaration) 을 Typescript 에서 사용할 수 있게 해준다. 1.x 에서는 tsd 나 typings 같은 패키지로 복잡하게 했었는데 2.x 에서는 @types/패키지 를 npm install 하면 끝난다.

타입스크립트는 TS 형태를 JS 로 컴파일하는 방식이며 컴파일시 tsconfig.json 파일을 참조한다.

이제 tsconfig.json 을 만들어보자. 아래 명령어 하나로 끝난다.

$ tsc --init

이제 tsconfig.json 가 생겼다. 파일내용은 다음과 같을 것이다.

outDir 은 직접 추가해주면 되는데 아래에서 설명하겠다.

{
    "compilerOptions": {
        "outDir": "build",      // add this line manually
        "module": "commonjs",
        "target": "es5",
        "noImplicitAny": false,
        "sourceMap": false
    }
}

다른건 신경안써도 되고 일단 target 필드만 보자.

위에서 말했듯 TS 는 JS로 컴파일을 하는데, 어떤 ES 표준버전으로 컴파일 할지 결정할 수 있다. node 6.4 이상은 es2015 를 지원하기 때문에2 node 구 버전을 쓰거나 프론트엔드 작업을 할 게 아니면 굳이 es5 로 컴파일을 할 이유가 없다. es2015 에는 Promise, Generator, Iterator 같은 편리한 기능들이 많이 있기 때문에 평소에는 es2015로 설정해주면 된다.

다만 여기서는 컴파일된 코드가 컴파일 전 코드와 다르다는 것을 보여주기 위해 target 을 es5 로 놔두겠다.

마지막으로 outDir 필드를 추가해주자. 맨 윗줄에 추가한 이유는 쉼표(,) 때문에 잘못입력할까봐 그런것인데 위치는 사실 상관없다.

outDir 은 컴파일된 JS 파일이 어디에 위치할지 결정해주는 것으로, 해당 옵션이 없으면 컴파일된 파일(.js) 이 소스파일(.ts) 과 동일한 폴더에 위치하게 된다. ts 파일과 js 파일이 섞이면 보기도 안좋고 관리하기도 어렵기 때문에, outDir 로 ts 와 js 위치를 구분해주는 것이 정신건강에 좋다.

Hello world!

Typescript 파일은 src 폴더 아래에 위치시키는 것이 관례인 것 같다. 우리도 src 폴더를 만들자.

$ mkdir src

이제 첫 ts 파일을 만들어보자.

$ touch index.ts

좋아하는 편집기로 아래 내용을 index.ts 에 입력한다.

class Greeter {
    constructor(public name: string) { }

    greet() {
        return `Hello world, ${this.name}!!`;
    }
};

const greeter = new Greeter("Vincent");
console.log(greeter.greet());

es6 에 추가된 classformatting 를 써야 구분이 될 것 같아서 다소 위와 같은 복잡한 hello world 예제를 작성했다.

이제 index.ts 파일을 tsc 를 이용해 컴파일 해보자.

$ tsc

컴파일을 하면 build 폴더가 생기고 안에 index.js 파일이 es5 형태로(엄청 복잡함) 컴파일 되어 있을 것이다.

현재까지의 구조는 아래와 같을 것이다.

├── build
│   └── index.js
├── package.json
├── src
│   └── index.ts
└── tsconfig.json

생성된 파일을 실행해보자.

$ node build/index.js
Hello world, Vincent!!

잘 출력되는 것을 볼 수 있다.

npm start

NPM 은 패키지 매니저이지만 간단한 스크립트 명령도 수행할 수 있다.

$ npm install
npm WARN cinnamon@1.0.0 No description
npm WARN cinnamon@1.0.0 No repository field.

$ npm test
> cinnamon@1.0.0 test /Users/haandol/git/cinnamon
> echo "Error: no test specified" && exit 1

Error: no test specified
npm ERR! Test failed.  See above for more details.

npm test 명령은 어디서 온것인가? 아까 작성된 package.json 의 scripts 필드를 보면 test 필드가 있는데 필드명은 npm 파라미터이고 값은 셸에서 실행되는 명령어이다. 즉, 아래는 npm test 를 실행하면 echo 명령으로 에러메시지를 보여준 뒤 프로그램을 강제종료한다.

...
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
},
...

대부분의 인터넷 예제들은 npm start 를 이용해 실행되도록 설정되어 있는데 우리도 해보자.

우리는 tsc 를 이용하여 index.ts 를 컴파일한 뒤 node 를 이용해 index.js 를 실행하기만 하면 된다.

아래와 같이 scripts 필드에 start 를 추가하고 저장한다.

...
"scripts": {
    "start": "tsc; node ./build/index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
},
...

제대로 적용이 되는지 확인하기 위해 index.ts 를 수정해보자.

class Greeter {
    constructor(public name: string) { }

    greet() {
        return `Hello world, ${this.name}!!`;
    }

    // Add hugeGreet method
    hugeGreet() {
        return `HELLO WORLD, ${this.name}!!!!!`;
    }
};

const greeter = new Greeter("Vincent");
console.log(greeter.hugeGreet());

이제 npm start 명령만 입력하면 자동으로 index.tsbuild/index.js 로 컴파일하고 해당 파일을 node 로 실행한다.

$ npm start

> cinnamon@1.0.0 start /Users/haandol/git/cinnamon
> tsc; node ./build/index.js

HELLO WORLD, Vincent!!!!!

마치며

Typescript 가 Angular, React, React Native 등의 다양한 환경에서 쓸 수 있게 범용으로 만든 MS 니까 언어라 그런지 튜토리얼도 너무나 다양한 내용을 다루고 있어서 혼란스러웠다.

구글 검색으로 찾은 다른 튜토리얼들 역시 프론트 개발자가 풀스택을 하면서 쓴 글이 많아서 마찬가지로 혼란스러웠다. 돌잔치에서 돌잡이하는 기분이었다. 뭘 잡아도 뭔지도 모르고 잡음.

본 글의 내용은 막 Node 개발을 시작한 서버 개발자로서 내가 궁금해하던 내용들만 짚어서 만들었기 때문에 다른 부분은 다른 예제들을 찾아보며 공부하면 될 것 같다.

짧게 쓴다고 썼는데도 겁나 기네…