« Home / All Guides

Felix's node.js Beginners Guide

node.js가 개발되는 속도에 비해 너무 빠르게 관련 자료가 증가하고 있다. 초보자가 node.js에 대한 양질의 자료, 최근 동향에 관련된 자료를 찾는 것이 매우 힘들다. 이 가이드의 목적은 정확하고 믿을 만한 최신 정보를 제공하는 것이다.

node.js의 안정버전인 node 0.4.x에 변화된 내용이 반영됐다.

자바스크립트

이 가이드는 독자가 이미 Javascript를 알고 있다고 가정한다. Javascript를 모른다면 먼저 Marijn Haverbeke가 쓴 책인 Eloquent JavaScript을 읽는 것이 좋다. 이 책은 무료다.

Hello World

이 튜토리얼에서는 node.js를 설치한 후 'hello world' http server를 만드는 방법을 설명한다.

설치.

먼저: 아직도 node.js를 사용하려면 *nix 운영체제가 필요하고 사실 Linux와 OSX를 추천한다. 하지만 FreeBSD나 윈도우의 cygwin으로도 사용할 수 있다. 윈도우용 node.js는 지금 작업중인데 아직 정식으로 공개할 단계는 아니다.

소스를 다운 받아 직접 빌드하는 것이 node.js를 설치하는 가장 일반적인 방법이다. 물론 패키지로 설치할 수도 있다. 그렇지만 아직 패키지의 업데이트 주기가 일정치 못하기 때문에 나는 직접 소스로 설치하는 것을 추천한다.

nodejs.org에서 소스를 받을 수 있다. 다음과 같은 명령어로 v0.4.4를 다운받아 설치한다:

$ wget http://nodejs.org/dist/node-v0.4.4.tar.gz
$ tar -xzf node-v0.4.4.tar.gz
$ cd node-v0.4.4.tar.gz
$ ./configure
$ sudo make install

node.js는 아주 일반적인 도구만 있으면 빌드할 수 있다. 그리고 build 시스템으로는 python을 사용한다. OSX에서는 XCode를 설치해야 하고 Ubuntu는 그냥 다음 명령을 실행하면 된다:

$ apt-get -y install build-essential

node.js 쉘 사용하기

설치를 완료하면 node.js 쉘을 사용할 수 있다:

$ node
> console.log('Hello World');
Hello World

이 쉘은 REPL이라고 부르고 간단하게 코드를 실행해보기 좋다. node.js 어플리케이션에 간단하게 바로 첨부하기도 좋다. Ctrl+C 키를 눌러서 REPL에서 나갈 수 있다.

REPL은 tab 자동완성도 지원하고 매우 편리하다.

Your first program

'.js' 파일을 만드어 nods.js 프로그램를 작성한다. 'hello_world.js' 파일을 만들고 다음과 같은 내용을 넣는다:

console.log('Hello World');

파일을 저장한 후에 터미널에서 다음과 같이 실행한다:

$ node hello.js
Hello World

hello world http server

콘솔에 'hellow world'를 출력하는 프로그램은 정말 간단하다. 웹으로 hello world를 출력하는 프로그램을 작성해보자. 다음과 같이 'hello_http.js'를 작성한후 접속한다:

var http = require('http');

var server = http.createServer(function(req, res) {
  res.writeHead(200);
  res.end('Hello Http');
});
server.listen(8080);

이제 터미널에서 실행 한다:

$ node hello_http.js

이 웹 어플리케이션이 콘솔 어플리케이션과 다른 점은 바로 종료하지 않는 다는 것이다. node 프로그램은 계속 이벤트를 기다리기 때문에 종료하지 않는다. http 서버의 경우는 주~욱 이벤트를 기다린다.

웹 브라우저로 간단하게 서버를 테스트할 수 있다. http://localhost:8080/에 접속해보자. 'Hello Http'라는 메시지를 볼 수 있을 것이다.

터미널에서도 확인할 수 있다. curl로 서버에 접속해보자:

$ curl localhost:8080
Hello Http

지금 작성한 프로그램을 좀 더 살펴보자. 우리는 첫 라인에서 http 코어 모듈을 include하고 http라는 변수에 할당 했다. 모듈 시스템에 대해서는 다음 단락에서 구체적으로 다룰 것이다.

'http.createServer'를 호출하여 server라는 변수를 만들었다. 이 함수에 넘긴 인자는 http 요청이 있을 때마다 호출할 클로저이다.

마지막으로 'server.listen(8080)'을 호출해서 열 포트를 정했다. 그러나 80 포트에 서버를 띄우고 싶다면 root권한으로 실행시켜야 한다.

이제 브라우저로 'localhost:8080'에 접속하면 클로저는 req와 res 객체를 인자로 받는다. req 객체는 읽기 전용 스트림으로 form 전송이나 파일 업로드 같이 들어오는 데이터에 읽을 수 있다. req 객체는 쓰기 전용 스트림이고 클라이언트에 데이터를 보내는데 사용한다. 이 예제는 단순히 200 OK 헤더와 'Hello Http'라는 바디를 보낸다.

모듈 시스템

node.js는 단순한 모듈 시스템을 지원하기 때문에 프로그램을 파일 여러개로 구현할 수 있다.

이를 이해하기 위해 다음과 같은 'main.js' 파일을 만들어 보자:

var hello = require('./hello');
hello.world();

이미 눈치 챘겠지만 "require('./hello')"는 다른 자바스크립트 파일을 임포트하는 것이다. './'로 시작하는 것은 파일이 'main.js'와 같은 디렉토리에 있다는 것을 말한다. 그리고 '.js' 확장자는 자동으로 추가되기 때문에 파일 확장자를 생략한다.

'hello.js'파일을 다음과 같이 만들자:

exports.world = function() {
  console.log('Hello World');
}

exports 객체의 world 프로퍼티에 할당했고 exports 객체는 모듈을 include한 파일에서 호출한 require 함수가 반환하는 객체다. 이제 'main.js' 프로그램을 실행하면 다음과 같은 결과를 볼 수 있다:

$ node main.js
Hello World

그리고 알아야 할 게 또 있다. 많은 노드 유저들은 exports 객체를 다음과 같이 overwriting한다:

module.exports = function() {
  // ...
}

벌써 눈치챈 사람들도 있겠지만 require 함수는 할당한 함수를 반환한다. 이 함수는 객체 지향 프로그래밍에서 사용하는 클래스의 생성자와 비슷하다.

그 다음 알아야 하는 것은 'require'의 용법이다. require는 포함하는 파일의 상대적 경로에 대한 정보를 가지지 않는다. 예를 들어:

var http = require('http');

node.js는 먼저 코어 모듈에 'http'라는게 있는 지 찾는다. 만약 찾았으면 그걸 바로 반환하지만 mysql같이 core 모듈이 아닌 경우는 어떨까?

var mysql = require('mysql');

node.js는 기본적으로 디렉토리 트리를 뒤진다. 부모 디렉토리로 이동해서 'node_modules'라는 디렉토리가 있는지 확인한다. 그런 폴더가 있으면 node.js는 그 폴더 안에서 'mysql.js'라는 파일을 찾는다. 만약 그런 파일이 없으면 디렉토리가 '/'에 도달할때까지 계속 부모 디렉토리로 이동한다. '/'에 도달하게 되면 예외가 발생한다.

'require.paths'라는 변수도 있어서 이 배열에 등록된 경로에서도 파일을 찾을 찾는다. 이 배열은 런타임에도 변경할 수 있지만 곧 없어질 테니 못 본척하는게 좋다.

마지막으로 디렉토리 대표 파일인 'index.js'도 찾는다. require('./foo')라고 호출하면 'foo.js'라는 파일과 'foo/index.js'라는 파일을 모두 찾는다.

EventEmitter 사용하기.

node.js는 EventEmitter라는 클래스로 옵저버 패턴을 구현했다. node.js는 새로운 이벤트가 필요할 때마다 EventEmitter를 상속한 클랙스를 만든다.

EventEmitter는 사용하기 쉽다. on함수를 호출하여 특정 이벤트를 처리listen할 수 있다. 이벤트의 이름과 callback 클로저를 on함수의 인자로 넘긴다. 예를 들어:

var data = '';
req
  .on('data', function(chunk) {
    data += chunk;
  })
  .on('end', function() {
    console.log('POST data: %s', data);
  })

'on()'함수는 객체의 레퍼런스를 반환하기 때문에 이벤트 리스너의 체인을 만들 수 있다.

만약 이벤트를 한 번만 처리하고 싶을 때에는 'once()'함수를 사용하면 편리하다.

마지막으로 removeListener 함수를 호출하여 이벤트 리스너를 제거할 수 있다. 이 함수를 이벤트 이름이 아니라 콜백 함수의 레퍼런스를 인자로 받는다.

var onData = function(chunk) {
  console.log(chunk);
  req.removeListener(onData);
}

req.on('data', onData);

이 예제는 once()를 사용한 것과 완전히 똑같다.

Next Steps

이제 node.js의 기본을 다졌으니 혼자서도 작은 프로그램정도는 만들 수 있을 것이다. 신나는 놀이동산같은 node의 api문서를 참고하는 것이 좋다.

node.js 앱을 디버깅하기

node.js 어플리케이션을 디버깅하는 방법은 굉장히 다양하지만 나는 test driven development guide를 엄격하게 지키는 방법을 좋아한다.

어쨌든 어플리케이션의 버그를 찾는 기술을 스스로 터득해야 하는 것이다. 여기에서는 단지 몇 가지 방법을 간단하게 소개할 뿐이다.

console.log() 사용하기

console.log()를 사용하여 객체를 inspect하는 것이 가장 쉽다. 단순히 인자로 객체를 넘기면 된다:

var foo = {bar: 'foobar'};
console.log(foo);

출력를 정열format하기 위해 sprintf처럼 사용할 수도 있다.

var foo = {bar: 'foobar'};
console.log('Hello %s, this is my object: %j', 'World', foo);

node 디버거 사용하기.

console.log()을 사용하는 것이 맘에 들지 않을 수도 있고 어떤 문제는 breakpoint를 사용하는 것이 좋을 수도 있다. node에 포함돼 있는 디버거를 바로 호출해서 사용할 수 있다:

$ node.js debug my_file.js

Work in progress, please come back later ...

Using the WebKit Inspector

Work in progress, please come back later ...

Frameworks

node.js를 배우는 중이라고 해도 POST 리퀘스트를 파싱하고, url을 처리하고, 뷰를 렌더링하는 것들을 만들고 싶지는 않을 것이다. 우리는 좋은 웹 프레임워크가 필요하다. 이 단락에서는 사람들이 많이 사용하는 프레임워크를 소개한다.

Express

express는 node.js 프레임워크 선수진들 중에서 주전 프레임워크라고 할 수 있다. 상대적으로 성숙돼있고 connect 기반으로 돼 있다. 이 프레임워크에는 라우팅, 설정, 템플릿 엔진, POST 리퀘스트 파싱 등등의 기능이 구현돼 있다.

express는 프레임워크가 갖추어야 할 요소를 모두 지원하지만 Rails, CakePHP, Django같은 풀스택 프레임워크라기엔 부족하다. express는 Sinatra랑 좀 더 유사하다. 그리고 Ruby에 뿌리를 두고 있는데 자바스크립트에 적합하도록 자바스크립트에 맞출 것 같지 않다. 어쨌든 직접 프레임워크를 작성하는 것에 비하면 너무 좋다.

fab.js

자신이 자바스크립트를 좀 씹는 다고 생각한다고 다시 생각해봐야 한다. 원래jQuery의 chaining에서 영향을 받았다. fab.js는 자바스크립트를 뒤틀는 매우 낮설은 방식이기 때문에 머리가 터질지도 모른다. 각 함수는 다른 함수를 반환한다. lisp이 하는 것처럼 코드를 반환하기 때문에 메소드 이름이 전혀 필요없다.

fab.js가 완벽해지길 기다리지 마라. node.js라는 칼을 뽑았다면 적어도 한번은 fab.js를 썰어볼 필요가 있다. fab.js는 자바스크립트가 Ruby, Python, PHP등의 프레임워크들을 따라한 것이 아니라 독자적인 철학을 가지고 있음을 보여준다.

Hosting & Deployment

쉽지만 아쉬운 Deployment

이제 node.js 어플리케이션을 만들었으면 가능한 빨리 실행해보고 싶을 것이다. 여기에서는 그 방법을 설명한다.

  1. 프로그램을 실행시킬 서버로 복사한다. 만약 git을 사용하고 있으면 레파지토리가 있는 서버나 GitHub같은 서비스에서 그냥 다른 서버로 clone하면 된다.

  2. 프로그램이 server.js 파일이라면 그 파일이 있는 디렉토리로 이동해서 다음과 같이 실행한다:

    $ screen
    $ node server.js
    

Screen 세션에서 'server.js' 프로그램을 실행했다. Screen은 쉘에서 로그인한 터미널을 닫아도 프로그램이 계속 실행되도록 해주는 프로그램이다.

이제 터미널 앱을 닫아도 안전하다. 'server.js'는 계속 실행되고 있다. 만약 실행중인 프로그램을 다시 보고 싶으면 서버로 다시 로그인해서 다음과 같은 명령을 실행한다:

$ screen -r

이 명령은 백그라운드에서 프로그램이 실행되고 있는 쉘과 다시 연결시켜준다.

그러나 이 방법은 오직 개발 중에만 사용한다. 이 것은 node 어플리케이션이 죽어버려도 다시 살려 주지 않는다. 그래서 실 운영 환경에서 이렇게 하는 것은 별로다.

Joyent no.de

Work in progress, please come back later ...