古いnode.js(0.10.x)でMoment.jsのプラグインとMoment Timezoneを両方使った時に出るエラーと、修正方法をご紹介。
経緯
- 自分が作ったHubotのScript「hubot-amesh」を入れたHubotをHerokuにデプロイし、コマンド(amesh)をリプライしたら何も返ってこず、ログを見たらエラーが出ていた。
- エラーはMoment.jsのプラグイン「Round」のfloor関数が無いというエラー(
has no method 'floor'
)だった。 - 自分の環境では動いていた。
エラー箇所
moment = require 'moment-timezone'
require 'moment-round'
# ...
getFilename = ->
moment()
.tz('Asia/Tokyo')
.floor(5, 'minutes')
# ^ <- ここ
.format('YYYYMMDDHHmm')
node.jsのバージョンが6.3.1のローカル環境では動いていた。
調査
- Herokuのnode.jsのバージョンを確認
-
0.10.46
- 理由はHubotの雛形のgenerator-hubotのpackage.jsonでengines.nodeが
0.10.x
と設定されているため
- 理由はHubotの雛形のgenerator-hubotのpackage.jsonでengines.nodeが
-
- enginesの部分を下記のように自分の環境と合わせる
- npmのバージョンも指定できるので指定する
{
...
"engines": {
- "node": "0.10.x"
+ "node": "6.3.1"
+ "npm": "3.10.3"
}
}
上記のバージョン指定の修正を加えることでエラーが起きなくなった。
古いnode.jsで起きるエラーでした。
READMEに対応するnode.jsのバージョン書いてめでたしめでたし。。。
、、、って思ったけど、HubotをHerokuで使ってる人の何人がpackage.jsonのenginesでHerokuのnode.jsのバージョンを変えられると知っているだろうかと考えると、script自体を0.10.xに対応させた方が良い気がした。
0.10.xでMoment.jsのプラグインとMoment Timezoneを共存させる
というわけで本題。
0.10.xに対応させるためscript修正する。
momentTimezone = require 'moment-timezone'
moment = require 'moment'
require 'moment-round'
# ...
getFilename = ->
tokyo = momentTimezone().tz('Asia/Tokyo')
moment(tokyo).floor(5, 'minutes').format('YYYYMMDDHHmm')
moment-timezoneとmomentを別変数に持ち、
moment-timezoneでタイムゾーンを指定した時間オブジェクトを作ってから、
Moment Cloneの仕組みを使って時間オブジェクトをコピーして次の処理を行う。
こうすることによって0.10.xでもエラーが出なくなった。
node.jsのバージョン変遷に詳しくないのだが、0.10.xと6.xではnpmのパッケージの管理方法が違うのではないかと思った。
あるいは、requireのアルゴリズムが違う?
ともかく、試行錯誤して答えが見つかった。
ゆる募
なんで0.10.xと6.xでこういう差が出るのか解説記事があればぜひ教えて下さい。
おまけ
経緯の中でも紹介していますが、「hubot-amesh」というscriptを作りました。
「amesh」と話しかけると現在の雨の状況を画像で教えてくれます。
※ ImageMagick(Herokuにはデフォルトで入っています。)とimgurのClient IDが必要になります。
ぜひ使ってみてください。