Babel で IE8 対応する地獄

  • 95
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

IE8 対応が必要な JavaScript に Babel (+ webpack) を使っているんだけど、素直に書くと動かないところがあったのでメモ。

とある事情により Polyfill も叶わない環境を想定している。

大体これと同じ内容:

class を使うためには・・・

class を使ったコードを Babel に変換させると Object.defineProperties を使って class 相当を実現させようとする。しかし、IE8 以下の古い IE には Object.defineProperties が無いため、エラーになる。

IE8 でも class が使いたいときは、loose mode の es6.classes を使う:

class-test.js
class Foo {
  foo() { }
}
console.log(new Foo());
端末
# ダメ
$ babel class-test.js -o t.js
$ grep 'Object.defineProp' t.js | wc -l
1

# こうする
$ babel class-test.js -o t.js --loose es6.classes
$ grep 'Object.defineProp' t.js | wc -l
0

loose mode はその名前の通り、コードが少なくなる代わりに ES6 の class の仕様とは少し違ってしまうので注意:

Method enumerability
Method assignment
Loose mode · Babel

Named exports を使うためには・・・

Named exports をする時、class と同様の問題が起きる。Named export とは:

lib.js
export function foo() {
  console.log('foofoo');
}
main.js
import * as lib from 'lib';
lib.foo(); // => foofoo

というように foo という名前を付けて export する書き方。(きちんとした名前知らない。要調査。)

この lib.js を babel にかけると:

端末
$ babel lib.js
"use strict";

exports.foo = foo;
Object.defineProperty(exports, "__esModule", {
  value: true
});

function foo() {
  console.log("foofoo");
}

このように IE8 では使えない Object.defineProperty を使ってしまう。

これは loose mode の es6.modules を有効にすると良い:

端末
# ダメ
$ babel lib.js -o t.js
$ grep 'Object.defineProp' t.js | wc -l
1

# こうする
$ babel lib.js -o t.js --loose es6.modules
$ grep 'Object.defineProp' t.js | wc -l
0

こちらも副作用があるので注意が必要:

es6.modules
es6.modules

Loose mode · Babel

2つに分かれているので注意。

他にも

今回は困らなかったので紹介しないが、class での static method の継承が上手く行かない話や、getter/setter にも Object.defineProperty が使われる話が、Caveats · Babel に書かれている。

おわり。そもそも IE8 対応がつらい。

参考にしたもの