하마
7k
2016-06-22 15:35:51
3
12310

TypeScript +Express + Node.js 시작하기


HTTP://BRIANFLOVE.COM/2016/03/29/TYPESCRIPT-EXPRESS-NODE-JS/  

아래 강좌 " TypeScript 을 위한 STL"  보고 연속성을 갖는 의미에서 번역했습니다.

완벽한 번역은 아니오니, 대략 훑어보시고 진지하게 사용하시려면 직접 보시는게 좋을거 같습니다.

그리고 세세한 정보들은 따로 검색해보시길 바랍니다. 

예를들어 )  TypeScript 란 ? Grunt  란 ? 


TYPESCRIPT + EXPRESS + NODE.JS


Node.js 를 위한 Express 웹 어플리케이션 프레임워크는 비동기 Node.js 엔진상에서 웹앱을 구축하기위한

가장 유명한 솔루션중의 하나입니다. Express 시작하는 웹앱개발은 매우 쉽습니다. 이 튜토리얼에서는 

 Express + Node.js 를 npm 으로 세팅하며 JavaScript 와 TypeScript 를 사용하여 코드를 구축하고 

app 을 빌드해보는 시간을 갖겠습니다.


왜 TypeScript 인가? 

강력한 타입과 함께 ECMAScript 6 (ES6) 를 사용한 차세대 웹어플리케이션을 구축하기 위한 언어로

무난하게 선택되었습니다. 강력한 타입이  Node.js 서버가 실행되고, JavaScript 가 실행되는 브라우저

에서는  JavaScript 를 향상시키는데 필요하진 않지만 개발자가 버그를 줄이며 (버그를 잡기위한 노력,

시간 또한)  써드파티 API 를 사용하는데 통찰력을 제공합니다. 


  

시작하기


  1. Node.js 다운로드 및 인스톨 
  2. package.json 파일 만들기 
  3. Express 인스톨 
Bash
$ mkdir myapp     
$ cd myapp        
$ npm init       

npm init 를 하고나서 계속 엔터를 쳐주면 폴더에 package.json 가 생성 되어 있을 겁니다.  

요기다가 몇가지를 추가해보도록 하죠. 


  1. 노드엔진 기술 
  2. 시작 script 생성 
JavaScript
{
  "name": "myapp",
  "description": "Just for fun",
  "version": "1.0.0",
  "private": true,
  "author": "Brian Love",
  "engines": {
    "node": "~5.6"
  },
  "scripts": {
    "start": "node ./bin/www"
  }
}

엔진과 스크립트 속성이 추가되었습니다. 엔진프로퍼티가 필요하진 않지만 만약 Google Cloud platform에

디플로이 하려면 필요 할 수 있습니다. 스크립트 속성은 npm 을 사용하여 실행될 수 있는 스크립트들의

맵입니다.이 예제에서 "start" 라는 이름의 스크립트를 생성하였고 그것은 노드를 실행시키며 JavaScript

파일을 실행시키기위한 초기화를 제공합니다.  여기서는 "www" 라는 이름의 파일(확장자가 없음을 주의) 과

함께 bin 이라는 디렉토리를 생성하였습니다. 이 www 파일은 JavaScript 파일인데 node.js 에 의해 실행되며

Express 웹 어플리케이션을 시작시킬 것입니다.


Express설치 


 다음으로는 express 패키지를  설치할것인데요. npm 을 사용하면 누워서 떡 먹기에요. 

Bash
$ npm install express --save


설치를 하고나면 myapp 폴더안에 node_modules 폴더가 만들어져 있을겁니다.

이 폴더는 express 가 사용하는 많은 노드 모듈들을 포함하고 있지요. 

만약 Git 을 사용한다면  .gitignore  파일에 저 폴더를 추가하는것을 잊지 마시구요. 


Express + Node.js 세팅 


express 를 시작하기 전에 먼저 bin/www  파일을 만들겠습니다. 

Bash
$ mkdir bin
$ cd bin
$ touch www


좋아하는 에디터 하나 열어서 타이핑 할 준비를 하세요. 일단 코딩을 하고나서 TypeScript 로 바꿀겁니다.

서버 시작을 위해 TypeScript  를 이용하지 않는 이유는 글쎄요...수 많은 시간을 통해 얻은 그냥 제 경험

인데요.. 일단 이 코드를 쓰고 나면 끝나기 때문입니다. 가장 기초적인 코드가 아래에 있습니다.


#!/usr/bin/env node
"use strict";

//module dependencies.
var app = require("../app");
var debug = require("debug")("express:server");
var http = require("http");

//get port from environment and store in Express.
var port = normalizePort(process.env.PORT || 8080);
app.set("port", port);

//create http server
var server = http.createServer(app);

//listen on provided ports
server.listen(port);

//add error handler
server.on("error", onError);

//start listening on port
server.on("listening", onListening);

우리가 한 첫번째 일은 "../app" 모듈을 요구한것인데요. 이것은 app.js 와 연계 되어 있고  우리의 루트 폴더

에 있어야 할 겁니다. app.js 파일은 우리의 TypeScript 소스파일로 부터 만들어질겁니다.  

지금 그것을 만드는걸 걱정하지마세요. 그냥 기억만 해두세요.

app.js













자 아래 코드들을 www 파일에 추가해 봅시다. 

normalizePort() 는 받아드리는 포트를 설정 합니다.

 process.env.PORT설정에 설정되있지 않다면 디폴트로 8080 을 사용합니다. 


/**
 * Normalize a port into a number, string, or false.
 */
function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

추가적으로 , 잡히지 않은 예외가 던저질때 호출되는 onError 함수 

/**
 * Event listener for HTTP server "error" event.
 */
function onError(error) {
  if (error.syscall !== "listen") {
    throw error;
  }

  var bind = typeof port === "string"
    ? "Pipe " + port
    : "Port " + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case "EACCES":
      console.error(bind + " requires elevated privileges");
      process.exit(1);
      break;
    case "EADDRINUSE":
      console.error(bind + " is already in use");
      process.exit(1);
      break;
    default:
      throw error;
  }
}

onListening 은 서버가 성공적으로 시작되면 한번만 호출됩니다. 

**
 * Event listener for HTTP server "listening" event.
 */
function onListening() {
  var addr = server.address();
  var bind = typeof addr === "string"
    ? "pipe " + addr
    : "port " + addr.port;
  debug("Listening on " + bind);
}


오케이, 우리는 바쁜 일은 다 끝냈습니다.  이제 TS 를 이용하여 프로그램을 작성해 봅시다. 



TypeScript 컴파일러 와 링커 설치 


타입스크립트 환경을 우리 어플리케이션에 설정해 봅시다. 

첫번째로 필요한것은 타입스크립트 컴파일러를 설치하는것 입니다. 간단하게 npm 으로 가능하죠. 


Bash
$ npm install typscript --save

타입스크립트를 컴파일하기위해 우리는 Grunt task runner 를 사용할 것입니다. 

npm 을 사용하여 다시 grunt 관련하여 여러가지를 인스톨 해보죠. 그리고 gruntfile.js 파일을 만들 것 입니다. 

Bash
$ npm install grunt --save
$ npm install grunt-cli --save
$ npm install grunt-ts --save
$ npm install grunt-tslint --save
$ npm install grunt-contrib-watch --save
$ npm install tslint --save
$ touch gruntfile.js



gruntfile_js


















우리의 타입스크립트 코드를 컴파일하기 위해 몇가지 추가해봅시다. 

gruntfile.js 을 열어서 아래와 같이 코딩 

module.exports = function(grunt) {
  "use strict";

  grunt.initConfig({
    ts: {
      app: {
        files: [{
          src: ["src/**/*.ts", "!src/.baseDir.ts", "!src/_all.d.ts"],
          dest: "."
        }],
        options: {
          module: "commonjs",
          noLib: true,
          target: "es6",
          sourceMap: false
        }
      }
    },
    tslint: {
      options: {
        configuration: "tslint.json"
      },
      files: {
        src: ["src/**/*.ts"]
      }
    },
    watch: {
      ts: {
        files: ["js/src/**/*.ts", "src/**/*.ts"],
        tasks: ["ts", "tslint"]
      }
    }
  });

  grunt.loadNpmTasks("grunt-contrib-watch");
  grunt.loadNpmTasks("grunt-ts");
  grunt.loadNpmTasks("grunt-tslint");

  grunt.registerTask("default", [
    "ts",
    "tslint"
  ]);

};


타입스크립트 컴파일러는 src/ 디렉토리 안에 우리가 만든 모든 .ts 파일을 다룰 것 입니다.

.baseDir 와 _all.d.ts 같은것들은 무시할 것이구요. node_modules/.bon/tsc 바이너리 실행자를 사용하여 

이것들을 수동적으로 실행 할수 있습니다.또한 이런것들을 하기위해 package.json 파일안에 스크립트를

생성할 수 도 있습니다. 다음 스크립트를 package.json 에 간단히 추가해봅시다.  


package.json 파일엔 아래처럼 grunt 가 추가되야 합니다. 

JavaScript
{
  "name": "myapp",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "grunt": "grunt",
    "start": "node ./bin/www"
  },
  ...
}


다음엔 tslinit 가 필요합니다. tslinit.json 파일은 다음과 같습니다. 

JavaScript
{
  "rules": {
    "class-name": true,
    "curly": true,
    "eofline": false,
    "forin": true,
    "indent": false,
    "label-position": true,
    "label-undefined": true,
    "max-line-length": [true, 150],
    "no-arg": true,
    "no-bitwise": true,
    "no-console": false,
    "no-construct": true,
    "no-constructor-vars": false,
    "no-debugger": true,
    "no-duplicate-key": true,
    "no-duplicate-variable": true,
    "no-empty": true,
    "no-eval": true,
    "no-string-literal": true,
    "no-switch-case-fall-through": true,
    "no-trailing-whitespace": true,
    "no-unused-expression": true,
    "no-unused-variable": false,
    "no-unreachable": true,
    "no-use-before-declare": true,
    "no-var-requires": false,
    "one-line": [
      true,
      "check-open-brace",
      "check-catch",
      "check-else",
      "check-whitespace"
    ],
    "quotemark": [true, "double"],
    "semicolon": true,
    "triple-equals": [true, "allow-null-check"],
    "typedef": [true,
      "callSignature",
      "indexSignature",
      "parameter",
      "propertySignature",
      "variableDeclarator",
      "memberVariableDeclarator"],
    "use-strict": false,
    "variable-name": [
        true,
        "allow-leading-underscore"
    ],
    "whitespace": [
      true,
      "check-branch",
      "check-decl",
      "check-operator",
      "check-separator",
      "check-type"
    ]
  }
}

작업이 끝나면 grunt 커맨드를 실행할수 있을겁니다.


$ npm run grunt

여기서 ERR가 발생하는데 TypeScript compiler 가 es6 빌트인 오브젝트인 Array 등을 알지

못해서인데  아래 같이 인클루드를 해주면 된다. 

/// <reference path="../node_modules/typescript/lib/lib.es6.d.ts"/>

여기 튜토리얼에서는 대신  _all.d.ts 파일을 참조했다. lib.es6.d.ts 디펜던시를 포함하여  
모든 프로젝트 디펜던시는 여기에 놓기 때문이다.

그리고 타입스크립트 파일들의 탑레벨에 _all.d.ts 파일을 참조하였다. 
즉 app.ts 파일의 처음에 아래를 추가 

/// <reference path="_all.d.ts"/>


타입스크립트 Express 웹 어플리케이션 


TypeScript + Express + Node.js 를 사용하여 코딩할 준비가 마침내 되었습니다. 

시작하기위해 먼저 src 디렉토리를 만들어 봅시다. 그리고 app.ts 파일을 만드세요. 


Bash
$ mkdir src
$ cd src
$ touch app.ts


제일먼저 만들어 볼것은 서버 클래스 입니다. 

JavaScript
"use strict";

import * as bodyParser from "body-parser";
import * as express from "express";
import * as path from "path";

/**
 * The server.
 *
 * @class Server
 */
class Server {

  public app: express.Application;

  /**
   * Bootstrap the application.
   *
   * @class Server
   * @method bootstrap
   * @static
   * @return {ng.auto.IInjectorService} Returns the newly created injector for this app.
   */
  public static bootstrap(): Server {
    return new Server();
  }

  /**
   * Constructor.
   *
   * @class Server
   * @constructor
   */
  constructor() {
    //create expressjs application
    this.app = express();

    //configure application
    this.config();
  }
}

소스를 재빨리 살펴봅시다.

  1.  먼저 자사스크립트를 위해 STRICT MODE 를 사용했구요.
  2. 필요한 모듈을 임포트 하였습니다. body-parser 모듈 과 익스프레스 엔진과 path 모듈을 사용.
  3. 서버클래스를 만들었구요.
  4. 서버 클래스는 express.Application 속성을 가지고있습니다. 
  5. 서버 클래스는 새로운 서버클래스인스턴스를 만드는 부트스트랩 정적메소드를 가지고 있습니다.
  6. 서버 클래스는 생성자도 가지고 있네요. 생성자에서는 설정등을 해주고 있습니다.  

다음으로 진행하기 전에 몇가지 알아 봅시다.

  1. body-parser 모듈을 아직 인스톨하지 않았습니다. npm 으로 해야하죠.
  2. 타입스크립트 컴파일러는 Array 같은 빌트인 오브젝트를 알지 못합니다.
  3. 타입스크립트 컴파일러는 익스프레스를 위한 타입 정의를 알지 못합니다. 
해결해 봅시다.

먼저 body-parser 모듈 설치 


$ npm install body-parser --save

_all.d.ts 파일을 src 폴더 아래에 만듬. 이것은 우리 어플리케이션을 위한 타입 정의를 가르키는 참조를

포함하게 될것입니다.


$ touch _all.d.ts

 _all.d.ts 파일에 아래 추가 


/// <reference path="../node_modules/typescript/lib/lib.es6.d.ts" />

app.ts 파일에 _all.d.ts 파일 참조 


/// <reference path="_all.d.ts" />


타입스크립트 컴파일러는 이제 ES6 인터페이스에 대하여 알게 되었습니다. 추가적으로 메인 타이핑

파일을 참조할 것입니다. 이제 익스프레스나 앵귤러같은 오픈소스 프로젝트와 함께 할때 강력한

타입스크립트의 타입의 장점을 취하기위해 커먼모듈에 대한 타입 정의 파일을 얻기위한 Typings 를

사용할것입니다.  


Typings 설치



$ npm install typings --save

일단 typings 를 인스톨하고나서  타입스크립트 정의 파일들을 인스톨링 하고 서치하기 위한 커맨드라인

인터페이스를 사용할수 있습니다. 


$ node_modules/.bin/typings install body-parser --ambient --save
$ node_modules/.bin/typings install express --ambient --save
$ node_modules/.bin/typings install node --ambient --save
$ node_modules/.bin/typings install serve-static --ambient --save
$ node_modules/.bin/typings install express-serve-static-core --ambient --save
$ node_modules/.bin/typings install mime --ambient --save


다음 단계는 typings 로 부터 생성된 typings/main.d.ts 파일을 참조하는것이다. 이 파일은 _all.d.ts 파일과

비슷한데 이것은 타입스크립트 정의 파일의 모두의 참조를 포함합니다. 

아래와 같이 _all.d.ts 파일을 열어서 추가하세요. 


/// <reference path="../typings/main.d.ts" />

이제 모든것이 세팅되었으니 다시 어플리케이션을  시작해 봅시다.

$ npm run grunt
$ npm start


만약 브라우저에서 http://localhost:8080  로 연결해보면 에러가 날것인데 그건 루트에 대한 GET 라우트가

정의되지 않아서입니다. 

localhost_8080

Routes 정의 

마지막 단게는 웹 어플리케이션을 위한 경로를 정의하는것 입니다. 라우트 모듈의 분리된
클래스들에서 설정할것인데요.여기 src/routes/index.ts 파일을 봅시다. 


/// <reference path="../_all.d.ts" />
"use strict";

import * as express from "express";

module Route {

  export class Index {

    public index(req: express.Request, res: express.Response, next: express.NextFunction) {
      //render page
      res.render("index");
    }
  }
}

export = Route;

.

Index.index() 라우트는 간단하게 index 페이지를 랜더링합니다. 이것을 묶어주기위해 우리는 app.ts 에서

routes/index.ts 모듈을 요구해야합니다. 


import * as indexRoute from "./routes/index";


그리고 나서 새로운 private 메소드를 routes() 라는 이름으로 만들것이고 생성자에서 호출될것입니다.


/**
 * Constructor.
 *
 * @class Server
 * @constructor
 */
constructor() {
  //create expressjs application
  this.app = express();

  //configure application
  this.config();

  //configure routes
  this.routes();
}

routes() 메소드는 간단하게 웹 루트 "/" 에 대한 GET 요청과 엮여졌습니다. 


/**
 * Configure routes
 *
 * @class Server
 * @method routes
 * @return void
 */
private routes() {
  //get router
  let router: express.Router;
  router = express.Router();

  //create routes
  var index: indexRoute.Index = new indexRoute.Index();

  //home page
  router.get("/", index.index.bind(index.index));

  //use router middleware
  this.app.use(router);
}

routes() 메소드에서 익스프레스의 Router() 로 처음 접근되고나서 이전에 임포트한 모듈을 사용합니다.

index 클래스에 대한 새로운 인스턴스를 만들었고 Index 클래스는 

index 라는 이름의 메소드를 가졌습니다.  (조금 헥깔릴것이라고 생각되네요)


Hello World


마침내 다 만들었습니다.  어플리케이션을 다룰때 저는 jade 템플릿 엔진을 이용합니다. 

npm 을 이용해서 설치해보시죠. 


$ npm install jade --save

views 폴더에 index.jade 파일을 만듭니다. 

$ mkdir views
$ cd views
$ touch index.jade

 index.jade 파일을 열고 다음을 타이핑해 넣습니다.

h1 Hello World!
p You did it, congratulations!

재컴파일 하는것을 잊지 마시구요. grunt watch 명령어를 사용해도 됩니다.

$ npm run grunt watch

TS 가 컴파일되면 , 서버를 재시작하세요.

$ npm start

이제 다음과 같이 시작됩니다. 

Hello World

Download Source


3
  • 댓글 3

  • toxin
    439
    2016-06-22 23:10:07

    좋은정보 감사합니다.

    노드 스터디하면서 서버만드는중인데 많이 헤매고 있네요.

    라우터같은 개념을 정확하게 모르니 서버만들기가 참..

  • z
    1k
    2016-06-26 23:41:11

    하마님 나중에 시간되시면 대화좀 나눌수 있을까요?

    pbshop1001@gmail.com

    꼭 메일 주세요

  • dasider41
    354
    2016-06-27 07:55:22

    //느띠나뭉

    저도 react.js를 주로 사용하고, 대세임은 인정합니다, 그리고 최근 트렌드는 grunt대신 webpack이라 말씀 역시 동의합니다. 그렇지만 지구상의 대부분의 개발자가 그렇다는 내용은 동의하기는 힘드네요;;;; angular 2역시 아직은 대세임에는 부정하기 힘들것 같습니다, 좋은글을 너무 부정적인 시각으로 볼 필요는 없을것 같네요.

    ps. 지구를 엄청 사랑하시는 분인가 봅니다 :)

  • 로그인을 하시면 댓글을 등록할 수 있습니다.