50
Meteor만드는 Modern Web Application 이재호 (Founder of Appsoulute) [email protected] http://github.com/acidsound http://spectrumdig.blogspot.com @acidsound

Meteor로 만드는 modern web application

Embed Size (px)

Citation preview

Page 1: Meteor로 만드는 modern web application

Meteor로 만드는 Modern Web Application이재호 (Founder of Appsoulute)[email protected]://github.com/acidsoundhttp://spectrumdig.blogspot.com@acidsound

Page 2: Meteor로 만드는 modern web application

1. npm install -g meteorite2. mrt create sogon2x

Meteor application create

Page 3: Meteor로 만드는 modern web application

1. cd sogon2x2. mrt3. http://localhost:3000

Meteor application launch

Page 4: Meteor로 만드는 modern web application

구현 목표관심사 Page단위 SNS 서비스

1. 화면 생성2. 포스트 입력 저장3. 입력 이벤트 처리4. 포스트 정렬 및 페이지 지정5. 페이지별 라우터 생성6. 스마트 패키지 이용 시간 처리7. 사용자 계정 적용8. 페이지별 가입/탈퇴 처리9. 마이페이지 구현

Page 5: Meteor로 만드는 modern web application

백문불여일타百聞不如一打

Let's rock

Page 6: Meteor로 만드는 modern web application

>> client directoryif (Meteor.isClient) {}

>> server directoryif (Meteor.isServer) { Meteor.startup(function () { // code to run on server at startup });}

JS

Page 7: Meteor로 만드는 modern web application

<body>{{> head}}{{> main}}

</body><template name="head"></template><template name="main"></template>

HTML/시작

Page 8: Meteor로 만드는 modern web application

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>

Page 9: Meteor로 만드는 modern web application

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>

Page 10: Meteor로 만드는 modern web application

<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></template>

Main template

Page 11: Meteor로 만드는 modern web application

Post template <li class="row post"> <div class="postHead"><span class="label label-success 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>

Page 12: Meteor로 만드는 modern web application

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; }}

Page 13: Meteor로 만드는 modern web application

{{#each posts}} <li class="row post">.... </li> {{/each}}

* 반복 구간

Posts template

Page 14: Meteor로 만드는 modern web application

Template.main.posts=function() { return [ { text : 'First post' } ];}

Posts

Page 15: Meteor로 만드는 modern web application

var Posts = new Meteor.Collection('posts');

Posts collection

Page 16: Meteor로 만드는 modern web application

Template.main.posts=function() { return Posts.find();}

> Posts.insert({'text':'First Post'});

Posts

Page 17: Meteor로 만드는 modern web application

package 제거mrt remove insecure

거칠게 구현하고 Scaffold 빼내기의 반복

Posts.insert({'text':'say something'});"f595d61e-fad3-4a33-8a19-cfc667e5b672"insert failed: Access denied

Client-side security

Page 18: Meteor로 만드는 modern web application

Meteor.methods({ "postText": function(text) { if(text) { Posts.insert({'text':text}); } }});

> Meteor.call('postText', 'say something');

Call/Method

Page 19: Meteor로 만드는 modern web application

Event HandlingTemplate.main.events({ 'submit': function () { var input = $('.postText'); Meteor.call('postText',input.val(), function(err,result) { if(err) throw 'server error'; }); input.val(''); return false; }, 'keydown .postText':function (e) { return (e.shiftKey && e.which === 13) && sendSubmit() || true; }});

sendSubmit으로 refactoring

Page 20: Meteor로 만드는 modern web application

Session.set('page', '...');

Template.main.pageTitle=function() { return Session.get('page'); } {{#if pageTitle}} <h2>{{pageTitle}}'s Page</h2> {{/if}}

Session

Page 21: Meteor로 만드는 modern web application

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 Call/Method

Page 22: Meteor로 만드는 modern web application

{{#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> {{/each}}

Page template

Page 23: Meteor로 만드는 modern web application

Subscribe/Publishmrt 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}}); });

Page 24: Meteor로 만드는 modern web application

Routermrt add router

<body>{{> head}}{{renderPage}}</body>

Page 25: Meteor로 만드는 modern web application

비 로그인 시 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></template>

Page 26: Meteor로 만드는 modern web application

Router 정의 Meteor.Router.add({ '/':function() { Session.set('page',''); return 'title'; }, '/page/:page':function(args) { Session.set('page',args[0]); return 'main'; } })

Page 27: Meteor로 만드는 modern web application

Moment

시간을 트위터처럼a few seconds ago, 10 hours ago

Page 28: Meteor로 만드는 modern web application

Moment 설치mrt add moment> moment().from()"a few seconds ago"> moment(Date.now()-60000).from()"a minute ago"

Page 29: Meteor로 만드는 modern web application

timeago helperHandlebars.registerHelper('timeago',function(time) { return moment(time).from(); });

<span class="badge pull-right"> {{timeago created_at}} </span>

Page 30: Meteor로 만드는 modern web application

<template name="head">.... <ul class="nav pull-right"> <li> <a href="#">{{loginButtons}}</a> </li> </ul>

Account

Page 31: Meteor로 만드는 modern web application

User Collection> Meteor.user() // 현재 접속 유저* login 이전 nullnull* user/password loginid : "<UUID>"emails : Array* facebook loginiid : "<UUID>profile : name : <User Name>

Page 32: Meteor로 만드는 modern web application

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"; } }});

Page 33: Meteor로 만드는 modern web application

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>

Page 34: Meteor로 만드는 modern web application

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> {{/if}}

Page 35: Meteor로 만드는 modern web application

JSON Key/Value 구조user()ㄴ profile ㄴ subscribers ㄴ page1 ㄴ timestamp ㄴ page2 ㄴ timestamp>> 가입 여부 확인!!Subscribers['page1'] -> 있으면 true 없으면 null이니까 false

>> 검색Posts.find({page: {$in : [ 유저가 가입한 Page들의 이름 Array ]});

Subscribers 구조

Page 36: Meteor로 만드는 modern web application

MethodSubscribe/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}); }

Page 37: Meteor로 만드는 modern web application

Helper Subscribe/Unsubscribe Template.main.helpers({ 'isSubscribe': function (subscribers) { return subscribers && subscribers[Session.get('page')]; } });

Page 38: Meteor로 만드는 modern web application

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}} {{/if}}</h2>

Page 39: Meteor로 만드는 modern web application

'click .subscribe' : function () { Meteor.call('subscribe', Session.get('page')) }, 'click .unsubscribe' : function () { Meteor.call('unsubscribe', Session.get('page')) }

Event subscribe/unsubscribe

Page 40: Meteor로 만드는 modern web application

Posts collection subscribePage 에서 볼때 page 기준유저의 MyPage 에선 User 하는 기준으로 following

Meteor.autosubscribe(function() { Meteor.subscribe('posts', Session.get('page'), Meteor.user()); });

Page 41: Meteor로 만드는 modern web application

Posts collection publishMeteor.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}} );});

Page 42: Meteor로 만드는 modern web application

내가 Subscribe 한 곳의 글을 모아볼 수 있게template main 에서 {{#each posts}} 부분을 posts template 으로 분리

MyPage

Page 43: Meteor로 만드는 modern web application

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>

Page 44: Meteor로 만드는 modern web application

Posts CollectionTemplate.main.posts=function(){ return Posts.find({}, {sort:{created_at:-1}});};에서

Template.posts.posts=function(){ return Posts.find({}, {sort:{created_at:-1}});};로 변경

Page 45: Meteor로 만드는 modern web application

MyPage RouterMeteor.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'; }});

Page 46: Meteor로 만드는 modern web application

MyPage filterMeteor.Router.filters({ 'login' : function() { if (Meteor.user()) { Session.set('page', ''); return 'mypage'; } else { return 'title'; } }});Meteor.Router.filter('login', {only: 'title'});

Page 47: Meteor로 만드는 modern web application

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>

Page 48: Meteor로 만드는 modern web application

ONE MORE THING?

Page 49: Meteor로 만드는 modern web application

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";

Page 50: Meteor로 만드는 modern web application

FORK ME!!PULL ME!!http://github.com/acidsound/sogon2x