2013年3月に開始した本ブログですが、更新ペースが落ちてきたことと、 フリーランサーに転向してsunday hackingがeveryday hackingになったため、 本ブログは一旦終了しようと思います。
今後は、@dai_shiでつぶやくか、外部のブログサービスに投稿することで発信していきたいと思います。
なお、フリーランサーとしてのコンタクトページはこちらにありますので、 ご用命などありましたらぜひご連絡ください。
ありがとうございました。
Node.jsやAngularJSなどを使ってWebアプリを開発するときに気づいたことをメモする技術系ブログ
Meteorには様々な便利パッケージがありますが、 その中でもうまく使えばだいぶコーディングを省けるパッケージを紹介します。 autoformはフォームを生成するためのパッケージです。 MongoDBのスキーマを定義しバリデーションするsimple-schema とともに使います。 collection2とも使えます。 今回はsimple-schemaで説明します。
初めに、パッケージのインストールは、
meteor add aldeed:simple-schema aldeed:autoform check
です。バリデーション用のcheckパッケージも入れました。
例えば、毎日の体重を記録するアプリを想定しましょう。 コレクションの定義は、
Records = new Mongo.Collection('Records');
となります。これのスキーマを定義するには、
RecordSchema = new SimpleSchema({
date: {
type: Date
},
weight: {
type: Number
}
});
のようにします。この例は単純ですので直感的と思いますが、より詳しくはsimple-schemaのドキュメントを参照ください。
さて、このスキーマを使ってフォームを作成するには、
<template name="inputForm">
{{> quickForm id="inputForm" schema="RecordSchema" type="method" meteormethod="/records/insert"}}
</template>
とします。これにより、
このような感じでフォームが完成しました。このフォームはtypeに合わせて適切なコンポーネントが使用されている上、値が入力されていなかったり不適切な場合はアラートメッセージを表示してくれます。
フォームがsubmitされた際にはmeteor methodsが呼び出されます。この実装は例えば下記のようになります。
Meteor.methods({
'/records/insert': function(doc) {
check(doc, RecordSchema);
Records.insert(doc);
}
});
このcheck
が重要で、これがないと不正なデータを登録できてしまいます。フォームのバリデーションはクライアントサイドだけの話なので。
このcheck
すら冗長だと考える方はcollection2を使ってみるとよいでしょう。
autoformの最も簡単な紹介でした。これ以外にも色々柔軟な使い方ができるので、おすすめのパッケージです。
最後に全体のコードを載せておきます。これだけですので、まずは試してみるとよいでしょう。
HTMLファイル
<body>
{{> inputForm}}
</body>
<template name="inputForm">
{{> quickForm id="inputForm" schema="RecordSchema" type="method" meteormethod="/records/insert"}}
</template>
JavaScriptファイル
Records = new Mongo.Collection('Records');
RecordSchema = new SimpleSchema({
date: {
type: Date
},
weight: {
type: Number
}
});
Meteor.methods({
'/records/insert': function(doc) {
check(doc, RecordSchema);
Records.insert(doc);
}
});
Meteor 1.2からはAngularとReactのサポートも追加されましたが、Blazeも根強い人気があります。今回はそんなBlazeをちょっと使いやすくするパッケージを二つ紹介します。
初めに紹介するパッケージは、Handlebar-helpersです。
インストールは、
meteor add raix:handlebar-helpers
です。これを使うと、テンプレートで、
{{#if $lt counter 10}}
のようなことが書けるようになります。実は本来テンプレートにはロジックを書くのはよろしくないので、これはあまり好まれない場合があります。しかし、通常の書き方だと、
{{#if isCounterLargerThanTen}}
のようになりヘルパー関数を用意する必要があります。よって、小規模プロジェクトなどでは原則を破ってロジックを書いてしまった方が効率がよい場合もあると思います。
次に紹介するパッケージは、blaze-magic-eventsです。
インストールは、
meteor add themeteorites:blaze-magic-events
です。これも好みが分かれるところですが、イベントハンドラを書きやすくするものです。テンプレートに、
<button onclick={{sayHi}}>Say Hi!</button>
と書いて、JavaScriptコードに、
Template.helloworld.events({
sayHi (event, template) {
console.log('event and templateInstance params', event, template)
template.$('p').html('hi there from sayHi() handler!')
}
});
と書きます。これも微妙にロジックを書いてしまっているので美しくないのですが、jQueryに慣れている人は分かりやすいかもしれません。
最後にせっかくなので、自分のパッケージも紹介しておきます。blaze-showhideです。これもテンプレートに簡単なロジックを書いて表示・非表示を切り替えるようにするものです。
以上、テンプレートにはロジックを書かないという原則を破ってちょっと便利にするパッケージの紹介でした。
以前、Angular向けに自分で開発したsocial-cms-backendは今もメンテナンスしていますが、 これのMeteor版があったら面白いだろうなと思っていました。Meteor版だとfrontendも含まれるので、単にsocial-cmsと呼ぶものになるかなとか。 既に、似たようなものが既にあったので紹介します。自分で作る手間は省けたものの、作ってみたかったという気持ちもあったりします。
一つは、ryw:blog (GitHub)です。 これは他のアプリに組み込むライブラリとしての位置付けで作られたもので、 なんとiron-routerとflow-router両方に対応しているということです。 単体で動かそうと思うと、意外とパッケージ導入に手間がかかりました。 参考までに手順をまとめておきます。
meteor create test-app
cd test-app
meteor add ryw:blog
meteor add kadira:flow-router kadira:blaze-layout
meteor add twbs:bootstrap ian:accounts-ui-bootstrap-3
meteor add accounts-password
meteor run
その後、htmlにログインボタンを設置すれば一応動きます。 ただし、デフォルトでは全員管理者になってしまうので、ロール管理しようとするともう少し複雑になります。 accounts-admin-ui-bootstrap-3 を使うとよさそうですが、初期の管理者を手動で設定する必要があったりと多少導入にハードルを感じます。 もっと簡単にスタンドアローンで動かすための整備は、まだ残件かなと思いました。
UIはいろいろカスタマイズできるようになっているようですが、コメント機能がないのは不完全な感じがします。 DISQUSを使う方法が説明されていますが、スタンドアローンで機能拡張できるとよいです。 そういう意味では、ライブラリとして使うものなのか、すぐに使えるようにするものなのかが曖昧に感じてきました。 このあたりもう少しいじってみたいような気もします。
さて、ついでにもう一つのパッケージを紹介します。 xolvio:md-blog (GitHub)です。 これは、The Meteor Testing Manualで実際に使われているアプリのパッケージのようです。 こちらにデモサイトがあるので様子が分かります。 表示のカスタマイズやロールの設定もできるようです。 試してはいませんが、スタンドアローンで動くアプリを作るのが目的であればこちらの方が楽かもしれません。
感想ですが、だいぶ便利なものが作られているなと思う一方で、まだまだ色々登場しそうですし、何か作ってみたいなと思います。
MeteorでGoogle Mapsを使うライブラリとしては、 dburles:google-maps が有名なようですが、使ってみたところちょっと気に入りませんでした。 せっかくBlazeがシンプルな設計になっているのに、全然お手軽な感じがしません。 リアクティブにするためのサンプルが載っていますが、アプリ開発者の仕事になってしまっています。 慣れている人はいいですが、Blaze初心者にはつらい感じです。
ないものは作ろうということで、作りました。
https://atmospherejs.com/daishi/blaze-google-maps
全部のAPIをサポートしているわけではないので、ライブラリとして置き換えられるようなものではありません。 しかし、マーカーをコレクションから読み込んで表示することに限れば、素直に使えるのではないかと思います。 もちろん、リアクティブに動作します。
Google Maps APIをMeteorから使ってみようと思う方はぜひお試しください。
10/6追記
なぜか「ライブラリ」と書いていましたが「パッケージ」と書くつもりでした。
Meteorの標準テンプレートであるBlazeはシンプルで割と気に入っています。 最低限の機能が用意されていて、あとは自分でがんばってねという感じが悪くないです。 ただ、Angularに慣れてしまうとこんなことはできないのかなどと思うことがあります。
その一つが、ng-showみたいなこと。ng-clickと合わせて表示を切り替えることがしばしばあります。
Blazeでは{{#if}}を使うと似たようなことができます。これはおそらくng-if相当です。具体的には次のようになります。
<template name="foo">
{{#if hello}}
<p>Hello World!</p>
{{/if}
</template>
と
Template.foo.helpers({
hello: function() {
return Session.get('hello');
}
});
さらに表示を切り替えるボタンは例えば次のようになります。
<template name="bar">
<button>Toggle</button>
</template>
と
Template.bar.events({
'click button': function(event) {
event.preventDefault();
Session.set('hello', !Session.get('hello'));
}
});
ちなみに、AngularだとHTML内にロジックを書いてしまえば次のように書けます。
<p ng-if="hello">Hello World!</p>
<button ng-click="hello = !hello">Toggle</button>
そこで、Blazeでも簡単に書けるようにするパッケージを作ってみました。
https://atmospherejs.com/daishi/blaze-showhide
これを使うと、
<div>
{{#showIf name="hello"}}
<p>Hello World!</p>
{{/showIf}}
{{#toggleShowHide name="hello"}}
<button>Toggle</button>
{{/toggleShowHide}}
</div>
こんな感じで書けるようになります。Sessionはアプリで共通なので実際に使う場合は他のtemplateと競合しないように注意する必要があります。
ng-ifやng-showを使いたいのならangular-meteorを使えばよいのではないかという意見もありますが、それはそれとしてBlazeでもパッケージでこういうやり方ができるということが分かりました。
余力があればやってみたいことは、ng-show相当の機能や設定のカスタマイズなどです。 余力というかモチベーションですが。
ところで、既に似たような機能を持つパッケージがないか探したのですが、見つかりませんでした。 もしかしたら、探し方が不十分であるパッケージの一機能として実現されているものもあるかもしれません。 いずれにしてもパッケージ作りの勉強になりました。
最近、Meteorの勉強中です。何かパッケージを作ってみたいと思ったのですが、多くのものはすでに誰かがやっています。 MeteorのパッケージはAtmosphereで探します。
今回、自分が使おうと思ったものにぴったりのものが見つからなかったので、作ってみました。 探したものはFacebookのAPIを呼び出すライブラリです。OAuthのライブラリはMeteorで提供されているのですが、Graph APIを使うものは3rt partyのものを探しことになります。
見つけたのはこれらです。
いっぱいあるように見えますが、facebook-node-sdkはGitHubを見るとforkしているのが分かります。
https://github.com/jdrorrer/facebook-sdk/ ← https://github.com/dcsan/facebook-sdk ← https://github.com/biasport/facebook-sdk ← https://github.com/hugesuccess/facebook-sdk
ネットワーク図を見てもいいかもしれません。全部は表示されていないようですが。
さて、今回はサーバサイドのライブラリを探していたのでfbgraphとgraph-apiが候補なのですが、過去の検討で使っていたライブラリを使いたいという要求もありました。 そこで、そのライブラリをMeteorパッケージにラップしました。
作ったパッケージは、 https://atmospherejs.com/daishi/facebook-server-api です。
ソースコードは、GitHubにあります。 中身はなんと2行だけです。
一応、新規にFB.mapi
というAPIを用意しました。Meteor流のfibersを使った同期的APIです。
fibersはあまり好まないのですが、Meteorでやっていくには仕方ないかと諦め気味です。
先日の記事で、 ブログシステムとしてGhostを使ってherokuにデプロイする話を紹介しました。
ところが使い始めてみるといくつか問題がありました。
そこで、hexoに移行してみることにしました。デプロイ先はgithub.ioです。 github.ioがどこまで使えるのかは分かりませんが、少なくともherokuのfree planよりはよさそうです。
hexoはghostと違ってスタティックなサイトを生成するだけですが、markdown形式のファイルを入力とするので、 移行は比較的楽かと期待しました。 Ghostのmarkdownプレビュー機能は便利だったのですが、それは残念ながら諦めることにしました。ちゃんと探していませんが、オーサリング側の拡張もありそうです。
移行時に気づいたことをまとめておきます。 全体的に、Ghostの方が出来が良くて、hexoでやりたいことを再現するのに苦労した感じです。
Ghostでは問題なかったmarkdownの変換がhexoではうまく行かないケースがいくつかありました。
今回テンプレートにhandlebarsを使ったのでそれが原因かもしれません。
例えば、{{foo}}
のような記述がうまく変換できませんでした。{{foo}}
とすることで解決。
他にも、<code>
の変換結果が異なりました。これは問題という訳でもないですが。
Ghostで標準のhandlebarsがhexoではコミュニティサポートであり、サポートされていませんでした。 どうやら、hexo v2からhexo v3で大幅な変更があったようで、プラグインなどが追従できていないようです。 これはなんとかしました。
Ghostの標準テーマであるCasperががシンプルで使いやすくて気に入っていたのですが、 hexoのテーマには似たようなものがありませんでした。以前のCasperを移植したものはありましたが、 機能やデザインがいまいちでした。 Ghostに戻ろうかと何度も挫折しましたが、結果的になんとか自分が使いたいCasperの機能とデザインは移植できました。
当初の目的であった、herokuの課題への対応は、github.ioになったことで解消されました。 hexoで苦労したのはどれもCasperを使おうとしたことに起因するので、もっと素直に使う分には問題ないかもしれません。 苦労したおかげでテーマのテンプレートやCSSは理解が進んでいじりやすくなりました。
最後に一つ学んだこと、Ghostすごい。WordPressを置き換えることができるかもしれません。 (ただ、単純に代替として使うという意識ではきっとダメです、新世代に移行するという意識でないと)
機会があったらどこかでGhostもまた使いたいです。
あまりにも特殊な話なので書くか迷ったのですが、記録のために書いておきます。
Ghostはnode.jsベースのブログシステムです。 先日、Ghostをherokuにデプロイする話を書きましたが、 使ってみて一つだけ不便に感じることがありました。
エディタでC-hが効かないのです。
C-hというのは普段Backspaceの代わりに使っているキーバインドで、 Ctrlキーを押しながらhを押します。ないと困る人には困るのです。 ブラウザでも使えるようにしています。しかし、これが困るのはLinuxユーザだけかもしれません。 OSXの場合はCtrlではなくてCommandがありますし、Windowsの場合はそもそもC-hが効かないと思います。
GhostのMarkdownエディターは気に入ったので、なんとかしてC-hを使えるようにしたいところ。 ちなみに、C-hが使えない理由はC-hがGhostのショートカットに割り振られていて、 ヘッダータグの挿入になるからです。 ちょっと調べてみましたが、本家Ghostではすぐには解決しそうにない(あまりに特殊環境か)ので、 forkすることにしました。
https://github.com/dai-shi/Ghost
です。修正したコードはほんの2行です。 C-hとC-bに設定されていたショートカットをC-S-hとC-S-bにしました。つまり、Shiftキーも同時に押した時だけショートカットが有効になるようにしました。
さて、これをghost-on-herokuでも使いたいのですが、一筋縄では行きませんでした。 というのも、gitリポジトリからcloneしてデプロイするには、gruntのタスクを走らせて ビルドする必要があるからです。手動でやるのは簡単ですが、これをnpmでやる必要がありました。
結果的には、ghost-on-herokuのpackage.jsonを次のように修正することで解決できました。
diff --git a/package.json b/package.json
index 3af466a..aec84be 100644
--- a/package.json
+++ b/package.json
@@ -10,14 +10,37 @@
"private": true,
"version": "0.6.4",
"dependencies": {
- "ghost": "0.6.4",
+ "ghost": "https://github.com/dai-shi/Ghost/archive/0.6.4-for-emacs-keybinding.tar.gz",
"ghost-s3-storage": "~0.2.1",
"pg": "latest"
},
+ "devDependencies": {
+ "bower": "1.4.1",
+ "csscomb": "3.0.4",
+ "grunt": "0.4.5",
+ "grunt-bg-shell": "2.3.1",
+ "grunt-cli": "0.1.13",
+ "grunt-contrib-clean": "0.6.0",
+ "grunt-contrib-compress": "0.13.0",
+ "grunt-contrib-copy": "0.8.0",
+ "grunt-contrib-jshint": "0.11.2",
+ "grunt-contrib-uglify": "0.9.1",
+ "grunt-contrib-watch": "0.6.1",
+ "grunt-docker": "0.0.10",
+ "grunt-express-server": "0.5.1",
+ "grunt-jscs": "1.8.0",
+ "grunt-mocha-cli": "1.13.0",
+ "grunt-mocha-istanbul": "2.4.0",
+ "grunt-shell": "1.1.2",
+ "grunt-update-submodules": "0.4.1",
+ "matchdep": "0.3.0",
+ "top-gh-contribs": "2.0.2"
+ },
"engines": {
"node": "~0.10.0"
},
"scripts": {
+ "postinstall": "(cd node_modules/ghost/node_modules && ln -s -b ../../grunt-* .) && (cd node_modules/ghost/node_modules/.bin && ln -s -b ../../../.bin/bower) && (cd node_modules/ghost && grunt --force init && grunt prod)",
"start": "node server.js"
}
}
devDependenciesはもう少し削れるかもしれません。 この修正に加えて、heroku configの設定も行いました。
$ heroku config:set NPM_CONFIG_PRODUCTION=false NODE_MODULES_CACHE=false
これで期待通りになりました。
普通はそうではないのかもしれませんが、Emacsのキーバインドに慣れていると、 FirefoxのアドレスバーでC-hと打って履歴が表示されて困ることが多いです。
通常のUbuntuでは、
https://wiki.ubuntulinux.jp/UbuntuTips/Desktop/GnomeEmacsKeyTheme
にあるように、
$ gsettings set org.gnome.desktop.interface gtk-key-theme Emacs
を実行すれば解決しました。
ところが、LubuntuはGNOMEではないので、この方法は使えません。
調べたところ、~/.gtkrc-2.0
の設定ファイルに、
include "/usr/share/themes/Emacs/gtk-2.0-key/gtkrc"
と書いたら解決しました。よかった、よかった。
ただ、これはgtkのアプリでしか有効になりません。firefoxはたまたまできたのかもしれません。
openboxのキーバインドで個別に設定できるのかもしれませんが、 今のところ簡単な設定方法は見つけられずにいます。
小ネタでした。
7/20追記。
なんかすごい発見かと思って勘違いしましたが、通常の
gtk-key-theme-name = "Emacs"
の設定でも問題ありませんでした。
参考サイト: http://tiborsimko.org/emacs-bindings-in-gtk-apps.html
やはり、非gtkアプリでもできるようにしたいです。 しかし、 http://bbs.archbang.org/viewtopic.php?pid=30742などのやりとりを見ていると無理そうです。