지난 밤 이상한모임에선 이모콘이란 이름 하에 온라인 컨퍼런스를 개최하였습니다. 그 중에 @nipol님께서 JSPM으로 시작하는 Systemjs라는 발표를 하셨고, 채팅창은 혼란에 빠졌습니다. 발표 내용이 무슨 소린지 이해할 수 없다는 평이었는데, 사실 그럴 수 밖에 없었습니다. Front-end 개발 방법이 시간이 흐름에 따라 아예 바뀌어버렸으니까요.

이 글은 (제가 아는 한도 내에서) Front-end 개발이 어떻게 바뀌었고, @nipol님의 발표는 무슨 의미인 것인지 해석을 해보고자 합니다.

Front-end?.

이 용어 자체가 생소하신 분도 있으실 거라 봅니다. 대체적으로 HTML, CSS, (Client Side) JavaScript를 의미합니다. 즉, 웹 브라우저에서 이뤄지는 작업을 말합니다.

옛날 옛적에.

DHTML 전쟁이 있었습니다. 그 과정에서 정말 이상한 것들이 생겼다가 사라졌죠. 그 전쟁의 승자는 Internet Explorer이었고, 현재도 한국에서 군림하고 있죠.

Table based layout.

CSS로 디자인을 한다는 개념이 보급되기 전에는 웹 페이지를 딱 정해진 사이즈로 출력해서 보여줄 방법이 마땅치 않았기 때문에 <table> 태그로 구조를 잡았습니다.

이 당시의 CSS, JavaScript는 정말 신기한 존재로써, 대부분의 개발자가 “외계의 어느 누군가가 만들어 놓은 것을 퍼다가 쓰는 것” 이라고 여겼습니다.

XHTML과 Ajax.

하지만 <table>은 레이아웃을 잡으라고 있는 태그가 아니었습니다. 이에 불만을 품은 개발자들이 <div> 태그와 CSS를 사용해서 레이아웃을 잡기 시작했죠. 이때 널리 쓰인 HTML 표준이 XHTML입니다. 적어도 HTML 4.01보다는 제정신이었거든요.

그리고 구글에서 Ajax라는 것을 선보여서1 다들 그걸 쓰고 싶어했습니다. 이때부터 사람들이 CSS와 JavaScript를 직접 손대야한다는걸 인지하기 시작한 것 같습니다.

jQuery.

하지만 당시 웹 브라우저 현황은 끔찍했습니다. 구버전 브라우저에서도 잘 돌아가는 사이트를 만들기 위해서는 너무 복잡한 과정이 필요했죠. 특히나 Ajax를 쓰기 위한 과정은 너무나도 다르고, 그걸 직접 만지기 위해서는 너무나도 피곤했죠.

그 과정에서 여러 라이브러리가 생겨났다가 잊혀졌고, 승자는 jQuery가 되었습니다. jQuery는 편한 API로 누구나 쉽게 쓸 수 있게 되어있었고, 그마저도 많은 개발자들이 붙어서 여러가지 플러그인을 만들어서 사용자는 플러그인들을 마음대로 퍼다가 쓰면 되게 되었습니다.

의존성 지옥.

하지만 플러그인을 집어다 쓰다보니 문제점이 생겨나게 됩니다. 서로간에 의존성이 있어서, 가져다 붙이는데에 순서가 중요해진 것입니다.

예를 들어서 Bootstrap을 가져다 붙인다고 치면 의존성 순서는 다음과 같이 될 것입니다.

  1. jQuery
  2. Bootstrap
  3. 나머지 직접 짠 소스들

Bootstrap은 jQuery에 의존성이 있습니다. 만약 여기다가 jQuery-ui 등등을 더 가져다가 붙이면 어떻게 될까요? 플러그인이 한 5개만 되더라도 의존성을 표현하는 것이 매우 피곤해질 것입니다.

Bower.

이런 상황에서 브라우저가 아닌 환경에서 JavaScript를 실행할 수 있게 됩니다. 여러분이 알고 있는 Node.js가 바로 그것이죠. 그리고 그것을 바탕으로 JavaScript를 할 줄 알던 개발자들이 조금 더 제정신으로 JavaScript 의존성을 관리해보자며 만들어낸 것이 Bower입니다.

Bower

Bower는 Front-end에서 사용하는 것들의 의존성을 설치해주는, 나름대로 착한 의도를 가진 프로그램이었죠.

저 새는 해로운 새다.

하지만 Bower는 다운로드만 해줄 뿐 의존성 지옥에서 구원해주진 못했습니다. 별도의 파일이 생겨서 따로 관리를 해줘야 하는 점, bower_components를 서버에 올려야 하는 등 귀찮음을 더 증폭시켜주었습니다. @nipol님이 Bower가 싫다고 하신건 그런 연유에서죠.

해로운 새

그냥 npm을 쓰는 것이 더 좋은 지경이 되었고, 지금 실제로도 그러합니다.

less, Sass, Coffee.

이 와중에 CSS와 JavaScript를 좀 더 편하게 써보고자 하는 시도는 더 늘어갔습니다. node 진영의 less, ruby 진영의 sass같은 CSS의 super-set 언어도 나왔고, CoffeeScript같은 언어도 나왔죠.

이런것들까지 섞이다보니 의존성 지옥은 더 심각해져갔습니다.

그래서, JSPM.

이 문제를 해결해주는 솔루션으로 이번 발표에선 JSPM이 소개되었습니다. JSPM은 SystemJS 기반으로 의존성 관리를 해줍니다.

여기부터는 실제 발표를 따라가보겠습니다. 따라하기 위해서는 Node.js가 필요합니다.

설치.

일단 jspm을 설치합니다.

$ npm install -g jspm

그리고 실습을 해볼 디렉토리를 만듭시다.

$ mkdir drugstore
$ cd drugstore

초기화.

jspm을 실행해봅시다 뭐 물어보는 부분에선 그냥 enter키만 누르시면 됩니다.

$ jspm init .

Would you like jspm to prefix the jspm package.json properties under jspm? [yes]:
Enter server baseURL (public folder path) [./]:
Enter jspm packages folder [./jspm_packages]:
Enter config file path [./config.js]:
Configuration file config.js doesn't exist, create it? [yes]:
Enter client baseURL (public folder URL) [/]:
Do you wish to use a transpiler? [yes]:
Which ES6 transpiler would you like to use, Babel, TypeScript or Traceur? [babel]:

패키지 설치.

이제 패키지를 잔뜩 깔아서 의존성을 뒤섞어봅시다. library로 React를 쓸 것이고, 클라이언트에서 출력할 것이므로 react-dom도 필요합니다. 이모콘에서는 react-dom을 쓰지 않으시려고 0.13.3 버전을 사용하셨었으니 이 부분이 살짝 다를 것입니다. Bootstrap도 깔아서 CSS 용도로 쓸 생각입니다. jspm은 이름 그대로 js가 기본이고 나머지는 계산 밖의 물건이므로 CSS 처리를 위해 css 확장도 설치해야합니다.

$ jspm install css
$ jspm install react
$ jspm install react-dom
$ jspm install bootstrap

CSS 설정.

CSS도 읽어오도록 설정을 해야합니다. config.js에 다음 내용을 적절히 추가합니다.

  meta: {
    "github:twbs/bootstrap@3.3.5": {
        "deps": [
          "github:twbs/bootstrap@3.3.5/css/bootstrap.min.css!"
        ]
    }
  },

돌려봅시다.

먼저 index.html을 만들어봅시다. <body> 안에 <script> 태그 외에 아무것도 넣지 않았음을 주목해주세요.

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>약 사세요</title>
  </head>
  <body>
    <script src="jspm_packages/system.js"></script>
    <script src="config.js"></script>
    <script>
      System.import('app/main');
    </script>
  </body>
</html>

다음으론 app 디렉토리를 만들고 그 안에 main.js를 만들어봅시다.

import 'bootstrap';
import React from 'react';
import ReactDOM from 'react-dom';

class DrugStore extends React.Component {
  render() {
    return (
      <main className='container'>
        <header className='row'>
          <h1>약 사세요!</h1>
        </header>
        <section className='row'>
          <table className='table'>
            <thead>
              <tr>
                <th>번호</th>
                <th>이름</th>
                <th>가격</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>1</td>
                <td>React</td>
                <td>Free!</td>
              </tr>
              <tr>
                <td>2</td>
                <td>AngularJS</td>
                <td>Free!</td>
              </tr>
            </tbody>
          </table>
        </section>
      </main>
    );
  }
}

ReactDOM.render(<DrugStore />, document.body);

눈에 보이는 것이 많이야 이해가 쉬울 것 같다고 생각했기에 발표때랑 달리 조금 더 많은 내용을 일부러 넣어보았습니다. 해당 소스는 React를 알아야 이해할 수 있는데, 간단히만 설명드리자면 HTML 태그처럼 생긴 것들이 자동으로 JavaScript로 변환되서 실행될 것입니다.

이제 간단히 웹서버를 실행해서 접속해봅시다. 다음 명령어를 실행한 후에 http://localhost:8000에 접속하시면 됩니다.

$ python -m SimpleHTTPServer

결과물.

결과물

이게 무슨 의미가 있나요?.

사실 jspm이 필요 없는 분도 많이 계실겁니다. jQuery랑 플러그인 몇 가지 정도만 붙여서 쓸 거라면 차라리 직접 다운로드 받아서 배치하는게 더 좋을지도 모르죠. 하지만 의존성이 좀 더 복잡해지면 복잡해질수록, JavaScript로 구현해야 하는 부분이 많아질수록 문제는 더욱 힘들어집니다.

지금 당장 만든 예제만 하더라도 jspm bundle-sfx 명령어로 수행된 파일을 사용하지 않으면 의존성을 모두 브라우저 상에서 실행하는 걸 볼 수 있는데, 사용되는 의존성만 하더라도 200개 가까이 됩니다. 이걸 일일히 <script> 태그를 써서 나열하는 것은 너무 이상하지 않을까요?

개인적인 소감.

의존성 문제를 해결해주는 친절한 기능이 눈에 띕니다. 실제로 제가 최근 작업한 사이트는 의존성을 bower로 관리하다가 gulpnpm으로 바꿨는데 그래도 아쉬움이 남아있는 상태였습니다. 예를 들어 gulp-copy2를 이용해서 의존성 파일을 옮겨준 다음에 babel을 돌려야 한다던가 하는 점 등등이 상당히 피곤했습니다. 하지만 jspm을 쓰면 그 부분은 말끔히 정리가 가능하므로 상당히 기대가 되는 편입니다.

근데 SCSS는 지원하지 않는 문제2 등이 있는데, 그 부분은 gulp로 파일을 따로 만들거나 webpack을 쓴다던가 하는 방법 외엔 아직 뚜렷히 떠오르는 대안이 없다는 아쉬움이 있습니다.

결론.

신약입니다. 아직 임상실험이 덜 되서 아쉬운 부분이 있지만 앞으로 좋아지지 않을까 하고 기대해봅니다.

다만 공부할 게 좀 많으니까 한번에 다 먹는건 힘듭니다. 천천히 공부하면서 음미하시면 될 것 같습니다. :)

각주.

  1. 사실 좀 더 옛날부터 있던 기술이었는데 구글에서 효과적으로 사용해서 재조명 받은 것이죠. 원래 위치로

  2. 아직 SystemJS쪽에서 개발한 loader가 없습니다. 비공식 로더는 존재하는데, 문제는 웹 문서에 어떻게 적용하는지 방법이 안나와있습니다. 예를 들어 import 'bootstrap.css!' 같은 것을 SCSS 문법 내에서 어떻게 사용하는가 하는 점 등등. 원래 위치로