Edited at

Babel で IE8 対応する地獄

More than 3 years have passed since last update.

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 対応がつらい。


参考にしたもの