「node.js」と一致するもの

先日の記事で、 ブログシステムとしてGhostを使ってherokuにデプロイする話を紹介しました。

ところが使い始めてみるといくつか問題がありました。

  1. herokuはアクセスが無いとスリープするので、サイトを初めて開くときに時間がかかる
  2. 常にアクセスが来るとスリープはしなくなるが、Freeプランの範囲を越えてしまい、Hobbyにアップグレードするように催促が来る
  3. 画像ファイルを置けないのはやはり多少不便である

そこで、hexoに移行してみることにしました。デプロイ先はgithub.ioです。 github.ioがどこまで使えるのかは分かりませんが、少なくともherokuのfree planよりはよさそうです。

hexoはghostと違ってスタティックなサイトを生成するだけですが、markdown形式のファイルを入力とするので、 移行は比較的楽かと期待しました。 Ghostのmarkdownプレビュー機能は便利だったのですが、それは残念ながら諦めることにしました。ちゃんと探していませんが、オーサリング側の拡張もありそうです。

移行時に気づいたことをまとめておきます。 全体的に、Ghostの方が出来が良くて、hexoでやりたいことを再現するのに苦労した感じです。

markdownの変換が不完全な場合がある

Ghostでは問題なかったmarkdownの変換がhexoではうまく行かないケースがいくつかありました。 今回テンプレートにhandlebarsを使ったのでそれが原因かもしれません。 例えば、{{foo}}のような記述がうまく変換できませんでした。&#x7b;{foo}}とすることで解決。 他にも、<code>の変換結果が異なりました。これは問題という訳でもないですが。

handlebarsがサポートされていない

Ghostで標準のhandlebarsがhexoではコミュニティサポートであり、サポートされていませんでした。 どうやら、hexo v2からhexo v3で大幅な変更があったようで、プラグインなどが追従できていないようです。 これはなんとかしました。

Casperの移植が大変だった

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

これで期待通りになりました。

色々考えた結果、herokuを使うのが一番手軽だと思い、Ghostをデプロイしてみることにしました。 file storage問題は既に取り組まれていて、storage moduleでfile以外の方法も使えるようになったようです。 具体的には、Ghost S3 Storageというのがあるようです。 個人的には、mongodbをバックエンドにしたstorageとかできないかなと期待します。

さて、Ghostをherokuにデプロイする簡単な方法はないか調べたところ、 https://github.com/cobyism/ghost-on-heroku というのがありました。 これは便利と思って早速試そうとしたところ、メール機能の有料アドオンを使う設定になっていて それを外す方法が分かりませんでした。

そこで、通常の方法でデプロイすることにしようと思いました。 参考にしたサイトはhttp://www.autodidacts.io/host-a-ghost-blog-on-heroku/です。 ところが、作業を開始してから思いの外手順が多いことに気づき、 作業メモの利用価値が低くなってしまいそうでした。 これでは再利用性がなくなってしまいます。

そこで、方針を戻して、ghost-on-herokuをforkすることにしました。 有料アドオンを使っているところをやめて、GMailでメール機能を使えるようにします。 Ghostのソースを調べると思っていたように、NodeMailerが使われていたため、簡単そうです。 ghost-on-herokuをみようみまねで編集して、ボタンひとつでデプロイできるようにしました。

こちらです。

https://github.com/dai-shi/ghost-on-heroku

ボタンひとつでデプロイできます。動作確認はこれからですが。

このherokuのテンプレート機能便利だと思いました。他にも使えそうです。

node.jsのデプロイ先としてはherokuを使うことが多いのですが、 他にはどういう候補があるのか調べてみようと思いました。 昔の記事を見ると手軽に使えそうだった、Nodejitsu, AppFog, Node Ninjaなど 使えなくなった(もしくは、以前より使いにくくなった)ものもあります。 また、最近Ghostを試してみたいと思ったのですが、 herokuがサポートされていない(ファイルアクセスができない)こともあり、 他の候補を調べてみることにしました。

条件は、無料で使えるプランがある(一定期間でも)ことです。 網羅はできていないと思います。順不同です。 実際に試したわけではなく、サイトから得られる情報をまとめただけです。

flow.ch

Flow App Engineは、Java, PHP, Ruby, Node.js, Python or .NET (Beta) を動作させることができて、dockerのイメージも動かせるそうです。 各種データベースも用意されているとのこと。 webベースのdashboardで簡単に操作できるようです。

free trialは14日間です。pricingは、usage-basedとfixedの2種類とのこと。

modulus.io

Modulusは、Node.js,PHP, Javaが使えます。Meteorがサポートされているのも特徴のようです。 modulusというコマンドをインストールして、デプロイ作業をするようです。 その他必要そうなものはひと通り揃っているように見えます。

sign upすると30日間使える$15分のクレジットがもらえるようです。 しかし、一番安い構成でも月に$28.80になるので、30日連続運用はできないことになります。

dotCloud

dotCloudは、Python, Java, Node.js, PHPが使えるようです。 デフォルトはMySQLですが、他のストレージのadd-onもあります。MongoDBもMongoSoupというのがあるようです。 特徴的なのは、プラットフォームへのアクセスで、 CLIのツールと、Webコンソールと、REST APIが用意されているとのこと。

Sign up for Freeとありますが、実際無料でどこまで使えるか分かりませんでした。 一番小さい構成では、月$9.90のようです。

cloud.google.com

Google Cloud Platformは、IaaSに近い感じですが、 Cloud Launcherを使って簡単にStackを構成できるようです。MEANも使えるようです。

Free trialでは、$300分を60日間使えるそうです。

bluemix

IBM Bluemixは、OSSのCloud FoundryをベースとしたPaaSです。 色々使えるようですが、一例として、Node.js, PHP, Python, Rubyがあげられています。

フリートライアルでは、30日間使えるそうです。

現在、アプリ開発コンテストが開催中とのこと。

まとめ

残念ながら、期間限定なしでfreeで使えるサービスは見つけられませんでした。 freemiumは最近は流行りではないのでしょうかね。 herokuもfreeの範囲が狭まることになりましたし、厳しい情勢です。

node.jsとかブラウザで簡単な統計処理をしようと考えて使えそうなライブラリがないか調べました。 できるだけ依存ライブラリがないものがいいです。

構築にMakeを使うと書いてアイルからネイティブコードがあるのかと思いましたが、そうではなくpure JavaScriptでした。 http://jstat.github.io/にドキュメントがあります。かなり色々な関数がそろっているようです。 検定などもできるようです。JavaScriptのArrayをそのまま渡すこともできるので、お手軽です。 GitHubのStarは712です。

こちらも同じような感じです。Arrayを使うのが基本です。回帰や分類もできるようです。 これが紹介ページですが、フォントがいい感じです。 GitHubのStarは821なので、jStatとこれがメジャーどころでしょうか。

こちらはCollectionやVectorといったクラスを導入して抽象化しているようです。 と思いましたが、作られたオブジェクトは普通のArrayとしても扱うことができ、とても便利そうです。 READMEにはJavaScript標準のMathと連携しているサンプルが載っています。 JavaScriptのprototype chainのおかげですね。魅力的です。 Star数は327です。

ドキュメントページはこちらです。 Star数は711なので初めの2つと同じくらいですね。ここまで来るとStar数だけでは判断できないでしょう。 Vector and Matrix math for JavaScriptというふれこみで、他のものよりMatrix系が充実しているようにも見えます。

READMEにはほとんど情報がないのに、Star数が530という状態が不思議です。最近更新されていないところを みると過去に集めたStarでしょうか。それともどこか別のところにドキュメントページがあるのでしょうか。 Rっぽいことができるらしいです。コードとしては枯れているのかもしれません。

これまでのライブラリと比べると小規模なもので、Arrayを拡張して基本的な関数群を追加してくれます。 機能は少ないですが、これだけがやりたい場合はいいかもしれません。Star数は23です。


最後に、こんなページを見つけました。 中身はよく理解していませんが、JavaScript(というかv8)は意外と速いと言う気付きだそうです。

http://julialang.org/には新しく、もう少し見やすいベンチマークの表が載っています。

上記のライブラリたちのベンチマークも気になるところです。

以前の記事で、 x-rayというライブラリを使ってスクレイピングをしてみた話を書きました。 その時に、ページネーションだけでなく、リンク先取得もできればいいと思ったのですが、 先日バージョンアップしていた2.0.0ではすばらしいことに複合的な処理が書けるようになっていました。

さっそく、試してみましょう。 サンプルををちょっといじって実行してみます。

var xray = require('x-ray')();
xray('https://www.google.com/', {
  title: 'title',
  image: xray('#gbar a:nth-child(2)@href', 'title'),
  map: xray('#gbar a:nth-child(3)@href', 'title'),
  play: xray('#gbar a:nth-child(4)@href', 'title'),
  youtube: xray('#gbar a:nth-child(5)@href', 'title')
})(function(err, obj) {
  console.log(obj);
});

ちゃんとそれぞれのページのタイトルが取れました。 「画像検索」はなぜか文字化けしました。

これは便利です。しかも、delayやthrottleの設定までできます。 今度勉強がてらコードも読んでみるといいかもしれません。

また、小ネタでした。

ところで、x-rayってだけだと検索キーワードとしてはあいまいすぎますね。

今さらながら、node-v0.12.3を入れました。 vmが新しくなったことはどこかで聞いたのですが、timeoutが指定できるようになっているというのは認識できていませんでした。

これまで、 rss-pipes や codeonmobile で、vmモジュールを使ってなんちゃってsandbox環境を作っていました。 その際、無限ループだけは避けたかったため、safeCode.jsというのを作って ループのカウントをしてexceptionを投げるようにしていました。

ところが、node-v0.12で新しくなったvmはtimeoutの指定ができるので、簡単にできるようになりました。 今後はこれを使うことにします。

サンプルコードはこちら。

var vm = require('vm');
var x = vm.runInNewContext('x=0;for(i=0;i<100;i++){x++;}x', {}, {
  timeout: 10
});
console.log(x);
x = vm.runInNewContext('x=0;for(i=0;i<10000;i++){x++;}x', {}, {
  timeout: 10
});
console.log(x);

実行するとこんな感じ。

$ node vm-test.js
100

vm.js:38
  return this.runInContext(context, options);
              ^
Error: Script execution timed out.
    at Error (native)
    at ContextifyScript.Script.runInNewContext (vm.js:38:15)
    at Object.exports.runInNewContext (vm.js:69:17)
    at Object.<anonymous> (/tmp/vm-test.js:6:8)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:501:10)
    at startup (node.js:129:16)

というわけで、なんちゃってsandboxが簡単に作れるようになりました。 ドキュメントにはuntrusted codeは別processで走らせるべきだというように書いてあります。確かに、メモリを大量に消費するようなmalicious codeには対処できないと思います。他にはどういう穴があるのでしょうか。globalオブジェクトだけを渡しているうちはそこまで悪いことはできないような気もしますが、どうなんでしょう。

http://dailyjs.com/2015/02/05/xray/ で紹介されていたx-rayというツールを試してみました。

https://github.com/lapwinglabs/x-ray のサンプルをほぼそのまま実行しました。

すこし脱線しますが、yieldableというのを知りました。利用者がcallbackタイプとyieldタイプを使い分けられるのはいいですね。

x-rayはpaginationがサポートされているのが便利でした。もう一歩進んで、一つリンクを進んで詳細ページも扱えるといいのですが。

さて、プロクシの設定をしたかったのですが、x-ray自体にはサポートされていません。しかし、内部で使われているsuperagentを差し替えることはできます。superagent-proxyというライブラリがあるのでそれを使えばできそうです。 今回はいつも使っているrequestを使ってみました。下記にコードスニペットを載せておきます。

var xray = require('x-ray');
xray.prototype.request = function(url, callback) {
  require('request').get(url, function(err, response, body) {
    callback(err, body);
  });
};

あまりうまいやり方ではないですが、一応こんな感じで動いています。

小ネタでした。

ちょっとチャレンジングなタイトルにしてみました。

nodeを使った開発では、タスクランナーというものがあるらしいです。 ユーザ数が一番多いのはgruntなんですかね。 というのも、実はこれまで使ったことがないのです。 使わなければいけないシーンがなかったです。 タスクランナーの印象は、何というか、簡単なことをするために、大変なことをしている感じです。

似たようなことを考えている人はいるんだろう、と思って、 検索してみました。

http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/

最近の記事です。npmで全部できる、と。 windowsでの対処法も書かれていて参考になります。 パッケージによっては、windowsでも**.jsと書けるそうです。

http://substack.net/task_automation_with_npm_run

npmのscriptsフィールドを使おう、と。 ./node_modules/.binにパスが通っているので 依存パッケージとしてインストールすれば簡単に使えます。

https://mattandre.ws/2014/08/task-runner-npm-scripts/

これもだいたい同じです。windowsのことは考えられていませんが。

http://anders.janmyr.com/2014/03/running-scripts-with-npm.html

これにはコンプリーションの話が載っていました。

自分だけのプロジェクトの場合は、windowsのことは気にせずnpmだけですんでしまいますね。一番上の記事をちゃんと読むと、windows対応も意識すればそこそこできそうです。

gruntのエコシステムもすばらしいと思うのですが、個人的には依存パッケージが増えるのを好みません。9割程度のタスクはnpmでも十分にできそうです。というわけで、これからはpackage.jsonのサンプルなども記事にしてみようかと思いました。

LiveReloadをご存知でしょうか。Web開発をするときに、ブラウザのリロードを省く機能を提供するものです。 類似のものとしては、Live.jsというのもあります。 また、Meteorでも実装されています。

一言で言うと、websocketでコネクションを維持して、サーバ側のファイル変更を通知して自動でリロードするものです。 CSSの場合はリロードせずに変更を適用することもできます。 livereloadは商用のようですが、そのコアのソースコードはMITライセンスで公開されています。

livereloadはブラウザ拡張を使うことがメインのようですが、javascript版のクライアントもあります。 javascript版だと、mobile safariでも動きます。 livereloadのnode.js用のサーバは、https://github.com/livereload/livereload-serverで公開されていますが、 これはそのまますぐには使うことができません。 平たく言うとプロトコルが実装されているだけで、実際に更新通知する機能は含まれていません。

そこで、簡単に使えるライブラリとしてまとめてみました。特徴をまとめると、

  • livereloadのサーバコードの最新版を使用(現在npmに登録されているlivereload系のモジュールはほとんど旧バージョン)
  • livereloadのクライアントコードの最新版を使用(npm化されていないのでnapaというモジュールで導入)
  • fs.watch()を使ってファイル変更を迅速に監視(node-watchというモジュールを使用)
  • node-devを使うことでサーバ側のファイル変更を監視して、クライアントを自動リロードする機能を追加
  • これらの機能をたった一行を加えるだけで使えるようにパッケージ化

となります。

プロジェクトページは下記です。

https://github.com/dai-shi/easy-livereload

最低限の使い方は、

app.use(require('easy-livereload')())

ですが、細かい設定はオプションを引数に与えることでできます。

本質的には他人が作ったライブラリを結合して簡単に使えるようにしただけですが、 相当便利だと思いますので、ぜひお試しください。