SlideShare ist ein Scribd-Unternehmen logo
1 von 50
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

Javascript技巧参考大全
Javascript技巧参考大全Javascript技巧参考大全
Javascript技巧参考大全fgghyyfk
 
лабораторная работа 1 Исправленная
лабораторная работа 1 Исправленнаялабораторная работа 1 Исправленная
лабораторная работа 1 Исправленнаяsheplyakov
 
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...irwinvifxcfesre
 
Belajar Android Studio Material Design Penggunaan RecyclerView dan Card View
Belajar Android Studio Material Design Penggunaan RecyclerView dan Card ViewBelajar Android Studio Material Design Penggunaan RecyclerView dan Card View
Belajar Android Studio Material Design Penggunaan RecyclerView dan Card ViewAgus Haryanto
 
2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Off2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Offirwinvifxcfesre
 
Introducción WebComponents y Visual Studio
Introducción WebComponents y Visual StudioIntroducción WebComponents y Visual Studio
Introducción WebComponents y Visual StudioDavid Chavarri
 
Program Hitung di java dan netbeans
Program Hitung di java dan netbeansProgram Hitung di java dan netbeans
Program Hitung di java dan netbeanscasnadi
 
Chief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for KeefChief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for Keefchicagonewsonlineradio
 
A slew of AACM 50th anniversary celebrations this weekend
A slew of AACM 50th anniversary celebrations this weekendA slew of AACM 50th anniversary celebrations this weekend
A slew of AACM 50th anniversary celebrations this weekendchicagonewsyesterday
 
Webstandard2007 Spry Widget Ver1
Webstandard2007  Spry Widget Ver1Webstandard2007  Spry Widget Ver1
Webstandard2007 Spry Widget Ver1真一 藤川
 
Praktik Pengembangan Konten HTML5 untuk E-Learning (Extended)
Praktik Pengembangan Konten HTML5 untuk E-Learning (Extended)Praktik Pengembangan Konten HTML5 untuk E-Learning (Extended)
Praktik Pengembangan Konten HTML5 untuk E-Learning (Extended)Muhammad Yusuf
 
Pianist and composer Jeff Kowalkowski releases strong new trio album
Pianist and composer Jeff Kowalkowski releases strong new trio albumPianist and composer Jeff Kowalkowski releases strong new trio album
Pianist and composer Jeff Kowalkowski releases strong new trio albumirwinvifxcfesre
 

Was ist angesagt? (20)

Javascript技巧参考大全
Javascript技巧参考大全Javascript技巧参考大全
Javascript技巧参考大全
 
Web components v1 intro
Web components v1 introWeb components v1 intro
Web components v1 intro
 
Jquery ui, ajax
Jquery ui, ajaxJquery ui, ajax
Jquery ui, ajax
 
лабораторная работа 1 Исправленная
лабораторная работа 1 Исправленнаялабораторная работа 1 Исправленная
лабораторная работа 1 Исправленная
 
Lesson 01
Lesson 01Lesson 01
Lesson 01
 
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
Peek inside the fantastical Ukrainian Village home and studio of artists Jare...
 
Get more votes!
Get more votes!Get more votes!
Get more votes!
 
Belajar Android Studio Material Design Penggunaan RecyclerView dan Card View
Belajar Android Studio Material Design Penggunaan RecyclerView dan Card ViewBelajar Android Studio Material Design Penggunaan RecyclerView dan Card View
Belajar Android Studio Material Design Penggunaan RecyclerView dan Card View
 
Oop koncepti
Oop konceptiOop koncepti
Oop koncepti
 
2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Off2015 Key Ingredient Cook-Off
2015 Key Ingredient Cook-Off
 
Introducción WebComponents y Visual Studio
Introducción WebComponents y Visual StudioIntroducción WebComponents y Visual Studio
Introducción WebComponents y Visual Studio
 
Program Hitung di java dan netbeans
Program Hitung di java dan netbeansProgram Hitung di java dan netbeans
Program Hitung di java dan netbeans
 
Chief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for KeefChief Keef's hologram can't catch a break, and it's a win for Keef
Chief Keef's hologram can't catch a break, and it's a win for Keef
 
A slew of AACM 50th anniversary celebrations this weekend
A slew of AACM 50th anniversary celebrations this weekendA slew of AACM 50th anniversary celebrations this weekend
A slew of AACM 50th anniversary celebrations this weekend
 
Webstandard2007 Spry Widget Ver1
Webstandard2007  Spry Widget Ver1Webstandard2007  Spry Widget Ver1
Webstandard2007 Spry Widget Ver1
 
Service Workers
Service WorkersService Workers
Service Workers
 
Tugas uts
Tugas utsTugas uts
Tugas uts
 
Praktik Pengembangan Konten HTML5 untuk E-Learning (Extended)
Praktik Pengembangan Konten HTML5 untuk E-Learning (Extended)Praktik Pengembangan Konten HTML5 untuk E-Learning (Extended)
Praktik Pengembangan Konten HTML5 untuk E-Learning (Extended)
 
Pianist and composer Jeff Kowalkowski releases strong new trio album
Pianist and composer Jeff Kowalkowski releases strong new trio albumPianist and composer Jeff Kowalkowski releases strong new trio album
Pianist and composer Jeff Kowalkowski releases strong new trio album
 
xe:objectData
xe:objectDataxe:objectData
xe:objectData
 

Andere mochten auch

지하철이 살아있다.
지하철이 살아있다.지하철이 살아있다.
지하철이 살아있다.zerozerosum
 
Ass 10.10 ideo hcd h
Ass 10.10 ideo hcd hAss 10.10 ideo hcd h
Ass 10.10 ideo hcd hYoung Choi
 
디미컨_엄정민
디미컨_엄정민디미컨_엄정민
디미컨_엄정민Jungmin Um
 
(싱크탱크)사업소개서(약식)
(싱크탱크)사업소개서(약식)(싱크탱크)사업소개서(약식)
(싱크탱크)사업소개서(약식)싱크탱크
 
두번째단추 디지털마케팅 웹기획
두번째단추 디지털마케팅 웹기획두번째단추 디지털마케팅 웹기획
두번째단추 디지털마케팅 웹기획Woosung Kim
 
카카오스토리 웹팀의 코드리뷰 경험
카카오스토리 웹팀의 코드리뷰 경험카카오스토리 웹팀의 코드리뷰 경험
카카오스토리 웹팀의 코드리뷰 경험Ohgyun Ahn
 
알뜰 서울의 발견 - 조용현, 코드포서울 2014년 연말 공유회
알뜰 서울의 발견 - 조용현, 코드포서울 2014년 연말 공유회알뜰 서울의 발견 - 조용현, 코드포서울 2014년 연말 공유회
알뜰 서울의 발견 - 조용현, 코드포서울 2014년 연말 공유회codenamu
 

Andere mochten auch (7)

지하철이 살아있다.
지하철이 살아있다.지하철이 살아있다.
지하철이 살아있다.
 
Ass 10.10 ideo hcd h
Ass 10.10 ideo hcd hAss 10.10 ideo hcd h
Ass 10.10 ideo hcd h
 
디미컨_엄정민
디미컨_엄정민디미컨_엄정민
디미컨_엄정민
 
(싱크탱크)사업소개서(약식)
(싱크탱크)사업소개서(약식)(싱크탱크)사업소개서(약식)
(싱크탱크)사업소개서(약식)
 
두번째단추 디지털마케팅 웹기획
두번째단추 디지털마케팅 웹기획두번째단추 디지털마케팅 웹기획
두번째단추 디지털마케팅 웹기획
 
카카오스토리 웹팀의 코드리뷰 경험
카카오스토리 웹팀의 코드리뷰 경험카카오스토리 웹팀의 코드리뷰 경험
카카오스토리 웹팀의 코드리뷰 경험
 
알뜰 서울의 발견 - 조용현, 코드포서울 2014년 연말 공유회
알뜰 서울의 발견 - 조용현, 코드포서울 2014년 연말 공유회알뜰 서울의 발견 - 조용현, 코드포서울 2014년 연말 공유회
알뜰 서울의 발견 - 조용현, 코드포서울 2014년 연말 공유회
 

Meteor로 만드는 modern web application