Angularjs vs Handlebars
Dev

Angularjs vs Handlebars

2015. 2. 13. 13:07

그동안 진행하던 프로젝트에서 angularjs를 사용하지 않고 handlebars를 사용하기로 했다. 그동안 angularjs 로 만든 곳을 jquery + handlebars로 변경해야하는데 그에 앞서 간단한 샘플앱을 만들어보기로 했다. 댓글 앱인데 모양새는 동일하고 내부만 조금씩 다르다.

Angularjs

angularjs는 template을 따로 저장한 후에 불러오기보다는 사용하고 싶은 곳에 직접 작성하는 것이 특징이다. 먼저 ng-app을 통해서 사용할 모듈을 지정하고 ng-controller로 사용할 컨트롤러를 지정한다. ng-init 으로 초기화할 액션을 수행할 수 있다. 보였다 안보였다 하는 부부은 ng-show, 클릭이 필요한 부분은 ng-click, 리스트는 ng-repeat 등 머리속에 떠오르는 대로 쭉 작성해둔 후에 controller를 통해 구현을 한다.

<div class="content box" ng-app="CommentApp" ng-controller="CommentController" ng-init="init()">
    <div class="comment_header">
        <h3>Comment {{ commentCount }}</h3>
    </div>
    <div class="comment_list">
        <button class="btn_comment_more" style="display:block" ng-show="hasMore()" ng-click="more()">이전댓글 더보기</button>
        <ul id="comment-list">
            <li ng-repeat="item in commentList">
                <div class="comment_profile">
                    <img ng-src="{{ item.author.image }}">
                </div>
                <div class="comment_content">
                    <div>{{ item.author.name }} {{ timeStampToDate(item.date) }}</div>
                    <div>{{ item.message }}</div>
                </div>
            </li>
        </ul>
    </div>
    <div class="comment_form">
        <form class="form" ng-submit="post(comment)">
            <div class="form-group">
                <label for="comment">Message</label>
                <input name="comment" class="form-control" ng-model="comment.message">
            </div>
            <div class="form-group">
                <button class="btn btn-primary" type="submit">저장</button>
            </div>
        </form>
    </div>
</div>

이렇게 작성한 template이 동작할 수 있도록 controller를 만든다. 먼저 ng-app으로 정한 module을 만들고 그 안에 ng-controller로 지정한 controller를 만든다. controller의 $scope에 그동안 사용한 변수와 함수를 만들고 액션을 지정하는 것으로 완료가 된다.

var app = angular.module("CommentApp", []);

app.controller("CommentController", ['$scope', function($scope) {
    $scope.commentCount = 0;
    $scope.commentList = [];

    $scope.init = function() {
        $scope.commentCount = sample.count;
        $scope.commentList = sample.list;
    };

    $scope.hasMore = function() {
        return $scope.commentCount > $scope.commentList.length;
    };

    $scope.more = function() {
        $scope.commentList = sample.olderList.concat($scope.commentList);
    };

    $scope.post = function(comment) {
        if (!comment.message) {
            return;
        }

        var item = {
            author: {
                name: "Joo",
                image: "http://mud-kage.kakao.co.kr/14/dn/btqbJlyNypL/kFOdHKDFNBlBW2VD9Ei00K/o.jpg"
            },
            date: new Date(),
            message: comment.message
        };

        $scope.commentList.push(item);
        $scope.commentCount++;

        comment.message = "";
    };

    $scope.timeStampToDate = function(timestamp) {
        return timeStampToDate(timestamp);
    };
}]);

이렇게 angularjs로 만든 샘플이 완료되었다. 물론 초기에 학습하는 시간이 필요하긴 하지만 학습이 완료되고 나면 엄청난 속도가 난다. 사실 먼저 handlebars로 만든 후에 angularjs로 포팅을 했는데 포팅하는데 한시간이 뭐야 몇분 걸리지도 않았다. 단점은 여러 커뮤니티에서 지적했듯 비교적 느린 속도와 소스보기를 했을때 굉장히 더럽고 html과 너무 뒤섞인다는 것이다. 그래서 그런지 대형프로젝트에서 사용하는 것을 잘 못 보기는 했다.

- Angularjs : https://angularjs.org/
- 샘플앱 : http://dev.joostory.net/study/angularjs_comment

Handlebars

handlebars는 사실 2일전에 처음 알게 된 것인데 그렇게 유명한 것인지 몰랐다. 웹의 세계를 너무 오래 떠나 있었나보다. handlebars의 특징은 view에만 중점을 둔 것이다. 문서도 액션에 대한 부분은 전혀 없고 compile 해둔 template으로 html 코드를 뽑아내는 부분에만 초점이 맞춰져 있다. 사용하려면 먼저 template을 compile해야한다. precompile을 할 수 있는데 이렇게 하면 좀 더 리소스크기를 줄이고 속도를 빠르게 할 수 있다. compiler가 빠진 handlebars.runtime을 사용하기 때문이다. precompile하면 Handlebars.templates 에 배열로 compile된 template을 담아주는데 아래[각주:1]와 비슷한 일이라고 생각하면 된다.

<script>
(function($, $h) {
    $h.templates = $h.templates || [];
    $h.templates['comment.tpl'] = $h.compile($('#template-comment').html());
    $h.templates['comment-list.tpl'] = $h.compile($('#template-comment-list').html());
    $h.templates['editor.tpl'] = $h.compile($('#template-comment-editor').html());
    $h.templates['header.tpl'] = $h.compile($('#template-comment-header').html());
})(jQuery, Handlebars);
</script>

precompile을 하지 않을 것이라면 script 태그안에 template을 담아두고 사용할때 compile하면 된다. "#each" 로 list에 대한 처리를 할 수 있고 "> coment.tpl" 과 같이 partial로 분리한 다른 template을 include할 수 있다. "dateformat"은 helper로 등록한 함수이다.

<div class="content box">
    <div class="comment_header"></div>
    <div class="comment_list">
        <button class="btn_comment_more">이전댓글 더보기</button>
        <ul id="comment-list"></ul>
    </div>
    <div class="comment_form"></div>
</div>

<script id="template-comment" type="text/x-handlebars-template">
    <li>
        <div class="comment_profile">
            <img src="{{ author.image }}" />
        </div>
        <div class="comment_content">
            <div>{{ author.name }} {{dateformat date}}</div>
            <div>{{ message }}</div>
        </div>
    </li>
</script>

<script id="template-comment-list" type="text/x-handlebars-template">
    {{#each commentList}}
        {{> comment.tpl }}
    {{/each}}
</script>


<script id="template-comment-editor" type="text/x-handlebars-template">
    <form class="form">
        <div class="form-group">
            <label for="comment">Message</label>
            <input name="comment" class="form-control" />
        </div>
        <div class="form-group">
            <button class="btn btn-primary">저장</button>
        </div>
    </form>
</script>

<script id="template-comment-header" type="text/x-handlebars-template">
<h3>Comment {{ commentCount }}</h3>
</script>

template을 view로 만드는 것이나 액션은 모두 직접 만들어줘야한다. 먼저 template에서 사용한 helper와 partial을 등록해두고 event에 대한 액션을 만든다. 이 부분에 대해서는 Handlebars에서 제공하는 것은 없기 때문에 jquery를 사용하였다.

var commentTemplate = $h.templates['comment.tpl'],
    listTemplate = $h.templates['comment-list.tpl'],
    editorTemplate = $h.templates['editor.tpl']
    headerTemplate = $h.templates['header.tpl'],
    $header = $("div.comment_header"),
    $list = $("#comment-list"),
    $more = $("button.btn_comment_more"),
    $form = $(editorTemplate()),
    commentCount = 0,
    commentList = [];

// function

$h.registerHelper('dateformat', function(date, options) {
    return timeStampToDate(date.getTime());
});

$h.registerPartial('comment.tpl', commentTemplate);

function updateHeader() {
    $header.html(headerTemplate({
        commentCount: commentCount
    }));
}
function updateMore() {
    if (commentCount > commentList.length) {
        $more.show();
    } else {
        $more.hide();
    }
}
function updateList() {
    $list.html(listTemplate({ commentList: commentList }));
}

function updateView() {
    updateHeader();
    updateMore();
    updateList();
};

function appendComment(message) {
    var comment = { author:{image:"http://mud-kage.kakao.co.kr/14/dn/btqbJlyNypL/kFOdHKDFNBlBW2VD9Ei00K/o.jpg", name:"Joo"}, date: new Date(), message: message };
    commentList.push(comment);
    commentCount++;
    updateView();
};

// init

commentCount = sample.count;
commentList = sample.list;

$("div.comment_form").append($form);
updateView();

// event

$form.on("submit", function(e) {
    e.preventDefault();
    appendComment(this.comment.value);
    this.reset();
});

$more.on("mousedown", function(e) {
    e.preventDefault();
    commentList = sample.olderList.concat(commentList)
    updateView();
});

이렇게 handlebars를 사용한 샘플앱도 완료가 되었다. handlebars는 학습이랄 것도 없는 것이 template 자체 문법은 너무 쉽고 helper나 partial, precompile에 대한 부분만 알아두면 jquery만 사용하는 것과 같다. 장점은 precompile이라고 할 수 있다. 초기 로딩되는 리소스를 줄이는데 도움이 된다.

- Handlebars : http://handlebarsjs.com/
- 샘플앱 : http://dev.joostory.net/study/handlebars_comment
- 샘플앱 (precompile) : http://dev.joostory.net/study/handlebars_comment_precompile

결론

Angularjs vs Handlebars 라고 제목은 붙였지만 사실 둘 모두 괜찮은 것 같다. 다만 머신속도가 엄청나게 빨라진 요즘 속도는 큰 의미가 없는 것 같아 Angularjs의 단점이 크게 보이지는 않는다. 개발자 대부분이 속도가 느리다는 것에서 망설이겠지만 속도가 그리 중요하지만 않다면 angularjs를 선택하는 것이 어떤가 싶다.

  1. 아래는 동일한 소스코드를 가지고 precompile버전, 아닌 버전을 만들기 위해 사용했다 [본문으로]
반응형