忘備録

日々の調べ物をまとめる。アウトプットする。基本自分用。

Meteorチュートリアルやってみた

というわけで、チュートリアルの要点をざっくりまとめる

チュートリアルURL

https://www.meteor.com/tutorials/blaze/creating-an-app

1. Creating an app

  • 「hot code push」:編集したソース(html, css, js)は即時反映される
=> App running at: http://localhost:3000/
=> Client modified -- refreshing (x4) #ソースの変更を監視して自動的にリフレッシュされる

2. Templates

HTML files in Meteor define templates

  • Meteorはhead、bodyとtemplateタグを解釈してHTMLファイルを生成する
  • templeteタグはMeteorのテンプレートとしてコンパイルされる
  • templeteは{{> templateName}}でHTMLに差し込むか、jsからTemplate.templateNameで参照できる

Adding logic and data to templates

  • MeteorはHTMLファイルをMeteor's Spacebars compilerによってコンパイルする
  • Spacebarsは{{}}を構文として解釈する
    • if文:{{#if}}
    • foreach:{{#each}}
    • textプロパティのデータの取得:{{text}}
    • taskテンプレートの参照:{{> task}}
  • helpersを定義することによって、テンプレートにデータを渡すことができる
// Template.bodyにtasks(配列データ)を渡す
Template.body.helpers({
    tasks: [
      { text: "This is task 1" },
      { text: "This is task 2" },
      { text: "This is task 3" }
    ]
});

3. Collections

  • MeteorはCollectionsによって永続データを保存する
  • collectionはMongoDBによって作成される
  • collectionsの中の項目は"documents"と呼ばれる
  • collectionオブジェクトは"new Mongo.Collection("hoge");"で作成できる
Tasks = new Mongo.Collection("tasks");
  • meteor mongoコマンドでMongoDB Shellが起動する
$ meteor mongo
MongoDB shell version: 2.6.7
connecting to: 127.0.0.1:3001/meteor
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
    http://docs.mongodb.org/
Questions? Try the support group
    http://groups.google.com/group/mongodb-user
meteor:PRIMARY>

4. Forms and events

Attaching events to templates

  • "Template.templateName.events(...)"の形でテンプレートにイベントリスナーを追加出来る
  • イベントハンドラの引数にはトリガーとなったイベントの情報が格納されたオブジェクトが渡される

Inserting into a collection

  • collectionに情報を追加する場合は、collectionオブジェクトのinsert()を利用する
// Tasksはcollectionオブジェクト
Tasks.insert({
    text: text,
    createdAt: new Date() // current time
});
  • collectionにはスキーマ定義なしに、作成時間など、どのような属性でも割り当てることができる

Sorting our tasks

  • collectionのソートはfind()の引数で定義できる
Tasks.find({}, {sort: {createdAt: -1}}); // Tasksはcollectionオブジェクト

5. Update and remove

Getting data in event handlers

  • イベントハンドラ内では"this"キーワードでイベントを呼んだオブジェクトを参照できる
  • 全てのdocumentsにはIDが振られていて"_id"で参照できる

Update

  • collectionを更新するにはcollectionオブジェクトのupdate()を利用する
  • update()の第1引数には操作対象を特定するためのセレクタを指定し、第2引数には操作内容を指定する
// Tasksはcollectionオブジェクト
Tasks.update(
    this._id, // 操作対象のdocumentを指定
    {$set: {checked: ! this.checked}} // checkedプロパティをtrue/falseで更新
);

Remove

  • collectionを削除するにはcollectionオブジェクトのremove()を利用する
  • update()の引数には削除対象のセレクタを指定する

Using object properties or helpers to add/remove classes

  • オブジェクトのデータを利用して出力HTMLを操作できる
<!-- checkedプロパティがtrueならcheckedクラスを追加 -->
<template name="task">
  <li class="{{#if checked}}checked{{/if}}">

6. Deploying your app

  • "meteor deploy"コマンドでデプロイができる
  • Meteorが用意しているテストサーバにデプロイすることもできる

テストサーバへのデプロイ

  • Meteorの開発者アカウントの作成が必要
  • メールアドレスの登録とパスワードの設定によってアカウントを作成する

ドメインが既に他のユーザに利用されている場合

$ meteor deploy my_app_name.meteor.com
To instantly deploy your app on a free testing server, just enter your email address!
                                              
Email: hoge@hoge.com
Sorry, that site belongs to a different user. 
                                              
Either have the site owner use 'meteor authorized --add' to add you as an authorized developer for the site, or switch to an authorized account with 'meteor login'.

パスワード設定を求められるので、表示されているURLにアクセスし、設定する

$ meteor deploy mktktmr-simple-todos.meteor.com
Deploying to mktktmr-simple-todos.meteor.com. 
Now serving at http://mktktmr-simple-todos.meteor.com
                                              
You should set a password on your Meteor developer account. It takes about a minute at:
https://www.meteor.com/setPassword?hogehoge
  • アカウント作成後は、メールアドレスとパスワードで認証が行われる
$ meteor deploy mktktmr-simple-todos.meteor.com
To instantly deploy your app on a free testing server, just enter your email address!
                                              
Email:hoge@hoge.com
                                              
Logging in as hogeo.
Password:                                     
Deploying to mktktmr-simple-todos.meteor.com. 
Now serving at http://mktktmr-simple-todos.meteor.com

7. Running on mobile

Running on an iOS simulator

$ meteor install-sdk ios
Please follow the instructions here:
https://github.com/meteor/meteor/wiki/Mobile-Development-Install:-iOS-on-Mac
  • iosプラットフォームを追加
$ meteor add-platform ios
ios: added platform
  • 実行
$ meteor run ios
[[[[[ ~/Documents/src/JavaScript/Meteor/simple-todos ]]]]]

=> Started proxy.                             
=> Started MongoDB.                           
=> Started your app.                                                            
                                              
=> App running at: http://localhost:3000/     
=> Started app on iOS Simulator.

本当に動いた 笑

f:id:mktktmr:20160119022001p:plain

Running on an Android emulator

。。。かと思いましたが、iOSと違ってsdk-toolにPATH通したり、
ただAndroidStudioが入っていればいいだけではないので、いちおう読んだ方がいいかも

$ meteor install-sdk android
Please follow the instructions here:
https://github.com/meteor/meteor/wiki/Mobile-Development-Install:-Android-on-Mac
  • androidプラットフォーム追加
$ meteor add-platform android
android: added platform

Your system does not yet seem to fulfill all requirements to build apps for Android.
                                              
Please follow the installation instructions here:
https://github.com/meteor/meteor/wiki/Mobile-Development-Install:-Android-on-Mac
                                              
Specify the --verbose option to see more details about the status of individual
requirements.

何かが足りないみたい。。。

「--verboseオプションつけてみ」とのことなので試してみる

$ meteor run android --verbose
Getting installed version for platform android in Cordova project
Getting installed version for platform ios in Cordova project
Checking Cordova requirements for platform Android
                                              
Your system does not yet seem to fulfill all requirements to build apps for
Android.
                                              
Please follow the installation instructions here:
https://github.com/meteor/meteor/wiki/Mobile-Development-Install:-Android-on-Mac
                                              
Status of the requirements:                   
✓ Java JDK                                    
✓ Android SDK                                 
✗ Android target: Please install Android target: "android-22".
  
  Hint: Open the SDK manager by running:
  /Users/makoto/Library/Android/sdk/tools/android
  You will require:
  1. "SDK Platform" for android-22
  2. "Android SDK Platform-tools (latest)
  3. "Android SDK Build-tools" (latest)
 Gradle

API Level 22のsdkが必要でした(23しか入っていなかった)
* sdkインスコして再度実行

$ meteor run android
[[[[[ ~/Documents/src/JavaScript/Meteor/simple-todos ]]]]]

=> Started proxy.                             
=> Started MongoDB.                           
=> Started your app.                          
                                              
=> App running at: http://localhost:3000/     
   Starting app on Android Emulator          \

androidもOK

f:id:mktktmr:20160119030347p:plain

ただ、めっちゃアプリの起動が遅いです。。。
エミュレータはすぐ起ち上がるのですが、それから3分くらい待ちました。

Running on an Android device

実機もちゃんと動いた。

f:id:mktktmr:20160119033814j:plain

8. Temporary UI state

  • "Session"変数はUIの一時的な状態保持に使える
  • "Session"変数はcollectionsの要領で利用できる
// 保持
Session.set("hideCompleted", event.target.checked);
// 参照
Session.get("hideCompleted")

Session is a reactive data store for the client

  • Sessionがcollectionと異なる点はサーバと同期しないこと
  • クライアントだけに保持したい値のために利用する

One more feature: Showing a count of incomplete tasks

  • コレクションオブジェクトのfind().count()を利用すると取得したdocumentsの数を取得出来る
//checkedプロパティがtrueのドキュメントの数を返す
Tasks.find({checked: {$ne: true}}).count();

9. Adding user accounts

  • 次のパッケージを追加するだけ簡単にログインシステムが実装が出来る
    • accounts-ui
    • accounts-password
# アプリケーションディレクトリにて以下のコマンドを叩くとログインシステムの実装に必要なパッケージが追加される
$ meteor add accounts-ui accounts-password
                                                                                
Changes to your project's package version selections:
                                              
accounts-base          added, version 1.2.2   
accounts-password      added, version 1.1.4
accounts-ui            added, version 1.1.6
accounts-ui-unstyled   added, version 1.1.8
ddp-rate-limiter       added, version 1.0.0
email                  added, version 1.0.8
less                   added, version 2.5.1
localstorage           added, version 1.0.5
npm-bcrypt             added, version 0.7.8_2
rate-limit             added, version 1.0.0
service-configuration  added, version 1.0.5
sha                    added, version 1.0.4
srp                    added, version 1.0.4

                                              
accounts-ui: Simple templates to add login widgets to an app
accounts-password: Password support for accounts
  • accounts-uiパッケージに"loginButtons"テンプレートが用意されている
  • Accounts.ui.configでアカウントUIの設定が出来る
Accounts.ui.config({
  passwordSignupFields: "USERNAME_ONLY" // メールアドレスの代わりにユーザ名で認証可能になる
});

passwordSignupFields: "USERNAME_ONLY"設定前 f:id:mktktmr:20160114210741p:plain

passwordSignupFields: "USERNAME_ONLY"設定後 f:id:mktktmr:20160114210743p:plain

  • Meteor.userId()でユーザIDを取得できる
  • Meteor.user()でユーザに関するdocumentを取得出来る
  • Meteor.user().usernameでユーザ名が取得できる
  • accounts-facebookパッケージを追加するとFacebookアカウントによるアカウントシステムが作れる
  • {{currentUser}}でログイン済みかどうかチェック出来る
  • {{currentUser.username}}でユーザ名が表示出来る

10. Security with methods

  • Meteorはデフォルトでinsecureパッケージが追加されている
  • insecureパッケージはクライアントから直接DBを操作することを許す

Removing insecure

  • アプリケーションディレクトリで以下コマンドを叩くとinsecureパッケージを除くことが出来る
$ meteor remove insecure
                                              
Changes to your project's package version selections:
                                              
insecure  removed from your project           

insecure: removed dependency 
  • Meteor.methods()を利用することでメソッドを定義することが出来る

remove insecure後にクライアントからinsert操作を行うと、以下のようにログにinsert操作が拒否されたことが出力される f:id:mktktmr:20160114215727p:plain

Defining methods

  • Meteor.methods({methodName: function (param){} })でメソッドを定義することができる
  • insecureパッケージを除いた場合、メソッドからDB操作をすることでできる
  • 定義したメソッドはMeteor.call("methodName", arg)で呼び出しができる

Optimistic UI

  • Meteor.call()を利用することで以下のメリットがある
    • AJAXでのリクエストのように、安全な環境でサーバにリクエストを送れる
    • クライアントでメソッドを実行することにより、サーバのレスポンスを予測できる(先読みして描画がするからUXが上がるってことかな)
  • まとめると、Meteor.callを利用するとセキュアなリクエストができて、ラウンドトリップの遅延を減らせる

11. Publish and subscribe

  • デフォルトはautopublishパッケージが適用されている
  • autopublishパッケージを除くとサーバがクライアントに送信するものを明示する必要がある
$ meteor remove autopublish
                                              
Changes to your project's package version selections:
                                              
autopublish  removed from your project        

autopublish: removed dependency
  • サーバーはMeteor.publish()でpublication登録することができる
  • クライアントはMeteor.subscribe()で登録されているpublicationを呼び出すことができる
if (Meteor.isServer) {
  Meteor.publish("tasks", function () {
    return Tasks.find();
  });
}

if (Meteor.isClient) {
  Meteor.subscribe("tasks");
}

Extra method security

  • Meteor.Error()でエラーを発生させることができる
  deleteTask: function (taskId) {
    var task = Tasks.findOne(taskId);
    if (task.private && task.owner !== Meteor.userId()) {
      // If the task is private, make sure only the owner can delete it
      throw new Meteor.Error("not-authorized");
    }
 
    Tasks.remove(taskId);
  }

ログインしていない状態で操作できなくなっているか確認

if (Meteor.isServer) {
  Meteor.publish("tasks", function () {
    return Tasks.find({
        // 試しにtaskの取得条件を外す
      /*$or: [
        { private: {$ne: true} },
        { owner: this.userId }
      ]*/
    });
  });
}

private taskは作成者本人にしか操作を許さない f:id:mktktmr:20160119011837p:plain

削除しようとしても例外が発生する f:id:mktktmr:20160119011842p:plain

。。。ここまでで、一応チュートリアルはおしまい

所感

すごく簡単にリアクティブなWebが作れたり、同じソースでモバイルアプリも作れてしまったり(ブラウザでいい気もするけど。。。)、 触っていて楽しいフレームワークでした。 AngularやReactと統合もできるみたいなので、js周りはしばらくこいつで遊べそう。