Angular MEAN Stack 설정 다시 정리 : 서버 사이드 랜더링 미루자.

Angular의 SEO 문제 때문에, 최근 일주일 Angular Universal 이나 SSR (Server Side Rendering) 에 관한 starter 들을 들여다보고 있었다. starter 들을 분석하고 이해가 가능해야 사용해볼 수 있는데, 웹프로그래밍 공부를시작한지 겨우 6개월된 나로써는 역부족이라는 판단을 했다. 억지로 따라하면, 작동이야 시키겠지만 자유롭게 활용할 수 없다면 차라리 워드프레스가 나으리라. 그래서 훗날을 기약한다. 6개월즈음 더 지나면 왠만큼 이해하고 활용할 수 있을 것으로 기대해본다.

Angular Universal 또는 SSR 을 잠시 미루어두기로 한 또 하나의 이유가 있다. 검색되는 universal starter 들의 업데이트 상황을 살펴보니, 그리 활발하지가 않다. 6~7개월 전에 업데이트 되고 손대지 않은 것들이 대부분이다. universal cli 도 방치된지 꽤 되었다. (간혹, ngx-universal 의 최신버전을 이용한 starter들이 없지는 않았지만, 드물었고 아직 개발중인 상태였다.) Angular가 버전 2와 3를 거쳐 4까지 왔는데도, 이 쪽 상황이 그런 것이 좀 이상해서, 그 이유를 곰곰히 생각해보았다.

Angular 코어의 버전업이 급속하게 되는 상황에서 그 지류에 있는 Universal을 건드려보아야 곧 쓸모없어질 가능성이 있다. 열심히해서 코어의 버전업 속도를 따라가야 지류에 있는 패키지들이생명을 유지할 터인데, 그러기에는 도저히 감당이 안되는 것이라고 나름대로 결론을 내렸다.  개발자들에게 동기부여가 되지 않은 듯 하다. 그래서, 좀 더 지켜보다가 어느정도 정착이 되고 표준화가 이루어지면 그때 다시 공부하는 것이 좋으리라.

다시 Angular MEAN Stack

Angular Universal starter 들을 살펴보는 중에, 우연히 Angular MEAN 스택을 위한 starter 를 하나 만났다. Angular cli 에 기초한 것이고 구성이 간단해서, 분석해보고 말고 할 것도 없이 바로 활용이 가능했다. 예전에 나는 Angular cli 를 4200번에 물리고 node 를 3000번 포트에 물려서 크로스 플랫폼 구성으로 테스트를 해왔었는데, 여간 불편한 것이 아니었다. 새로 만난 이 스타터를 활용하면 Angular 를 가지고 노는 일이 조금 더 간편하고 재미있어질 듯 하다.

일단 이 MEAN Stack Starter 가 어떤씩으로 구성되었는지 간단히 역분석해서 정리해놓았다. 혹시, 선생님도 없이 나처럼 혼자 웹프로그래밍을 가지고 노는 외로운 학생이 있다면, 조금 도움이 되었으면 좋겠다.

첫번째 단계, angular cli 를 이용해 새 프로젝트를 만들기

& ng new mean-starter --style=scss

ng new 명령을 사용해 프로젝트를 생성하면서 옵션에 css 대신 sass를 기본으로 사용하겠다고 정의해주었다. 이때, Angular cli 가 기본적인 node module들을 모두 설치해주기 때문에 npm install 을 초기 실행할 필요는 없다.

두번째 단계, 추가 패키지 설치

이 MEAN Stack Starter 가 사용하는 몇가지 추가 패키지들을 설치해주어야한다.

$ npm install --save-dev concurrently nodemon

concurrently 은 package.json 의 scripts 항목에 들어가는 실행명령에 사용되었다. 원래 angular cli 의 기본 패키지는 아니다. nodemon 은 실시간으로 변경내용을 서버에 반영하는 패키지다. (npm run dev 에서 필요하다.)

$ npm install --save angular2-jwt bcryptjs body-parser dotenv express jquery jsonwebtoken mongoose morgan

위 패키지들은 angular2-jwt를 제외하고는 node server 에 필요한 것들이다.

  • angular2-jwt : 토큰 기반의 Authentication 을 가능하게 하는 패키지(client side 용)
  • bcryptjs : 암호화 기능을 담당하는 패키지
  • body-parser : 이건 설명이 필요없을 듯.
  • dotenv : 프로젝트 루트에 .env 라는 파일을 읽어들여서 환경설정변수를 활용할 수 있도록 하는 패키지다.
    >.env 파일에는 다음과 같이 설정이 들어가 있다.
    
    MONGODB_URI=mongodb://localhost:27017/test
    SECRET_TOKEN=catswillruletheworld

     

  • express: 설명 생략
  • jsonwebtoken : 토큰 기반의 Authentication 을 가능하게 하는 패키지(server side 용)
  • mongoose : 데이타베이스 ( 이 starter 에서 4.11 이상 버전을 설치하면 이상한 오류가 뜨는데 그럴때는 버전 다운하면 해결된다. 일종의 버그라고 하는데 놔둬도 작동에는 별 지장이 없는 것 같다. – DeprecationWarning: `open()` is deprecated in mongoose)
  • morgan : html request 상황을 콘솔창에 보여주거나 파일로 저장할 수 있도록하는 로거 logger 패키지다. 설치하면 작동 상황을 한눈에 파악할 수 있어서 좋다. 안해도 그만.
$ npm install --save font-awesome bootstrap@next ngx-bootstrap@next jquery thether

MEAN Stack Starter 의 기본 테마에서 font-awesome 과 bootstrap이 사용되었다. bootstrap 4 가 사용되었기 때문에 @next를 꼭 붙여서 설치해야한다. 안하면 버전 3가 설치된다. thether와 jquery 는 bootstrap 에 필요하다.

ngx-bootstrap은 원래 이 starter의 저자가 사용하진 않았지만, 내가 임의로 추가했다. jquery를 사용하지 않고 bootstrap 기능을 angular 에서 활용할 수 있도록 도와주는 패키지다. jquery 는 angular native 보다 크게는 20배 가량 속도가 느리다고 한다. 또한, SSR(Server Side Rendering) 에서 예기치 않은 문제를 일으키기도 한다니 되도록 사용하지 않는 편이 좋겠다.

다음 패키지들은 모두 원래 starter 에는 없지만, 내가 추가로 설치한 것이다.

$ npm install --save angular-2-local-storage ng2-cookies validator
  • angular-2-local-storage
  • ng2-cookies
  • validator

원래 starter 에서는 따로 localStorage 패키지를 설치하지않고 native localStorage를 사용했다. 그런데, 이렇게 하면 나중에 SSR(Server Side Rendering)을 해야할 때 문제가 발생한다. server 에서는 client 에 있는 localStorage 에 직접 접근할 수 없기때문이다. set(….)은 먹히는데, get(…)이 안먹힌다. 그래서, 이것을 가능하게 해주는 패키지를 설치해서 사용하는 습관을 들이는 것이 나중을 위해 좋다. angular-2-local-storage 가 그 기능을 한다. 비슷한 기능을 하는 패키지는 여럿있지만, AoT SSR을 지원하는 패키지는 많지 않다.

ng2-cookies 는 쿠키를 사용할 수 있도록 해주는 패키지다. 쿠키 사용도 SSR에서 직접 서버측에서 컨트롤 할 수 없으므로, 따로 기능을 구현해주는 패키지가 필요하다. 사용법이 간단하니 npm  사이트에서 검색해서 읽어보면 1분만에 이해하고 금방 사용할 수 있다. 그런데, 이 패키지는 값을 Object로만 가져온다. 다른 비슷한 패키지들이 저장값의 형식에 따라 몇가지 set() get() 메서드를 가지고 있는 반면, 이건 묻지도 따지지도 않고 Object를 반환한다. 그래서 get 메서드를 사용할 때 원하는 형식으로 캐스팅을 해주어야하는 불편함이 있다.

validator 는 말 그대로 폼 입력값의 유효성을 검사하는 패키지이다. 필요한 경우에만 설치하면 된다.

기본 폴더 설정

원래 angular cli 는 src 폴더 안에서 놀아야한다. 우리가 만든 컴포넌트 들이 모두 그 속에 저장된다. 그런데, 이 Mean 스택 스타터에는 src 폴더가 없다. 분명 angular cli 에 기초해서 만든 스타터인데 어떻게 된 일일까? 대신 뚱단지 같이 client 폴더와 server 폴더가 보인다.

이런 폴더 설정은 어디서 한 것일까? 궁금증이 일어서 angular cli 속에 있는 파일들을 하나 하나 뜯어보았다.

angular client 측의 폴더 설정

tsconfig.json

...
"baseUrl": "client",
...

angular-cli.json

.......
  "apps": [
    {
      "root": "client",
      "outDir": "dist/public",
.......
      "styles": [
        "assets/bootstrap/compiled/bootstrap.css",
        "../node_modules/font-awesome/css/font-awesome.min.css",
        "styles.scss"
      ],
      "scripts": [
        "../node_modules/jquery/dist/jquery.min.js",
        "../node_modules/tether/dist/js/tether.min.js",
        "../node_modules/bootstrap/dist/js/bootstrap.min.js"
      ],
...........
  "lint": [
    {
      "project": "client/tsconfig.app.json"
    },
    {
      "project": "client/tsconfig.spec.json"
    },
    {
      "project": "e2e/tsconfig.e2e.json"
    }
 .....

이렇게 설정한 후에 src 폴더를 지우고 client 폴더를 만들어준다. src 가 client 로 바뀐 것이다. 어느 폴더를 기본폴더로 하고 컴파일시에 어디로 보낼지에 대한 정보가 위 파일들에 들어가 있는 거다.

server 폴더 만들고 설정파일 만들기

angular cli 가 자동으로 설정한 폴더들은 모두 client 측을 위한 것이다. 그런데, MEAN Stack 은 서버를 같이 연동한다. 원래 없었으니 일단 프로젝트 루트에 server 폴더를 만들어주자.

그럼 이 폴더를 컴파일할 때 어떻게 해야하지? 아무런 정보가 주어져있지 않으니, 우리가 만들어주면 된다.

> server/tsconfig.json

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../dist/server",
    "baseUrl": "",
    "module": "commonjs"
  }
}

 

server 와 client 포트 일치시키기

프록시 세팅을 이용한다. 설정파일은 프로젝트 루트에

proxy.conf.json

{
  "/api": {
    "target": "http://localhost:3000",
    "secure": false
  }
}

 

컴파일하고 실행

위에서는 폴더 설정을 살펴보았다. 그런데, 컴파일 및 실행 명령을 어떻게 내려야할까? 컴파일을 어떤 식으로 어떤 순서와 형태로 해야할 지를 설정해주는 부분은 package.json 파일의 scripts 부분이다. 이 Starter 에서는 다음과 같은 scripts 들이 설정되어 있었다.

"scripts": {
  "ng": "ng",
  "build": "ng build",
  "start": "node dist/server/app.js",
  "predev": "tsc -p server",
  "dev": "concurrently \"mongod\" \"ng serve -pc proxy.conf.json --open\" \"tsc -w -p server\" \"nodemon dist/server/app.js\"",
  "prod": "concurrently \"mongod\" \"ng build -aot -prod && tsc -p server && node dist/server/app.js\"",
  "test": "ng test",
  "lint": "ng lint",
  "lintbe": "tslint server/**/**.ts{,x}",
  "e2e": "ng e2e"
},

컴포넌트들을 다 배치하고 노드서버의 api 노드를 다 만들고 나서, npm run prod 라고 명령프롬프트에서 치면된다. 컴파일과 실행이 모두 이루어지게 설정되어있다.

컴파일만 하려면 npm run build, 실행만 하려면 npm run start… 뭐 그런씩이다.

나머지

server 와 client 폴더 안에 각각에 필요한 파일들이 다 들어가 있다. 코딩도 깔끔하고 구성도 좋다. angular 와 nodejs 를 좀 안다면 Start를 조금만 더 들여다보면 나머지 구성은 금방 파악할 수 있을 것이다. 초보자들에게는 좋은 공부가 될 수 있는 코딩들이다.

댓글 남기기