etsuxのブログ

自分がハマったことなどを記録しています。

Windows版のRuby On RailsでTypeError

Windows版のRuby On Railsを使おうとしたら、以下のエラーが出たので原因を調べてみる。

    ActionView::Template::Error (TypeError: オブジェクトでサポートされていないプロパティまたはメソッドです。):
    7: <%= stylesheet_link_tag 'application', media: 'all' %>
    8: <%= javascript_include_tag 'application' %>

以下のコマンド実行でエラーになっていることが確認できた。

    cscript //E:jscript //Nologo //U C:/Users/xxx/AppData/Local/Temp/execjsxxxxxxxx-xxxxx-xxxxxxxxx
    Microsoft JScript 実行時エラー: オブジェクトでサポートされていないプロパティまたはメソッドです。

エラーになっているJavaScriptのコード(execjsxxxx~の中身)は以下。

parse: function parse(input) {
    var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
    var args = lstack.slice.call(arguments, 1);
    var lexer = Object.create(this.lexer); ← ここでエラー
    var sharedState = { yy: {} };

単体で実行してもエラーになるのでObject.createはJScriptではサポートされていないようだ。

    <object_create.jsファイル>
    Object.create(null);
    cscript //E:JScript object_create.js
    Microsoft JScript 実行時エラー: オブジェクトでサポートされていないプロパティまたはメソッ ドです。

IE9以降でObject.createが利用可能とのこと。

JavaScript のバージョン情報

IE9以降のJScriptエンジンのJScript9にしてみたが、エラーが変わっただけで結局サポートされていない。

    cscript //E:{16d51579-a30b-4c8b-a276-0ff4dc41e755} object_create.js
    JavaScript 実行時エラー: オブジェクトは 'create' プロパティまたはメソッドをサポートしていません。

Windows 10環境を使っているので、EdgeのJavaScriptエンジンのChakraで動かしたら正常動作。

    cscript //E:{1b7cd997-e5ff-4932-a7a6-2a9e636da385} object_create.js

cscriptのJavaScriptエンジンをChakraに変えてRailsを実行したところ正常動作した。

lib\ruby\gems\x.x.x\gems\execjs-x.x.x\lib\execjs\runtimes.rb

JScript = ExternalRuntime.new(
      name:        "JScript",
-     command:     "cscript //E:jscript //Nologo //U",
+     command:     "cscript //E:{1b7cd997-e5ff-4932-a7a6-2a9e636da385} //Nologo //U",
      runner_path: ExecJS.root + "/support/jscript_runner.js",
      encoding:    'UTF-16LE' # CScript with //U returns UTF-16LE
    )

ただし、Windows 7とかにはC:\WINDOWS\System32\Chakra.dllがなく、上記の対処は環境が限定される(Windows 10だけ?)。

IActiveScriptProperty::SetPropertyのSCRIPTPROP_INVOKEVERSIONINGでスクリプトのバージョンを変更できるそうだが、JScript9が初期化された時点で設定するプログラムを作る必要があるので組み込むのは無理。

そもそも、CoffeeScript 1.9.0以降でObject.createを使うようになったことで今回のTypeErrorが発生するようになったらしいので、Object.createを使わないようにしてみる。

他にもObject.createを使用しているコードを探したところ、以下が参考になりそう。

lib\ruby\gems\x.x.x\gems\uglifier-x.x.x\lib\es5.js

// https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/Object/create
if (!Object.create) {
    Object.create = function (o) {
        if (arguments.length > 1) {
            throw new Error('Object.create implementation only accepts the first parameter.');
        }
        function F() {}
        F.prototype = o;
        return new F();
    };
}

CoffeeScriptのObject.createの使用箇所を以下のように変えたところ正常終了。

lib\ruby\gems\x.x.x\gems\coffee-script-source-x.x.x\lib\coffee_script\coffee-script.js
    
parse: function parse(input) {
    var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
    var args = lstack.slice.call(arguments, 1);
-   var lexer = Object.create(this.lexer);
+   var lexer;
+   if (Object.create) {
+       lexer = Object.create(this.lexer);
+   }
+   else{
+       function F() {}
+       F.prototype = this.lexer;
+       lexer = new F();
+   }
    var sharedState = { yy: {} };

結局、CoffeeScriptでObject.createを使用するようにした箇所を変更するのがベストですね。