JavaScript
CoffeeScript

CoffeeScriptからJavaScriptに移行する

今年歴史あるRailsプロジェクトのCoffeeScriptをJavaScriptにひたすら直す作業をしてたので、CoffeeScriptを使っていたがJavaScriptに移したくなった際の流れをまとました。

大まかな流れ

  1. CoffeeScriptに前処理をして変換後のJavaScriptが極力キレイになるようにする
  2. decaffeinate コマンドで変換処理を行う
  3. 生成されたJavaScriptファイルに問題ないか確認(目視/実際に動かして)。一部修正を行う
  4. 古いCoffeeScriptのファイルを削除する

大まかな流れはこんな感じです。変換処理自体は手作業ではなくコマンドに任せます。が前処理をしておくと読みやすいJavaScriptになるので面倒でも手作業で下準備をします。

準備

decaffeinate をインストールします。npm install --save-dev decaffeinate なり yarn add --dev decaffeinateご自由に。
使い方ですがdecaffeinate <ファイル名/ディレクトリ名>でCoffeeScriptからJavaScriptへの変換できます。

前処理を行う

多分これで全部ではないですが、ここを気にするだけでだいぶ違います。

暗黙のreturnを明示的にする

CoffeeScriptはRubyと同様に関数最後の式を関数の返り値とする特徴があります。そのためreturnを付け加えないと望ましくない返り値を返している場合があります。

y = (x) ->
  x * x

はJavaScriptに直すと

y = function(x) {
  return x * x;
}

になりますし、多分こうなって欲しいかと思います。
ところが

y = (x) ->
  console.log(x)

もJavaScriptに直すと

y = function(x) {
  return console.log(x);
}

となってしまい、読み手を混乱させるかもしれません。
この必要なreturnか不要なreturnかを変換後に区別して直すのは非常に面倒なので変換前に処理します。
具体的にはreturnが必要な箇所にはreturn xのようにして何も返さない時には関数末にreturnを加えます。returnが必要なケースでは別にreturn付け加えなくても良いですが、一応確認をしたという意味でつけておくと無難です。
関数末のreturnは不要であれば変換時に消えるのであとで削除する必要はありません。

クラス内部の変数をインスタンス変数に直す

CoffeeScriptでは以下のような書き方が可能です。

class X
  x = 10 # メソッド外でも変数が定義できる
  getX: () =>
    return x

ところがこれをJavaScriptに変換すると結構読みにくいものになります。(どんなだったか忘れました)
そのため若干解釈が変わってしまいますが、インスタンス変数に直します。privateだよという意味を込めて_から変数名を始めるようにしてもいいでしょう

class X
  constructor: () =>
    @_x = 10 # インスタンス変数に直す

  getX: () =>
    return @_x

変換処理を行う

decaffeinateコマンドを実行します。ここは特に何もないので省略します。
ちなみに、let constの判断とかある程度アロー関数化とか変数展開とか分割代入とか結構よしなにやってくれます。

変換後の確認と修正

基本的に問題ないはずですが、一応動作確認しておきます。あとループ変数がvarで1まとめになっていた気がするので最後直しておきます。スルーしてもいいですが、結構気になります。個人的にな感想ですがループの変換は結構微妙だったイメージです。

// Before
var x;

for(x = 0; x < 10; ++x) {
  // 何か
}

for(x = 0; x < 10; ++x) {
  // 何か
}
// After
for(let x = 0; x < 10; ++x) {
  // 何か
}

for(let x = 0; x < 10; ++x) {
  // 何か
}

まとめ

CoffeeScriptからJavaScriptへの変換時には、多少手間暇かけることで見やすいJavaScriptにすることができました。