QA@IT

coffeeをassets:precompileをすると、出力されたjsファイルでクラス名が変更されている。

2817 PV

Rails3.2で開発しています。

現在、suggest.jsというjsのライブラリを色々カスタマイズしています。しかし、このjsファイルをcoffeeに変換して、assets:precompileすると、吐き出されるapplication.js内でSuggestというクラス名がtに書きかわっています。

具体的にこの手順を説明します。

  • suggest.jsを落とします。
  • jsをcoffeeに書き換えるために変換サイトにアクセスし、変換します。
  • require_treeの対象であるフォルダに、suggest.js.coffeeという名前で保存します。
  • rake assets:precompile
  • rails s
  • http://localhost:3000/にアクセスし、Crome Developer Toolsでappication.js内をのぞくと、Suggetがtに書きかわっている。具体例は後述

なぜ、このような現象が起こるのでしょうか?またどうやったら、この問題を解決できますか?
ご回答いただけると幸いです。

問題の部分の一部抜き取り

元のcoffee

Suggest = {}  unless Suggest

#-- KeyCodes -----------------------------------------
Suggest.Key =
  TAB: 9
  RETURN: 13
  ESC: 27
  UP: 38
  DOWN: 40


#-- Utils --------------------------------------------
Suggest.copyProperties = (dest, src) ->
  for property of src
    dest[property] = src[property]

変換サイトで、coffeeをjsに行った場合のソース

var Suggest;

if (!Suggest) {
  Suggest = {};
}

Suggest.Key = {
  TAB: 9,
  RETURN: 13,
  ESC: 27,
  UP: 38,
  DOWN: 40
};

Suggest.copyProperties = function(dest, src) {

tに変換されてしまったapplication.js内

}(jQuery), function() {
}.call(this), function() {
    var t;
    t || (t = {}), t.Key = {TAB: 9,RETURN: 13,ESC: 27,UP: 38,DOWN: 40}, t.copyProperties = function(t, e) {
        var i;
        for (i in e)
            t[i] = e[i];
        return t
    }, t.Local = function() {
        return this.initialize.apply(this, arguments_)

回答

検証していないので細かいところは不正確なのですが、下記のような現象が起きているんだと思います。

  1. CoffeeScript から JavaScript への変換時には (function(){...})() でコード全体が囲まれる (暗黙的にグローバル変数を定義しないようにするため)
  2. function 内で使われる変数名 (ここでは Suggest) が最小化 (minify) の処理により別の名前 (ここでは t) に置き換えられる

もし 2 の最小化がなくても、1 により Suggest という変数のスコープはこのファイル内のみになります。Suggest という変数が同じファイルからしか参照されないならば、これでも問題ありません (t になっても動作は変わりないはずです)。

Suggest という変数を同じファイル以外からも参照する場合は、これをグローバル変数にする必要があります。トップレベルの this はグローバルオブジェクト (ブラウザの場合 window) なので this.Suggest = ... のように書くことでグローバル変数が定義できます。この場合は最小化で名前が変わることはないはずです。より CoffeeScript っぽくするなら @Suggest = ... とも書けますね。

編集 履歴 (1)

>>ある程度のデメリットがあるとしても、ほかの人はなぜこの技術を使うのか?
>>そもそも何か前提が違うのか?

CoffeeScriptの良さ(だったところ)は
クラス!
シンプル!
カッコイイ!
良くも悪くもこの3つでしょう

JSの代わりの新言語というより、
JSを良く書けるラッパーといった感じのものです
JSにこなれた人が、痒いところに手が届くのを気に入って使うようなものだと思います

ですのでギークには「未来のJSが書ける」とそこそこ受けたと思います
実際、CSはJSの次世代規格に強い影響を与えました

しかしデバッグはしにくいですし
面白いけど有用性は微妙だよねという印象だったと思います

さらにCSの便利だった構文が次々と標準になり、
最近「しっかりした」TypeScriptも登場して、
そろそろCSはお役御免かなという印象すらあります

今ネットで調べてみてもむしろ評判は「悪い」と感じます
この先流行ることもないでしょう
廃れてしまうのなら、保守性の面でも良くないです

もちろん個人的に使う分にはいいと思いますが
あくまでJSをやってる人がJSをよく(短く)書けるものであって、
JSの代わりの言語として学ぶと良くないと思いますよ

編集 履歴 (2)
  • お返事ありがとうございます。
    CoffeeScriptはあくまでも、jsを補完するような使い方(置き換えるではなく)が正しかったんですね。勉強になりました。
    -

お返事ありがとうございます。

<< 下記のような現象が起きているんだと思います。
なるほど、だからfunctionで囲まれるんですね。勉強になりました。

ただ、なんてんか疑問、懸念点があります。

  • Suggestは変数ではなくクラス名ではないでしょうか?

私はJSを体系的に勉強していないのでちょと不安ですが、Suggest.prototypeと書いてメソッドを定義している場所もあるので多分クラスだと考えていたのですが、違うのでしょうか?

  • このような事は頻発するのでしょうか?

私はCoffeeScript勉強し始めたばかりなのですが、なぜ勉強しようとおったかというと、RubyになれているのでJSよりも直感的に書けるのではないかと思ったからです。
しかしながら、今回の様なJS→Coffee→JSと直した場合、色々な副作用(クラス名が書きかわる。ほかにもメンバ変数の名前が一部だけ変更されてエラーというのもありました)があるのでは、正直メリットよりもデメリットの方が上回るように感じます。

ただ、私がCoffeeScriptを勉強をする前の評判では、もう少ししっかりとした技術という印象をもっていました(Rails正式採用、ギークが使っている等の理由により)。

そのため。このギャップが私には不思議です。
この現象(変数名の変更、クラス名の変更等によるエラー)は頻繁に起こる物なのか?
また、おこった場合はほかの人は手で対処しているのでしょうか?
ある程度のデメリットがあるとしても、ほかの人はなぜこの技術を使うのか?
そもそも何か前提が違うのか?
等、色々疑問がこの技術に対して浮かびます。よろしければご意見をお聞かせください(抽象的な質問+意見形式なので、申し訳なく思いますが)。

編集 履歴 (2)
  • JavaScript にクラスという概念はありません。クラスっぽく動作するオブジェクトが作れて、クラスっぽく使える文法 (new) があるだけです。
    また、変数名の変更は最小化の処理によって行われたもので CoffeeScript に起因するものではありません。それをもって CS のデメリットとするのは的外れです。
    -
  • どの言語を使うかは好みで決めれば良いと思いますが、私には CS のデメリットといっても 「JS よりメンテできる人が少ない」「asm.js に対応できないかもしれない」くらいしかすぐには思いつきません。JS より簡潔に書けるので、よく使うし今後も使うと思います。ただ JS を理解せず使うのはちょっと厳しいだろうなとは思います。 -
  • お返事ありがとうございます。クラスという概念がなかったんですね。勉強になりました。
    <<CoffeeScript に起因するものではありません
    確かに、これは圧縮するライブラリ(uglifier?)に起因する問題ですね。申し訳ないです。
    -
ウォッチ

この質問への回答やコメントをメールでお知らせします。