• 作成:

babelで分割代入を変換するのはobject-rest-spreadではなくtransform-destructuring

babel

難読化ツールjavascript-obfuscatorが分割代入での破壊的代入に対応していない

function main() {
  const o = {v: 1}
  let v;
  ({v} = o);
  console.log(v);
}

main();

は生のJavaScriptだと1を出力しますが, javascript-obfuscatorを通すとundefinedを出力します.

javascript-obfuscator break Assignment without declaration. · Issue #328 · javascript-obfuscator/javascript-obfuscator

それはプロパティの名前を正しく認識していないためで, 以下のようにコンパイルされるからです.

function main() {
  const _0x501e82 = { v: 0x1 };
  let _0x5b6c40;
  ({ v } = _0x501e82);
  console["log"](_0x5b6c40);
}
main();

babelで分割代入をES5レベルまでfallbackさせれば良いのでは

考えた解決策は以下です.

  1. javascript-obfuscatorのバグが治るのを待つ
  2. 私がjavascript-obfuscatorを治してpull requestを送りつける
  3. 難読化ツールに別のものを使う
  4. 頑張って破壊的分割代入を探し尽くして一つ一つeslint-disable-next-lineしてプロパティベースに書き換える
  5. babelのtargetsを分割代入をサポートしていないブラウザでも動くレベルに下げて分割代入のシンタックスをコンパイル前に消去する(おそらくパフォーマンスが劣化する)
  6. 難読化やめる

上記issueでバグを報告した所10月まで休暇だという返事が帰ってきたので, とりあえず難読化ツールは分割代入未対応だと諦めることにしました.

target下げてみる

babelのtarget下げるのが一番現実的だと判断して下げてみました.

Chromeがオブジェクトの分割代入をサポートしたのは60からだそうなので59まで下げれば良いですね.

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "Chrome": "59"
        }
      }
    ],
    "@babel/react"
  ]
}

そうしたら以下のエラーがコンソールに表示されました.

Uncaught ReferenceError: regeneratorRuntime is not defined

つまり、Babelのランタイムが読み込まれていないから「regeneratorRuntime is not defined」が発生しているわけです。

Node.js & webpack & babel で「 regeneratorRuntime is not defined」が発生する場合の対処 - Qiita

なるほど, 私の想定環境はElectronの最新版なので, ジェネレータだけネイティブのものを使用させれば問題ないですね.

問題はそれをどうやって実現するかで, 変換する部分を自在に設定する方法を知ってたらそもそも分割代入だけ変換するように設定しているんですよね.

pluginに@babel/plugin-proposal-object-rest-spreadを追加して, targetsのElectronにしても変換されませんしね…

オプションを有効にして変換されないか期待してみる

@babel/plugin-proposal-object-rest-spread · Babel

を見てオプションを有効にしてみます. 正直英語がわからない.

["@babel/plugin-proposal-object-rest-spread", { "loose": true, "useBuiltIns": true }]

を設定しても変換されませんね.

まあ説明文的にそうなるだろうとは思いました.

そもそもこのオプション正しいのか?

そもそも本当にbabelはtarget下げればコードを変換してくれるのかわからなくなってきました. スプレッドに付いては書いてますが破壊的代入については書いていないので.

function main() {
  const o = {v: 1}
  let v;
  ({v} = o);
  console.log(v);
}

main();
% babel --target ES5 --plugins @babel/plugin-proposal-object-rest-spread object-assign.js
function main() {
  const o = {
    v: 1
  };
  let v;
  ({
    v
  } = o);
  console.log(v);
}

main();

変換してくれないじゃないか… 目をつけていたプラグインが違ったようですね.

babel-plugin-transform-es2015-destructuring · Babel を使ったら変換してくれるようですね.

でもこれ新babelのパッケージじゃないんですよね.

解決

新しいのは以下.

@babel/plugin-transform-destructuring · Babel

これを入れて解決しました.