• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Meteor로 만드는 modern web application
 

Meteor로 만드는 modern web application

on

  • 515 views

 

Statistics

Views

Total Views
515
Views on SlideShare
513
Embed Views
2

Actions

Likes
0
Downloads
1
Comments
0

1 Embed 2

http://www.linkedin.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Meteor로 만드는 modern web application Meteor로 만드는 modern web application Presentation Transcript

    • Meteor로 만드는 Modern Web Application 이재호 (Founder of Appsoulute) jhlee@appsoulute.com http://github.com/acidsound http://spectrumdig.blogspot.com @acidsound
    • Meteor application create 1. npm install -g meteorite 2. mrt create sogon2x
    • Meteor application launch 1. cd sogon2x 2. mrt 3. http://localhost:3000
    • 구현 목표 관심사 Page단위 SNS 서비스 1. 2. 3. 4. 5. 6. 7. 8. 9. 화면 생성 포스트 입력 저장 입력 이벤트 처리 포스트 정렬 및 페이지 지정 페이지별 라우터 생성 스마트 패키지 이용 시간 처리 사용자 계정 적용 페이지별 가입/탈퇴 처리 마이페이지 구현
    • Let's rock 백문불여일타 百聞不如一打
    • JS >> client directory if (Meteor.isClient) { } >> server directory if (Meteor.isServer) { Meteor.startup(function () { // code to run on server at startup }); }
    • HTML/시작 <body> {{> head}} {{> main}} </body> <template name="head"> </template> <template name="main"> </template>
    • Head 1/2 <template name="head"> <div class="navbar navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <!-- .btn-navbar is used as the toggle for collapsed navbar content --> <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </a>
    • Head 2/2 <!-- Be sure to leave the brand out there if you want it shown --> <a class="brand" href="/">Sogon</a> <!-- Everything you want hidden at 940px or less, place within here --> <div class="nav-collapse collapse"> <!-- .nav, .navbar-search, .navbar-form, etc --> </div> </div> </div> </div> </template>
    • Main template <template name="main"> <div class="container"> <ul class="unstyled"> <li class="row"> <h2>nobody's Page</h2> <form class="form-inline"> <textarea class="postText input-block-level" placeholder="Press shift+enter to post"></textarea> <button type="reset" class="btn pull-right"><i class="icon-trash" /></button> <button type="submit" class="btn-primary submit btn pull-right"><i class="icon-white icon-pencil"/></button> </form> </li> </ul> </div>
    • Post template <li class="row post"> <div class="postHead"><span class="label labelsuccess author">User</span><span class="badge timeAgo badge-info pull-right">Now</span> </div> <div class="postBody"> <pre>Tell me something 어서 말을 해.<span class="pull-right label label-important tags">page </span></pre> </div> </li>
    • CSS /* CSS declarations go here */ .form-inline button { margin-top: 5px; margin-left: 5px; } form { margin-bottom: 50px; } /* fixed top Scroll */ body { padding-top: 60px; } @media (max-width: 979px) { body { padding-top: 0; }
    • Posts template {{#each posts}} <li class="row post"> .... </li> {{/each}} * 반복 구간
    • Posts Template.main.posts=function() { return [ { text : 'First post' } ]; }
    • Posts collection var Posts = new Meteor.Collection ('posts');
    • Posts Template.main.posts=function() { return Posts.find(); } > Posts.insert({'text':'First Post'});
    • Client-side security package 제거 mrt remove insecure 거칠게 구현하고 Scaffold 빼내기의 반복 Posts.insert({'text':'say something'}); "f595d61e-fad3-4a33-8a19-cfc667e5b672" insert failed: Access denied
    • Call/Method Meteor.methods({ "postText": function(text) { if(text) { Posts.insert({'text':text}); } } }); > Meteor.call('postText', 'say something');
    • Event Handling Template.main.events({ 'submit': function () { var input = $('.postText'); Meteor.call('postText',input.val(), function(err,result) { sendSubmit으 로 refactoring if(err) throw 'server error'; }); input.val(''); return false; }, 'keydown .postText':function (e) { return (e.shiftKey && e.which === 13) && sendSubmit() || true; } });
    • Session Session.set('page', '...'); Template.main.pageTitle=function() { return Session.get('page'); } {{#if pageTitle}} <h2>{{pageTitle}}'s Page</h2> {{/if}}
    • Page Call/Method Meteor.call('postText', input.val(), Session.get ('page'), function(... Meteor.methods({ "postText": function(text, page) { if(text) { Posts.insert({'text':text, 'created_at': Date. now(), 'page':page});
    • Page template {{#each posts}} <li class="row post"> <div class="postHead"><span class="label author" >User</span><span class="badge timeAgo pull-right" >Now</span> </div> <div class="postBody"> <pre>{{{text}}}<span class="pull-right label tags"> {{page}} </span></pre> </div> </li>
    • Subscribe/Publish mrt remove autopublish Meteor.autosubscribe(function() { Meteor.subscribe('posts', Session.get('page')); }); Template.main.posts=function(){ return Posts.find({}, {sort:{created_at:-1}}); }; Meteor.publish('posts', function (page) { return Posts.find({page:page}, {sort:{created_at:-1}}); });
    • Router mrt add router <body> {{> head}} {{renderPage}} </body>
    • 비 로그인 시 Title 추가 <template name="title"> <div class="container hero-unit"> <h1>Hello Sogon!</h1> <p> Simple and Robust SNS </p> <button class="btn btn-info pull-right">Read More..</button> </div>
    • Router 정의 Meteor.Router.add({ '/':function() { Session.set('page',''); return 'title'; }, '/page/:page':function(args) { Session.set('page',args[0]); return 'main'; } })
    • Moment 시간을 트위터처럼 a few seconds ago, 10 hours ago
    • Moment 설치 mrt add moment > moment().from() "a few seconds ago" > moment(Date.now()-60000).from() "a minute ago"
    • timeago helper Handlebars.registerHelper('timeago',function (time) { return moment(time).from(); }); <span class="badge pull-right"> {{timeago created_at}} </span>
    • Account <template name="head"> .... <ul class="nav pull-right"> <li> <a href="#">{{loginButtons}}</a> </li> </ul>
    • User Collection > Meteor.user() // 현재 접속 유저 * login 이전 null null * user/password login id : "<UUID>" emails : Array * facebook login iid : "<UUID> profile : name : <User Name>
    • Post with User() Meteor.methods({ "postText": function(text, page) { if(text && page && Meteor.user()) { Posts.insert({'text':text, 'page':page, 'author': Meteor.user(), 'created_at': Date.now() }); } else { throw "access denied"; } } });
    • Post template <li class="row post"> <div class="postHead"><span class=" label label-success author">{{author.profile. name}}</span><span class="badge timeAgo pull-right">{{timeago created_at}}</span>
    • Form with User() * template main {{#if currentUser}} <li class="row"> <form class="form-inline"> <textarea class="postText input-block-level" placeholder="shift+enter to post.."></textarea> <button type="reset" class="btn pull-right"><i class=" icon-trash"/></button> <button type="submit" class="btn-primary submit btn pull-right"><i class="icon-white icon-pencil"/></button> </form> </li>
    • Subscribers 구조 JSON Key/Value 구조 user() ㄴ profile ㄴ subscribers ㄴ page1 ㄴ timestamp ㄴ page2 ㄴ timestamp >> 가입 여부 확인 !!Subscribers['page1'] -> 있으면 true 없으면 null이니까 false >> 검색 Posts.find({page: {$in : [ 유저가 가입한 Page들의 이름 Array ]});
    • Method Subscribe/Unsubscribe "subscribe": function(page) { var subscribers={}; subscribers["profile.subscribers."+page]={ dateTime:Date.now() }; Meteor.users.update(this.userId, {$set:subscribers}); }, "unsubscribe": function(page) { var subscribers={}; subscribers["profile.subscribers."+page]=false; Meteor.users.update(this.userId, {$unset:subscribers}); }
    • Helper Subscribe/Unsubscribe Template.main.helpers({ 'isSubscribe': function (subscribers) { return subscribers && subscribers[Session. get('page')]; } });
    • Template Subscribe/Unsubscribe <h2>{{pageTitle}}'s page {{#if currentUser}} {{#unless isSubscribe currentUser.profile. subscribers}} <button class="btn btn-primary subscribe"> Subscribe </button> {{else}} <button class="btn btn-inverse unsubscribe"> Unsubscribe </button> {{/unless}}
    • Event subscribe/unsubscribe 'click .subscribe' : function () { Meteor.call('subscribe', Session.get('page')) }, 'click .unsubscribe' : function () { Meteor.call('unsubscribe', Session.get ('page')) }
    • Posts collection subscribe Page 에서 볼때 page 기준 유저의 MyPage 에선 User 하는 기준으로 following Meteor.autosubscribe(function() { Meteor.subscribe('posts', Session.get ('page'), Meteor.user()); });
    • Posts collection publish Meteor.publish('posts', function (page, user) { return Posts.find( page && {page:page} || user && { page:{$in: _.map(user.profile && user.profile.subscribers, function(v,k) { return k; }) } } || {}, {sort:{created_at:-1}} ); });
    • MyPage 내가 Subscribe 한 곳의 글을 모아볼 수 있게 template main 에서 {{#each posts}} 부분을 posts template 으로 분리
    • MyPage template <template name="posts"> {{#each posts}} ... {{/each}} </template> <template name="mypage"> <div class="container"> <ul class="unstyled"> <li> <h2>My page</h2> </li> {{> posts}} </ul> </div> </template>
    • Posts Collection Template.main.posts=function(){ return Posts.find({}, {sort:{created_at:-1}}); }; 에서 Template.posts.posts=function(){ return Posts.find({}, {sort:{created_at:-1}}); }; 로 변경
    • MyPage Router Meteor.Router.add({ '/':function() { Session.set('page',''); return 'title'; }, '/page/:page':function(args) { Session.set('page', args[0]); return 'main'; }, '/mypage':function() { Session.set('page',''); return 'mypage'; } });
    • MyPage filter Meteor.Router.filters({ 'login' : function() { if (Meteor.user()) { Session.set('page', ''); return 'mypage'; } else { return 'title'; } } }); Meteor.Router.filter('login', {only: 'title'});
    • Posts template link <template name="posts"> {{#each posts}} <li class="row post"> <div class="postHead"><span class="label label-success author">{{author. profile.name}}</span><span class="badge badge-info timeAgo pull-right"> {{timeago created_at}}</span> </div> <div class="postBody"> <pre>{{{text}}} <a href="/page/{{page}}"><span class="pull-right label label-important tags">{{page}} </span></a></pre> </div> </li> {{/each}} </template>
    • ONE MORE THING?
    • less? mrt add less > sogon.css를 sogon.less로 변경 http://www.bootstrapcdn.com/#bootswatch 중 //netdna.bootstrapcdn.com/bootswatch/2.1.0 /amelia/bootstrap.min.css 를 적용해보자. > theme를 적용해보자! @import "http://netdna.bootstrapcdn. com/bootswatch/2.1.0/united/bootstrap.min. css";
    • FORK ME!! PULL ME!! http://github.com/acidsound/sogon2x