Node.js | Express Web 어플리케이션 자동 생성

Express에는 Web 어플리케이션을 자동 생성하는 편리한 기능이 있다. 이것을 사용하여 빠른 개발에 대해 설명한다.

express-generator 설치

지난번 Express를 이용한 Web 어플리케이션의 극히 초보적인 것을 만들었다. 그래서 “결국, 모든 파일을 직접 만드는 것이 별로 유용하지 않다"고 느낄지도 모른다.

Express 생성 프로그램 설치

우선 “기본부터"라고 하여 최소한의 파일을 만들어 동작시켰지만, 사실은 그렇게 하지 않아도 Express의 Web 응용 프로그램은 만들 수 있다. Express에는 Web 응용 프로그램의 기본 파일을 자동 생성하는 기능이 있어서 이를 사용하면 Web 응용 프로그램 작성을 거의 자동화 할 수 있다.

그러기 위해서는, express-generator의 준비가 되어 있어야 한다. 지난번 간단히 언급했지만 Express는 ver.3에러 ver. 4.7로 업데이트되면서 패키지가 바뀌었다. 아마도 대부분은

$ npm install -g express

이러한 식으로 설치되어 있다고 생각된다. 그래도 현시점에서는 문제가 없지만, ver.4가 출시됨에 따라 자동 생성 기능은 Express Generator라는 프로그램에 분리되었다. 다음과 같이 패키지를 설치한다.

$ npm install -g express-generator

이것으로 ver. 4 이후의 응용 프로그램 생성 기능을 사용할 수 있다.

Express 명령으로 Web 어플리케이션 생성

그럼 Web 응용 프로그램을 만들 수 본다. 아래 순서대로 작업한다.

  1. 설치 폴더 만든다.
    먼저 Web 응용 프로그램 폴더를 어딘가에서 준비한다. 여기에서는 적당한 곳에 “exapp"라는 폴더를 만들어 둔다. 이 안에 Express의 Web 응용 프로그램을 작성해 나갈 것이다.

  2. 명령 프롬프트으로 작업 폴더로 이동한다.
    명령 프롬프트(Mac OS X의 터미널)을 시작하고 만든 작업 폴더(여기에서는 “exapp"폴더)가 있는 곳으로 cd 명령 사용하여 이동한다. 예를 들어, 특정 폴더에 “exapp"폴더가 있다면,

$ cd [특정 폴더]

이렇게 하면 된다. 주의할 점은 “exapp 폴더 안으로 이동하면 안된다"는 점이다. 즉, “cd [해당 폴더]\exapp"이렇게 하면 된다. exapp이 있는 상위 폴더로 이동한다.

  1. Express 명령을 실행한다.
    그럼 Express 명령으로 Web 애플리케이션을 생성한다. 이는 “express 폴더명과 같은 실행한다. 단, 이렇게 하면 템플릿 엔진에 “jade"라는 것이 설정된다. 아무튼, 이대로 라도 괜찮지만(또한, jade는 템플릿 엔진을 기억하면 된다), 아무래 이미 사용 경험이 있는 EJS을 사용하여 만드는 것이 편할 것이다.

EJS을 템플릿 엔진으로 설정하는 경우에는 “-e"옵션을 지정하고, “express -e 폴더명"과 같이 실행한다. 여기에서 예를 들면, “exapp"폴더에 파일을 생성할 것이기에,

$ express -e exapp

이와 같이 실행한다. 이것으로 필요한 파일들이 “exapp"폴더에 만들어 졌다. “-e"를 붙이지 않으면 생성되는 템플릿 파일 등이 달라지므로 주의해야 한다.

  1. npm install을 실행한다.
    이것으로 끝이 아니다. 이어서 cd 폴더명 && npm install명령을 실행한다. 여기에서 예를 들자면, 다음과 같이 실행한다.
cd exapp && npm install

디렉터리 이동하는 명령인 cd로 “exapp 폴더로 이동하고, npm install을 실행하는 작업을 하고 있다. 그렇지 않으면, 필요한 파일들이 모이지 않기 때문에, 배포 시에 응용 프로그램이 잘 동작하지 않는다.

이것으로 Web 응용 프로그램은 완성되었다!

Web 어플리케이션 구성

그럼 만든 Web 응용 프로그램의 구성을 살펴보자. 설치한 폴더(여기서는 “exapp"폴더) 안에는 다음과 같은 파일과 폴더가 만들어지고 있다.

bin 폴더

실행하는 프로그램이 저장되어 있는 곳이다. 이 폴더에는 ‘www’라는 파일이 하나 있다. 이 응용 프로그램의 실행 스크립트 파일이다.

node_modules 폴더

Node.js에서 사용하는 모듈(Express 등 각종 프로그램과 거기에 필요한 파일)들이 모두 여기에 정리되어 있다. 사용자가 이 안에 있는 파일을 조작할 은은 거의 없다.

public 폴더

이 폴더은 공개 파일을 설치하는 곳이다. 예를 들어, 이미지 파일 및 JavaScript 라이브러리, 스타일시트 파일 등을 여기에 정리한다. 여기에 배치하면 Express에서 사용할 수 있다.

routes 폴더

여기에 있는 파일들은 각각의 Web 페이지에서 처리할 스크립트 파일들이다. Express가 생성한 Web 어플리케이션에서는 스크립트 관련의 주요 처리 부분과 개별 페이지의 처리가 별도의 폴더로 나누어져 있다. 여기에는 각각의 페이지 처리가 보관되어 있다.

views 폴더

여기는 앞전에 설명했듯이, 페이지 템플릿 파일들을 정리된다. 화면 표시를 위한 필요한 파일들이 모두 이 안에 준비된다.

app.js 파일

이 파일은 메인 프로그램이 되는 스크립트 파일이다. Node.js으로 프로그램을 실행할 때에 이 파일은 지정하지 않는다. 앞전에 bin 폴더에 있는 www에서 app.js를 호출 실행한다.

package.json 파일

이 파일도 앞전에 설명했다. Web 어플리케이션의 패키지 정보를 기술한 파일이다.

 

대략 전체의 구성을 정리되었다. 이를 바탕으로 Web 어플리케이션을 작성하는 경우에는 “app.js에서 메인 프로그램 수정”, “routes에 만드는 페이지의 스크립트 파일을 준비”, “views에 표시용 템플릿 파일을 준비"와 같은 흐름으로 만들어 가면 된다.

조금 이해하기 어려운 것은 bin 폴더에 있는 www와 app.js의 차이이다. Express Application Generator로 생성되는 프로그램은, 어플리케이션의 기동 스크립트 및 메인 스크립트가 나뉘고 있다. www는 프로그램을 시작하기 위한 스크립트이고, app.js이 응용 프로그램의 메인 프로그램이다.

흐름을 알게 되면, 명령 프롬프트에서 “exapp"폴더로 이동하여 다음과 같이 실행한다.

$ node .\bin\www

이걸로 서버 프로그램이 실행된다. 브라우저에서 http://localhost:3000 에 액세스하면 간단한 페이지가 표시된다. Express으로 자동 생성한 Web 어플리케이션은 디폴트로 포트 번호 3000이 지정되기 때문에 주의하도록 한다.

메인 프로그램 app.js

그럼 작성된 Web 응용 프로그램을 살펴 보자.

메인 프로그램 “app.js"에 대해

우선 메인 프로그램인 app.js부터 보도록 하겠다. 파일 내용은 아래와 같다.

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
 
var routes = require('./routes/index');
var users = require('./routes/users');
 
var app = express();
 
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
 
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
 
app.use('/', routes);
app.use('/users', users);
 
// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});
 
// error handlers
 
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}
 
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});
 
module.exports = app;

포인트를 골라서 설명해 나가도록 하겠다.

1. 라이브러리 로드

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

먼저 수행하는 것은 라이브러리 로드이다. 각종 라이브러리를 로드하고 다음과 같은 변수에 저장한다.

변수 설명
express Express 객체의 변수이다.
path Path 객체이다.
serve-favicon favicon (Web 페이지에 표시되는 아이콘 데이터)에 관한 것이다.
morgan 로그 출력에 대한 객체이다.
cookie-parser 쿠키 이용에 관한 객체이다.
bodyParser 바디 부분의 파싱과 관련된 객체이다.
routes routes 폴더에 설치되어 있는 index.js의 객체이다. 이 내용은 나중에 설명하겠다.
user routes 폴더에 설치되어있는 user.js의 개체입니다. 이것도 나중에 설명하겠다.

마지막 2개는 모듈이 아닌 어플리케이션에 포함되어 있는 스크립트 파일을 로드하는 것이다. require으로, 이런 식으로 다른 스크립트를 로드할 수 있다.

충분히 다양한 모듈이 로드되어 있지만, 사실은 로드되는 것은 이뿐만이 아니다. 어플리케이션을 기동하기 위한 www에 다음과 같은 문장이 작성되어 있다.

var app = require('../app');
var debug = require('debug')('exapp:server');
var http = require('http');

이것으로 이 app.js 스크립트 디버깅에 대한 개체, 그리고 http 객체가 제공된다. 이 모든 것이 갖추어져 어플리케이션을 구축하고 있다.

2. express 함수로 Application 만들기

var app = express();

express 함수로 Application 개체를 만든다. 이것은 이전과 동일하다.

3. 각종 어플리케이션 설정하기

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

다음에는 app.set ~app.use ~ 와 같은 코드가 정렬되어 있는데, 이것은 각종 어플리케이션의 설정을 수행하고있는 부분이다. 이들은 우선 사용자가 이를 편집하는 일은 없을 것이다. 작성을 변경되거나 하지 않도록 주의하자.

4. get으로 루트 설정하기

app.use('/', routes);
app.use('/users', users);

get으로 ‘/‘와 ‘/users’ 주소에 각각 routes과 users 변수를 설정하고 있다. 이 routes 및 users 변수는 이전에 나온 것이다. routes 폴더에 있는 index.js와 users.js을 각각 require으로 로드한 것을 얻은 변수였다.

이러한 변수를 use로 설정하여, 지정된 주소에 스크립트를 할당하고 있다. 즉, ‘/‘에 액세스가 있으면 routes 안에 index.js가, ‘/users’에 액세스가 있으면 users.js가 각각 실행되도록 되는 것이다.

5. 에러 처리 설정

app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

app.use, if문 또한 app.use 계속되지만, 이러한 에러에 대한 처리를 수행하는 것이다. 이것도, 특별히 사용자가 만질 부분은 없다. 우선 잊어도 되는 부분이다.

6. 어플리케이션을 설정하기

module.exports = app;

마지막으로 만든 app 객체를 module.exports에 대입한다. 이것으로 어플리케이션이 설치되어 동작하게 된다.

도중에 갑자기 어려워 보이는 처리가 나와하기도 했지만, 모든 이해할 필요는 없다. 전체의 흐름으로써, 대충 “이런 식으로 처리가 되어 있구나” 정도로 파악할 수 있으면 그것으로 충분하다.

routes 스크립트 및 템플릿

이어서 표시하는 Web 페이지의 처리를 보고 가자. Web 페이지는 routes 안에 스크립트와 views 안에 템플릿을 준비하여 양자의 조합으로 만들어 진다. 여기에서는 /index로 표시되는 페이지를 구성하는 routes 안에 index.js와 views의 index.ejs의 내용을 살펴 보자. (아래와 코드 참조)

routes/index.js

var express = require('express');
var router = express.Router();
 
/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});
 
module.exports = router;

views/index.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>

express 라이브러리 로드

var express = require('express');

여기에 필요한 express 라이브러리를 로드한다. 이는 app.js에 대해 설명 시에도 등장 했다. Express 객체이다.

Router 객체의 준비

var router = express.Router();

express의 “Router"메소드를 호출한다. 이것으로 라우팅(URL과 그것을 호출하는 처리와 연관 얻을 수있는 것)에 대한 객체를 만든다.

GET으로 루트 정보를 설정하기

router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

Router에도 app.js의 express 객체와 마찬가지로 get 메소드가 준비되어 있다. 이것으로 URL 경로에 함수를 설정한다. 이것으로 지정된 주소에 액세스가 있으면 설정한 함수를 호출하여 실행하게 된다.

여기에서 render 메소드를 호출하여 index의 템플릿을 렌더링한다.

exports에 router를 설정

module.exports = router;

마지막으로, module.exports에 router 객체를 사용하고 작업 완료이다. app.js에서 마지막으로 module.exports = app;을 수행하고 있던 것과 같은 거다.

이상, 정리하면 “Router 작성”, “get에 의한 경로 설정”, “module.exports에 router 설정"이라는 흐름에서 라우팅이 이루어지고 있었다. 여기에서는 index에 대해 조사했지만, 기본적으로는 모두 같은 방식으로 라우팅을 설정한다. 라우팅을 위한 스크립트는 자신의 새로운 페이지를 추가하여 준비해야 하기에, 작성법의 기본은 제대로 기억해 두도록 한다.

새로운 페이지 작성

그럼, 이 기본적인 구조를 사용하여 새 페이지를 만들어 보자. 이번에는 /helo를 접근하여 표시되는 페이지를 만들려고 한다. 필요한 것을 정리한다.

routes 안에 helo.js

/helo의 처리를 기술하는 스크립트 파일로, routes 폴더 안에 helo.js 파일을 작성한다.

var express = require('express');
var router = express.Router();
 
/* GET helo page. */
router.get('/', function(req, res, next) {
    res.render('helo', {
        title: 'Helo',
        data: {
            '성진':'sungjin@foryou',
            '원석':'wonsuck@flower',
            '병호':'byeongho@devkuma.com'
        }
    });
});
 
module.exports = router;

이 중에 router.get으로 ‘/‘렌더링하는 처리를 설정해 두었다. 그리고 간단한 샘플로 title와 data를 템플릿에 전달하여 처리하도록 하고 있다.

views 안에 helo.ejs

/helo으로 표시되는 템플릿 파일이다.

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <table>
    <% for(var key in data){ %>
        <tr><td><%= key %></td>
        <td><%= data[key] %></td></tr>
    <% } %>
    </table>
  </body>
</html>

여기에서는 <%= title %>으로 title을 출력하는 문장과 변수 data 안에 키와 값을 <table>에 정리하여 출력하는 문장을 기술하고 있다.

app.js

메인 프로그램인 app.js 파일이다.

var helo = require('./routes/helo');
 
app.use('/helo', helo);

이 안에는 helo = require('./routes/helo')으로 helo.js의 exports를 변수 helo에 대입하고, app.use('/helo', helo);으로 /helo 액세스 처리를 helo 객체의 helo 메소드로 설정하고 있다.

public의 stylesheets 폴더 안에 style.css

마지막으로 <table> 스타일 시트를 추가한다. 스타일시트는 “public"의 “stylesheets"폴더에 저장된다.

table tr td{
    background-color:#eeeeff;
    padding: 3px;
}

이 안에 ‘style.css’를 열고, <table>의 스타일을 기술해 두면 된다.


대충 편집이 끝나면, Node.js에서 app.js를 실행하고, http://localhost:3000/helo에 방문해 본다. 만든 페이지가 제대로 표시되는지 확인한다.




최종 수정 : 2018-07-16