Node, Express, Typescript, Mongo project boilerplate

개요

작년 제2회 유니톤(대학생 연합 해커톤)에 나가면서, 절실히 느꼈던 것은 미리 준비해 갈 수 있는 것들에 대해서 준비하지 않아서 애를 많이 먹었다. 예를 들어 프로젝트의 boilerplate, 프로젝트 디렉토리 설정, linter설정, db connect, server config, aws설정을 미리 해갈 수 있었다면 좀 더 빨리 기능구현을 할 수 있지 않을까 생각했다.

Boilerplate란?

Boilerplate
Boilerplate는 변경 없이 재 사용할 수 있는 물품을 말한다. 이 용어는 철강쪽에서 유래된 단어로, 보일러 플레이트는 증기 보일러 내에 사용되는 커다란 압연 강판을 말한다. 이처럼, 오랜 기간동안 사용되었으며 튼튼하거나 반복적으로 재사용하기 충분한 정도로 만들어진 물품을 말한다.

소프트웨어에서는, 일종의 기본설정이 되어있고 디렉토리설정이 되어있는 재사용 가능한 템플릿 이라고 볼 수 있다.

가장 유명한 boilerplate는 아마도 HTML5 Boilerplate: The web’s most popular front-end template가 아닐까.

Node.js란?

Node.js
Node.js크롬 V8 Javascript Engine위에서 동작하는 Javascript runtime이고 이벤트-드리븐 방식, non-blocking I/O를 사용하므로 가볍고 효율적이다. node의 생태계중 하나인 NPM은 세계에서 가장 큰 오픈소스 생태계 중 하나이다. 무슨 소리인지 하나도 모르겠다. 라고 생각하는 독자가 있다면 단어 하나하나에 걸려있는 링크를 참조하며 이해하도록 하자. 개발자가 되려면 모르는 것을 검색하고 스스로 학습하는 습관을 들여야 한다.

Node에 대한 기본 지식이 없다면 간단히 Mooc에서 기본 개념정도는 알아두고 시작하는 것이 좋다고 생각한다. 추천하는 Mooc는 역시 codeschool의 Node.js Tutorial | Code School , Express.js Tutorial | Code School를 참조하는 것이 좋다. codeschool은 유료기는 하지만 충분이 가격 대비 품질이 보증되는 Mooc이므로 무조건 추천한다.

Typescript란?

typescript
Typescript는 순수한 자바스크립트로 컴파일되는 자바스크립트 superset이다. 컴파일 타임에서 타입을 체크하는 언어이고, Microsoft가 주요 Maintainer이며 Angular , Ionic Framework , Aurelia, DoJo등 많은 오픈소스에서 이미 채택되어 사용중이다. 쉽게 말하면 타입이 있는 자바스크립트이다. 타입스크립트는 3가지 특징을 가지고있다.

  1. Type checking 자바스크립트에서 type은 동적타이핑이며 이는 코딩할 때에 많은 이슈를 불러왔다. 예를들어 함수의 인자로 type을 검사하지 않기 때문에 String에서 Number관련 내장 함수를 사용하여 오류가 나는등 여러 이슈가 있다. 유연함이 생산성을 늘리는 것은 맞지만 도리어 해가 될때도 있다. 자바스크립트를 한번이라도 써본 사람이라면 타입이 있었으면 하는 바람을 가지고 있을 것이다. 이를 해결해 준것이 Typescript이다.
  2. Compile typescript로 작성한 파일에 컴파일 명령어를 치면 ecma5로 작성된 js를 자동으로 생성해준다. 그러므로 대부분의 브라우져에서 그대로 사용할 수 있다.
  3. Objective Oriented Programming 마지막으로 OOP이다. typescript는 es6처럼 class를 가지고 있고 이는 그동안 자바스크립트가 가지고 있던 난해한 prototype으로 설계하는 방식에서 벗어나 다른 프로그래밍 언어와 비슷한 OOP를 적용할 수 있게 되었다는 점이다.

Mongo DB란?

MongoDB
MongoDB는 대표적인 NoSQL으로 알려져있다. Scheme에 제약된 조건이 없으며 row수가 많은 데이터를 보관, 검색이 간편하고 scale-out에 장점을 가지고 있는 DB로 알려져있다. 사실 필자도 사이드 프로젝트를 하면서 Codeschool 강의를 참조하고, CRUD정도 작성해 본 것이 전부이기 때문에 다음 포스팅에서 자세히 작성하겠다.

Getting Started

자 이제 기본 개념들을 알았으니 한번 사용해보자. 물론, 이 블로그 아티클을 보는 사람의 컴퓨터에 Node.js 환경이 구축되어 있다는 것을 가정한다. 만약 Node.js가 구축되지 않은 환경이라면 Node.js 설치 링크를 참조하고 난 후 진행한다. Node.js 환경이 구축되어 있다면 NPM이 설치되어 있을 것이다.

1. NPM이 설치되어 있는지 확인

$ npm -v
4.0.5

2. npm을 이용해 typescript, tslint 를 global로 설치한다.

$ npm install -g tslint typescript

TSLint 란 typescript 전용 linter이다. linter는 여러명이서 협업을 진행할때 코딩 스타일, 코딩 컨벤션을 지정해 주는 툴이고 보면 된다. 유명한 linter에 관한 짤은 다음 그림을 참조하자. War

이 프로젝트에서 쓰지 않지만 typingstsd에 대해서 궁금한 사람들이 혹시 있을까봐 적는다. typings란 기존 자바스크립트 라이브러리들의 타입 정보만을 선언한 파일을 내려받을 수 있도록 도와주는 tool이다. 적다 보니 이제 안 쓴단다. 이전엔 TSD라는 typings와 비슷한 definition manager가 있었으나 Deprecated 되고 typings로 옮겨졌다.그리고 typings 마저도 이제 안 쓴다.

사실 필자도 설치하는 방법, 설정들을 정리하면서 @types/package들과 typings둘의 차이점에 대해서 몹시 궁금해졌다. 아무거나 적당히 사용하면 되는게 아닌가? 했지만 블로그에 글을 실으려면 정확한 정보를 제공해야 하기 때문에 구글링을 해 보았다.

구글 검색어: typings vs @type (외국도 한국처럼 vs를 참 좋아한다. 2가지 비교하고 싶으면 compare보다 vs를 치는게 훨씬 잘 나오는듯) 역시나 갓버플로우 형님들이 깔끔한 답변을 넣어줬다. TypeScript typings in NPM @types org packages - Stack Overflow 3줄요약

  • typescript 2.0넘으면 typings가 필요없다.
  • Microsoft에서 npm에 developer team을 갈아넣어서 maintain 할 것이다.
  • npm에서 설정만 하면 다 해줌.

결론적으로는 $ npm install @types/express 로 라이브러리를 설치하고import * as express from "express”; 이렇게 사용한다.

3. Express generator를 이용해 프로젝트 기본 Scaffolding을 한다.

필자는 Webstorm을 주로 사용하고, Webstorm에서 node project를 만들때는 Webstorm의 file탭-new탭-project를 클리하면 다음 화면이 나오고, 원하는 generator 버전, template 엔진을 선택한다. express-generator

Webstorm을 깔기 싫은 독자는 커맨드라인을 이용한다. GitHub - expressjs/generator: Express’ application generator을 사용한다.

$ npm install -g express-generator
$ express --view=jade 만들프로젝트경로 && cd 만들프로젝트경로
$ npm install

API 서버를 만들것이기에 Template엔진은 default로 설정되어있는 jade를 우선 깔고 나중에 필요없는 코드를 삭제한다.

4. 프로젝트를 만들었으니 접속

$ npm start

그다음 http://localhost:3000/ 에 접속하면 Express의 Wellcome to Express 화면을 볼 수 있다. 다음 화면을 볼 수 있으면 여기까지 잘 설치된 것이다. express

5. Typescript 컴파일 설정을 한다

$ tsc --init
message TS6071: Successfully created a tsconfig.json file.

위 커맨드로 tsconfig.json 파일이 생성되고 열어보면 다음과 같다.

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "noImplicitAny": false,
        "sourceMap": false
    }
}

CommonJS 는 브라우저 뿐만 아니라 서버사이드 애플리케이션이나 데스크톱 애플리케이션에서 사용되기 위한 javascript 명세이다. ts를 es5의 js로 컴파일 한다는 설정이다.

6. js파일들을 ts로 모두 바꾸자

  • Project/app.js => app.ts
  • Project/bin/www => www.ts
  • Project/router/index.js => index.ts

7. Tslint Config

$ tslint —init

위 커맨드를 입력하면 tslint.json파일이 생성되고, 이 파일에는 json구조로 규칙이 저장되어있다. 규칙을 수정하고 싶으면 tslint를 설정하는 규칙은 Tslint Rules을 참조하여 수정하면 된다. 간단히 설명하자면 대부분 첫번째 인자로의 true, false는 규칙 적용 여부, 그 뒤의 string은 옵션이다. 필자는 string이나 path에서 double quote(“)가 아닌 single quote(‘)를 사용하므로 이를 수정한다.

~~~
{
“quotemark”: [
            true,
            “single” //기존 “double”
        ],
}
~~~

Webstorm에서는 다음과 같이 설정하면 빨간 밑줄을 띄워주고, 대체로 editor나 IDE단에서 linter정도는 지원해 주므로 밑줄또는 경고등을 띄워준다. tslint

커맨드라인에서 linter를 적용하고 싶으면 다음을 입력하면 된다.

$ tslint -c path/to/tslint.json ‘path/to/project/**/*.ts’

linter를 적용하고 나면 여러 경고를 만날 수 있는데, 이 경고에 따라 수정하면 된다.

대체로 처음 설정후 만나는 linter의 경고에서는 변수가 아닌 값들을 var가 아닌 const나 let으로 강제하는 것들이 대부분이다.

8. export

app.js의 마지막줄 module.export를 export default로 바꿈, routes/index.ts,routes/users.ts도 module.export를 export default로 바꾼다.

export default app; // module.exports = app;

9. livereload

node는 기본적으로 코드를 변경하고 난 후에 서버를 재시작해야 그 코드가 반영된다. 매번 ctr + c, 서버 재시작하기 귀찮음을 많이 느껴보았으므로 livereload 기능은 써보니 엄청나게 편하다! 이를 설정하는 방법은 다음과 같다.

  • npm install nodemon —save-dev
  • npm install concurrently —save-dev concurrently는 여러 명령어를 한번에 실행시키는 node module이다.
{"scripts": {
    "start": "npm run build:live",
    "concurrently \"tsc -w\" \"nodemon ./bin/www.js --config nodemon.json\""
  },
...
}

위의 스크립트를 넣음으로써 동작은 다음과 같다. 1. npm start를 입력하면 typescript 컴파일러에 의해 코드의 변경을 감지하면 자동으로 컴파일을 진행(typescript => javascript) 2. nodemon은 컴파일된 javascript 파일의 변화를 감지하고 재시작한다

위의 방법이 싫으신 분은 ts-node사용하는 방법도 있다. Bonus: Live compile + run

10. 역시 소스코드 수정후 잘 돌아가는지 검사

$ npm strt

yuhogyun-ui-MacBook-Pro:boilerplate yuhogyun$ npm start

> boilerplate@0.0.0 start /Users/yuhogyun/boilerplate
> npm run build:live


> boilerplate@0.0.0 build:live /Users/yuhogyun/boilerplate
> concurrently "tsc -w" "nodemon ./bin/www.js --config nodemon.json"

[1] [nodemon] 1.11.0
[1] [nodemon] to restart at any time, enter `rs`
[1] [nodemon] watching: *.*
[1] [nodemon] starting `node ./bin/www.js`

11. Mongodb, Mongoose 설치 및 코드작성

우선 MongoDB Download Center | MongoDB 이 링크에서 몽고디비를 설치한다. 그다음 몽고디비 서버를 켠다

$ mongod

mongoose 는 Mongo를 node에서 사용하기 위한 object model이라고 보면 된다.
typescript에서 mongoose를 이용하려면 DefinitelyTyped/mongoose를 따라해보자.

/** Mongoose Config **/
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/boilerplate');

import {Document, model, Model, Schema} from 'mongoose';

var UserSchema: Schema = new Schema({
  username: {
    type: String,
    required: true,
    unique: true
  },
  age: Number,
  friends: [String],
  data: [Schema.Types.Mixed]
});

interface IUser extends Document {
  username: string;
  age: number;
  friends: string[];
  data: any[];
}

var UserModel: Model<IUser> = model<IUser>('User', UserSchema);

var user = new UserModel({user.username: 'Jane'});
user.username;     // IUser properties are available
user.save();       // mongoose Document methods are available

UserModel.findOne({}, (err: any, user: IUser) => {
  user.username;   // IUser properties are available
  user.save();     // mongoose Document methods are available
});

Reference Demo Project

블로그 글을 쓰며 개인용으로도 쓸겸 typescript node mongo express로 기본 CRUD API 서버를 만들어보았다. 위의 긴 과정을 생략하고 싶은 독자들은 다음 링크를 참조하자. https://github.com/yoohoogun114/node-express-mongo-typescript

글을 마치며

Typescript가 트렌드가 될지 안 될지는 모르겠지만, 우선 javascript에서 타입 부여가 가능하다는 것은 매우 큰 장점이다. Typescript 말고도 관련 오픈소스 프로젝트들을 둘러보았는데 아주 활발한 것 같아서 아마 미래는 밝은 듯 하다. 또한 그동안 MEAN스택에서 빠져있던 mongo를 채우니 이제 드디어 완성인 것 같은 느낌이다.

참고자료

TypeScript with NodeJS Include TypeScript files by default by arosequist · Pull Request #871 · remy/nodemon · GitHub


Philographer
Written by@Philographer
Fail Fast, Learn Faster

GitHublinkedInFacebook