Help us understand the problem. What is going on with this article?

Windows 7 の Rails で ExecJS が TypeError を吐くようになった

More than 3 years have passed since last update.

※「原因」に加筆し,タイトルの「Windows」を「Windows 7」に変えた(2015/02/04)

Rails アプリが軒並み死んだ

ある日突然,Rails がエラーを吐くようになった。

ExecJS::ProgramError TypeError: オブジェクトでサポートされていないプロパティまたはメソッドです。

ちなみに英語だと

ExecJS::ProgramError TypeError: Object doesn't support this property or method

のようだ。

bundle update をやったタイミングなのかどうか当初は分らなかったが,その日あたりからあらゆる Rails アプリが動かなくなっていった。

現象としては,app/assets/javascripts*.coffee なファイルが一つでも入っているとエラーが出る。

ただ,「ある日突然」よりも前に *.coffee からコンパイルされて出来た JavaScript が tmp/cache に残っていて,生きている(元の *.coffee が変更されていない)限りはエラーは出ないようだった。

CentOS 上では大丈夫だった。

異常が起こったのはこんな環境:

  • Windows 7
  • ruby 2.1.5p273 (2014-11-13 revision 48405) [i386-mingw32]
  • Rails 4.2, 4.1.8

CoffeeScript が 1.8.0 から 1.9.0 になってた

Rails がエラーを吐くようになったのは,どうも 1 月末あたりっぽい。

そこで,この頃にアップデートした gem が何かを調べてみた。すると,coffee-script-source が 1 月 29 日に 1.8.0 から 1.9.0 に上がってた。これが怪しい。

この gem は,CoffeeScript の処理系を提供するためのものらしい。つまり,CoffeeScript スクリプトを読み込んで JavaScript スクリプトに変換してくれるコンパイラー(JavaScript で書かれている)がこの gem の中に入っている。

gem のバージョン番号は CoffeeScript のバージョン番号に合わせてあるようだ。

coffee-script-source を 1.8.0 に戻す

Rails の Gemfile には coffee-script-source はあらわには書かれていない。

Gemfile に書かれているのは coffee-rails で,こいつが coffee-script に依存し,coffee-script が coffee-script-source に依存しているのだった。

そこで,Gemfile にあらわに

gem 'coffee-script-source', '1.8.0'

と追記してやると,正常に動くようになった。

ふぅ。この問題で半日以上つぶれた。

原因

TypeError が出た原因は私には分らない。

CoffeeScript 1.9.0 で何か非互換な変更が行われたのだろう。

Windows で問題が起こり,CentOS で起こらなかったのは,JavaScript の処理系の違いなのかな。

Rails は CoffeeScript を処理するため,JavaScript の処理系を必要とする。実際に JavaScript を実行させるのは ExecJS という gem の役目らしい。

ExecJS はその環境で使える JavaScript の処理系を自動的に選んで動かしてくれるのだとか。

Windows と CentOS で選ばれた JavaScript 処理系が違ったのではないかと思うが,詳細は分らない。

ともかく Rails は関係なくて,

gem "coffee-script-source", "1.9.0"
require "coffee-script"

p CoffeeScript.compile("x=1")

という簡単なコードでエラーが再現できることが分った。(1.9.01.8.0 にするとエラーは出ない)

追記:もうちょっと分った(2015/02/04)

TypeError の直接の原因は,CoffeeScript 1.9.0 で Object.create を使っていることっぽい。1.8.0 ではこれは使っていなかった。

ちなみにブラウザーの JavaScript エンジンで Object.create がサポートされたのは,Firefox なら 4.0,InternetExplorer なら 9.0(いずれも 2011 年リリース)から。

ということは,話がそれるけど,ブラウザー上で CoffeeScript の処理系を直接動かすような使い方をすると,IE8 以下は切り捨てることになるのだろう。

それから,ExecJS が Windows の cscript というコマンドを使って OS の JScript 処理系を呼び出していることも分った。cscript//E:jscript というパラメーターを渡し,スクリプトエンジンとして JScript を指定しているらしい。

Windows 7 が出たのは IE8 の時代だから,cscript で呼ばれる JScript が Object.create に対応してないバージョンというのは,原因としていかにもありそう。

新しい IE を入れても cscript で新しい JScript が呼ばれたりはしないのね。

追記:Windows 10 もダメ(2016/04/20)

Windows 10 に上げたので同じことをやってみたら,やっぱりダメだった。

「JavaScript の処理系が新しくなって,CoffeeScript 1.9.0 以上でもエラーが出なくなる」と予測していたので,これは意外だった。

教訓

気軽に

bundle update

とかやるとエラい目に遭うこともあると分った。

ただ,気軽に bundle update してなかったら,問題に気づくのがずっと先になり,今より対処に時間がかかっていたかもしれない。変更になった gem も多かっただろうし。

だから,やってよかったのだけど,タイミングがまずかった。他の仕事で忙殺されてたり,気持ちに余裕のないときにやるべきではなかった。

bundle update した直後にエラーが出るようになったんなら,私でもすぐに分ったかもしれないけど,今回は JavaScript のキャッシュが生きている(?)間はエラーが出なかった(らしい)のがつらかった。

scivola
主に Ruby 使ってます。 二十年来のコンパイラー恐怖症が Rust で治癒するか?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした