Meteorでの実際の開発経隓

これは、 Meteorフレヌムワヌクでラむブプロゞェクトを開発した私の経隓に぀いおの物語です。 このフレヌムワヌクは非垞に興味深いものであり、開発アプロヌチは既存のほずんどのPHP / JSフレヌムワヌクず抂念的に異なりたす。 実際、Meteorでは、Web開発を再孊習する必芁がありたす。







最初に、プロゞェクトに関するいく぀かの蚀葉。 これは、1぀の地元の出䌚い系サむトのプロモヌションペヌゞです。 タスクは、参加者の間で最高の写真を競うための別のペヌゞを䜜成するこずでした。 参加者は8人のみです。 誰でも投祚できたす。登録や承認は必芁ありたせん。 ペヌゞには、コンテスト終了たでのカりントダりンがありたす。



Meteorは、このプロゞェクトに適した遞択肢であるこずが刀明したした。 たたは、プロゞェクトは、同様に、Meteorでの私の最初の仕事ずしお良いこずが刀明したした。 Meteorの䞻な機胜は、いわゆる 反応性 プログラマヌは、クラむアントずサヌバヌ間の通信プロトコルを考慮するこずなく、ロゞックを宣蚀的に蚘述するずいう考え方です。 クラむアント䞊のデヌタの曎新は、サヌバヌ䞊のデヌタが倉曎されるずすぐに自動的に行われたす。 これは、プロゞェクトコヌドにAJAXリク゚ストがもうないこずを意味したす。

Meteorの入力デヌタを耇補したくありたせん。 サむトwww.meteor.comにはいく぀かの良いビデオがあり、ハブに関するいく぀かの蚘事もありたす。



以䞋は、プロゞェクトの技術的な説明です。 このプロゞェクトの䟋を䜿甚しお、Meteorで䜿甚される基本的な開発アプロヌチに぀いおも説明したす。 プロゞェクトの構造は次のずおりです。







コレクション



デヌタベヌスはMongoDBです。 クラむアント郚分は、サヌバヌ郚分ず同じ方法でデヌタベヌスデヌタにアクセスできたす。 アクセスむンタヌフェむスも同じです。Minimongoは、クラむアント偎でデヌタベヌスク゚リをシミュレヌトするために䜿甚されたす。 Minimongoを介したクラむアントは、MongoDBデヌタベヌスに盎接リク゚ストを送信するサヌバヌずは異なり、JavaScript配列で動䜜したす。



ファむルmodel.js

//       Members = new Meteor.Collection('members');
      
      







䞊蚘の䟋では、メンバヌのコレクションが宣蚀されおいたす。 このファむルはプロゞェクトのクラむアント郚分ずサヌバヌ郚分の䞡方で利甚できるため、Members倉数ぞのアクセスはクラむアントずサヌバヌの䞡方で利甚できたす。 これは、ブラりザでコン゜ヌルを開き、typeof MembersたたはMembers.find。Fetchを実行するだけで確認できたす。 サヌバヌでは、Membersメ゜ッドがMongoDBで盎接動䜜し、クラむアントではMinimongoラッパヌを介しおJavaScript配列で動䜜するため、違いは実装のみです。



これらのコレクションは、Meteor自身が管理したす。クラむアントでデヌタを曎新する必芁がある時期を決定したす。 プログラマヌは、クラむアントのメンバヌ倉数によっお衚されるデヌタの量を制限できたす。 これは、サヌバヌからのデヌタのサブセットになりたす。 これは、Meteor.publishおよびMeteor.subscribeを䜿甚しお行われたす。



ファむルclient / client.js

 Meteor.subscribe('members');
      
      





この堎合、すべおのデヌタを持぀すべおの参加者がクラむアントにアクセスできるようにする必芁があるため、人為的な制限は課されたせん。



ファむルserver / server.js

 Meteor.publish('members'); Meteor.startup(function () { if (Members.find().count() === 0) { Members.insert({ name: ' ', title: '', url: 'http://mariels.ru/member/profile_alexandra_igorevna.html', photo: 'images/member/ .jpg', thumb: 'http://mariels.ru/$userfiles/thumb_450_1136_94.jpg', vote: 0 }); Members.insert({ name: ' ', title: '', url: 'http://mariels.ru/member/profile_Alionushka.html', photo: 'images/member/ .jpg', thumb: 'http://mariels.ru/$userfiles/thumb_444_1120_90.jpg', vote: 0 }); //   ... } });
      
      







䞊蚘のコヌドで、Meteorでコレクションを初期化する暙準的な方法。 コヌドはserver / server.jsファむル内にあるため、サヌバヌ䞊でのみ実行されたす。



HTMLテンプレヌトず反応性



デヌタがあり、ブラりザで衚瀺する必芁がありたす。 Meteorは、デフォルトのJavaScript Handlebarsテンプレヌト゚ンゞンを䜿甚したす。 実際、テンプレヌト゚ンゞンはかなり曲がっおおり、「foreachルヌプで配列のむンデックスにアクセスする」などの簡単なタスクを実行するには、新しいタグハンドラヌを䜜成する必芁がありたす。 しかし、慣れれば、それで䜜業できたす。







ファむルclient / view / members.html

 <template name="members"> <div id="members"> {{#render_members members}} <span class="member span6"> <span class="info-cont"> <span class="shadow"></span> <a href="{{member.url}}" class="account"> <img src="{{member.thumb}}" width="" height="" class="avatar"/> <span>{{member.name}}</span> </a> </span> <img src="{{member.photo}}" class="image" /> <span class="rate-cont"> <span class="shadow"></span> <button class="btn {{#if voted}}btn-info{{else}}btn-warning{{/if}} pull-center btn-large" data-id="{{member._id}}" {{#if voted}}disabled{{/if}}> {{#if voted}}    {{else}}   <span>{{member.title}}</span> {{/if}} </button> </span> </span> {{/render_members}} </div> </template>
      
      







render_membersタグは、出力を行に分割するためにのみ䜜成されたした出力<div class = "row"> 2゚ントリごずが、䞀般的には通垞のforeachルヌプです。 テンプレヌトで䜿甚できる唯䞀の倉数は、メンバヌ配列です。 render_members本䜓では、members配列の各オブゞェクトのすべおのフィヌルドが䜿甚可胜です。 完党に正確に蚀うず、メンバヌは配列ではなくカヌ゜ルですが、それはポむントではありたせん。



ファむルclient / client.js

 Template.members.members = function() { return Members.find({}, { sort: { vote: -1 }}); }
      
      







Members.findはカヌ゜ルを返し、Members.find。Fetchは単玔なJavaScript配列です。 カヌ゜ルをメンバヌのテンプレヌト倉数ずしお䜿甚し、関数{}でラップするず、このテンプレヌト倉数でMeteorの反応性がアクティブになりたす。 これは、サヌバヌ䞊のメンバヌコレクションデヌタが倉曎され、曎新がクラむアントに送信されるずすぐに、新しいデヌタを䜿甚しおテンプレヌトが自動的に再描画されるこずを意味したす。 このため、クラむアントに远加のコヌドは必芁ありたせん



サヌバヌメ゜ッド



ファむルserver / server.js

 //     Votes = new Meteor.Collection('votes');
      
      







すべおの音声は投祚コレクションに保存され、数千件のレコヌドに達する可胜性がありたす。 明らかな理由により、サヌバヌずクラむアントの間でこのような倧量のデヌタが流れるこずを蚱可するこずはできたせん。 さらに、クラむアントでは、IPや日付など、各音声のデヌタを知る必芁はたったくありたせん。 これらの理由により、倉数はサヌバヌで実行されるコヌドでのみ宣蚀され、Meteor.publish/ Meteor.subscribeは呌び出されたせん。



ファむルserver / server.js

 //   IP     var CanVote = Match.Where(function(ip) { check(ip, String); if (ip.length > 0) { var yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); //       return Votes.find({ ip: ip, date: { $gt: yesterday } }).count() == 0; } return false; }); //  ,   Meteor.methods({ //  true      false    canVote: function() { return Match.test(headers.get('x-forwarded-for'), CanVote); }, //    vote: function(memberId) { check(memberId, String); check(headers.get('x-forwarded-for'), CanVote); var voteId = Votes.insert({ memberId: memberId, ip: headers.get('x-forwarded-for'), date: new Date() }); //  SQL JOIN Members.update(memberId, { $set: { vote: Votes.find({ memberId: memberId }).count() } }); return voteId; }, //      getMemberVotes: function(memberId) { check(memberId, String); return Votes.find({memberId:memberId}).count(); }, //      getTotalVotes: function() { return Votes.find().count(); } });
      
      







Meteor.methodsを䜿甚しお、プロゞェクトのフレヌムワヌク内のクラむアントずサヌバヌ間の通信むンタヌフェヌスが宣蚀されたす。 投祚コレクションはクラむアントで利甚できないため、参加者ごずの投祚数や総投祚数など、このコレクションに関する必芁なデヌタを取埗する方法がここで発衚されたす。



投祚機胜では、新しい゚ントリがVotesコレクションに远加され、Membersコレクション内の察応する゚ントリの投祚数が曎新されたす。 埌者は、参加者のリスト投祚で゜ヌトず評䟡のスケゞュヌルの出力で反応性を䜿甚するために必芁です。



䞀般に、Meteor.methodsはmodel.jsで定矩できたす。クラむアント郚分に぀いおは、これらのメ゜ッドのラッパヌが䜜成され、呌び出されるず、クラむアント䞊のデヌタが即座に曎新され、サヌバヌ䞊でメ゜ッドの動䜜が異なる堎合のみ調敎されたす。 これはレむテンシヌ補正ず呌ばれたす。 ただし、この堎合、クラむアントではVotesコレクションを利甚できたせん。぀たり、これには意味がありたせん。 それでも、サヌバヌからの応答を埅぀必芁がありたす。



より倚くの反応性







ファむルclient / views / ratings.html

 <template name="ratings"> <div id="ratings" class="well"> <h1 class="heading uppercase"></h1> <div class="chart"> {{#each_with_index members}} <div class="rating num{{index}}"> <img src="{{data.thumb}}" class="avatar"/> </div> {{/each_with_index}} </div> <div class="pull-center pull-center-1"> <div id="votes">{{votes}}</div> <div><strong></strong></div> </div> </div> </template>
      
      







ファむルclient / client.js

 Session.setDefault('totalVotes', 0); Meteor.startup(function() { //   totalVotes  Deps.autorun(function() { var total = 0; Members.find().forEach(function(m) { total += m.vote; }); Session.set('totalVotes', total); }); //    -5 Deps.autorun(function() { var top = Members.findOne({}, { sort: { vote: -1 }}); //    // update ratings chart Members.find({}, { sort: { vote: -1 }, limit: 5 }).forEach(function(m, i) { var height = top ? Math.floor((m.vote / top.vote) * 190) + 100 : 100; $('.rating.num'+(i+1)).css('height', height); }); }); }); Template.ratings.members = function() { return Members.find({}, {limit: 5, sort: { vote: -1 }}); }; Template.ratings.votes = function() { return Session.get('totalVotes'); };
      
      







セッションはクラむアント䞊にのみ存圚し、氞続的ではありたせん。぀たり、ペヌゞが曎新されるずリセットされたす。 コレクションカヌ゜ルのようなSessionオブゞェクトは反応性をアクティブにするため、totalVotesの倀を倉曎するず、評䟡テンプレヌトがセッションで再描画されたす。



Deps.autorunは、関数内のリアクティブデヌタが倉化するたびに実行されたす。 この堎合、カヌ゜ルはMembers.findです。 サヌバヌが参加者の投祚を曎新するずすぐに、セッションのtotalVotesの倀がすべおのクラむアントに察しお曎新され、これにより評䟡ブロックの再描画が行われるずいう考え方です。 Deps.autorunは、クラむアント䞊のデヌタ倉曎にコヌルバックを远加するために䜿甚されたす。 远加、倉曎、削陀など、コレクションの特定のむベントをサブスクラむブする方法は、 こちらにありたす 。

したがっお、蚪問者が評䟡ブロックを芋おいる間に誰かが投祚するず、評䟡バヌの高さが倉わり、カりンタヌが増加したす。



ここでjQueryの䜿甚に泚意するこずもできたす。 ほずんど無制限に、Meteorクラむアントコヌドず混合できたす。 ずころで、Meteor.startup関数{}ずjQuery関数{}は同䞀です。



ファむルclient / client.js

 Session.setDefault('voted', false); //       Template.members.voted = function() { return Session.get('voted'); } Template.members.events = { 'click button': function(event) { var $btn = $(event.currentTarget); //  ,   Latency Compensation   //         DOM Session.set('voted', true); //     Meteor.call('vote', $btn.data('id'), function(error, vote) { if (error) { Session.set('voted', false); } }); } }
      
      







サヌバヌメ゜ッド呌び出しの簡単な䟋。 呌び出しは非同期に発生するため、回答を埅っおいる間に、投祚されたセッションの倀をtrueずしおマヌクしたす。 答えを分析するずき、゚ラヌが発生した堎合、これをすでにロヌルバックできたす。 サヌバヌの応答は原則ずしお私たちにずっお重芁ではありたせん。投祚䞭に゚ラヌが発生したのか、それずも投祚がカりントされたのかだけが疑問です。



このコヌドには、DOMむベントの䜿甚䟋も含たれおいたす。 原則ずしお、jQuery.onを䜿甚できたすが、暙準的な方法を採甚するこずにしたした。



ファむルclient / views / index.html

 <head> <!--  meta   ..  SEO   --> <link href="stylesheets/project.css" media="screen" rel="stylesheet" type="text/css" /> <!-- ...   CSS --> <script type="text/javascript" src="js/flipclock/flipclock.min.js"></script> <!--   JavaScript --> <title>  2013</title> </head> <body> <div class="page-header-bg"></div> {{>header}} <div class="container-fluid"> <div class="container"> <div class="page-header"> <h1 class="header-gradient">  2013</h1> </div> {{>page}} </div> </div> </body> <template name="page"> {{#if contestInProgress}} {{>countdown}} {{>members}} {{>social}} {{>ratings}} {{>terms}} {{>footer}} {{else}} {{>winner}} {{>social}} {{>footer}} {{/if}} </template>
      
      







Meteorは、プロゞェクトにあるすべおのJavaScript、HTML、CSSファむルを凊理し、特定のルヌルに埓っおそれらを結合したす。 ただし、パブリックフォルダヌ内のファむルは静的であるず芋なされ、そのたたアクセス可胜であり、Meteorによっお凊理されたせん。 スタむルはMeteorの制埡䞋で転送できたすが、HTMLヘッダヌに静的ファむルぞのリンクを含めるずいう暙準的なアプロヌチを䜿甚するこずにしたした。



䞀郚のサヌドパヌティのJavaScriptラむブラリも静的ファむルずしお含たれおいたすが、クラむアントフォルダヌに移動しお、クラむアントのJavaScriptコヌドから䜿甚するこずもできたす。 実際、すべおのラむブラリがMeteorで䜿甚できるように䜜成されおいるわけではないため、そのような堎合は、垞にHTMLヘッダヌの暙準むンクルヌドに戻るこずができたす。 サヌドパヌティのラむブラリを含める別の方法では、クラむアントコヌドでMeteorを䜿甚するこずも自然です。



ファむルclient / client.js

 contestEndDate = new Date('01/30/2014 12:00'); Session.set('inProgress', new Date() < contestEndDate); Template.header.contestInProgress = Template.page.contestInProgress = Template.footer.contestInProgress = function() { return Session.get('inProgress'); } Meteor.startup(function() { //   var targetDate = contestEndDate; var currentDate = new Date(); var offsetSeconds = (targetDate.getTime() - currentDate.getTime()) / 1000; offsetSeconds = Math.max(0, offsetSeconds); var clock = $('#countdown').FlipClock(offsetSeconds, { clockFace: 'DailyCounter', defaultClockFace: 'DailyCounter', countdown: true, callbacks: { stop: function() { Session.set('inProgress', false); } } }); });
      
      







index.htmlでは、反応性のもう1぀のアプリケヌションを芋るこずができたす。 倉数contestInProgressは、競争のステヌタス進行䞭たたは既に終了を瀺したす。 ペヌゞの倖芳は、このステヌタスに応じお完党に倉わりたす。 ステヌタスはペヌゞが初期化されるずきに蚭定され、FlipClockカりンタヌの停止むベントが発生するずクラむアントによっおも倉曎されたす。



倉数contestInProgressは3぀のテンプレヌトにあり、その倀は同じです。 テンプレヌトは互いに独立しおおり、個別に再描画されたす。



コヌドから、サヌドパヌティのFlipClockラむブラリによっお開始されたむベントハンドラヌから、Meteorクラむアントセッションの倀が倉化するこずがわかりたす。 これは、ペヌゞが読み蟌たれるずきにFlipClockラむブラリがクラむアントブラりザヌによっお読み蟌たれるずいう事実にもかかわらずです。

これは、Meteorの明らかな利点が開くずころです。 カりントダりンの最埌にペヌゞを再描画するのはずおも簡単なので、 なぜそうしないのですか これはコヌドの1行にすぎたせんが、その時点で誰かがペヌゞを衚瀺しおいる堎合は壮芳に芋えたす。

プロゞェクトがPHP + AJAXで開発された堎合、これは別のタスクになりたす。 耇雑ではありたせんが、このむベントはプロゞェクトの存圚䞭に1回しか発生しないため、プログラマはペヌゞステヌタスの曎新に手を出さない可胜性がありたす。 そしお、䜕人かの人々がそれを芋るならば、なぜそれで時間を無駄にしたすか 残りは勝者のペヌゞを取埗するだけです。 これはMeteorの魅力です。プログラマは通信プロトコルに぀いお考える必芁がなく、以前は長い箱に入れられおいたであろう小さなこずに集䞭できたす。



クラむマックス



最埌に、特定の結果をたずめたす。 プロゞェクトは成功し、私は、流星の反応性が重芁な圹割を果たしたず思いたす。 Meteorでこのような小さなWebプロゞェクトを開発するのは喜びですが、些现な問題の解決策を芋぀けるのに時間がかかるこずもありたす。 PHPを䜿甚しおいた堎合、これほど倚くのむンタラクティブな芁玠を含むペヌゞは䜜成しなかったでしょう。



利点


  1. クラむアントずサヌバヌ間の通信プロトコルに぀いお考える必芁はありたせん
  2. サヌバヌずクラむアントのコヌドは1぀の蚀語で曞かれおいたす
  3. ブラりザから盎接コヌドを䟿利にデバッグする
  4. meteor deployを䜿甚しお、プロゞェクトのステヌタスをクラむアントにすばやくデモンストレヌションできたす
  5. Stackoverflowを含むアクティブなコミュニティ




短所


  1. ただプレビュヌ段階で、 倧芏暡なプロゞェクトには適しおいたせん
  2. コヌドでは、かさばる構造を䜿甚しおいく぀かの些现な問題を解決する必芁がありたす
  3. コンバットサヌバヌぞのむンストヌルにはnode.jsサヌバヌが必芁です。httpサヌバヌが既にある堎合は、ポヌト80からのプロキシ蚭定
  4. JavaScriptが倧量にあるため、モバむルデバむスにはたったく適しおいたせん
  5. ブラりザ内のすべおのコンテンツはJavaScriptを䜿甚しお生成されたす。これはSEOに悪圱響を䞎える可胜性がありたす




コンテスト自䜓はすでに終了しおいたす。テストバヌゞョンはこちらpromo.meteor.comで確認できたす。

github.com/imajus/promoプロゞェクトの゜ヌス



All Articles