JavaScript Babel/BrowserifyでES2015/ES2016/ES2017がIE11でも動くようにする

Babelのコマンドラインと、Browserifyを使って、ES2015/ES2016/ES2017のJavaScriptが大体全部が、IE11でも動くようにして動作確認を行いました。

requireを1箇所つかうだけなので、Browserify じゃなくて WebPack でもいいと思うので、お得意な方はそちらで使ってください。

# 対象

Windows環境ですが、たぶん Macでも使えます。

# ES2015/ES2016/ES2017 を Chrome と Firefox で動作確認する

2018/02/27現在の Win版Chrome と Firefox では、Babel変換しなくても全部動いてます。その動作確認を次のファイルによって行います。

index.htmlをブラウザで開くと、エラーもなく[test finish]とメッセージが表示されれば、動作確認完了です。

IE11では当然エラーになります。EdgeはローカルファイルやローカルWebサーバーではセキュリティの関係なのか動かないので、試してません。(たぶん動く)

```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title></title>

<script src="index.js"></script>

  </head>
  <body>
  </body>
</html>
```

次のファイルは長いですが、ES2015/2016/2017の動作を確認するためです。コピペで利用してください。

```js:index.js
"use strict";

  var isObject = function(value) {
    if (
      (Object.prototype.toString.call(value) === '[object Object]')
      && (!Array.isArray(value))
      && (value !== null)
      && (typeof value !== 'undefined')
    ) {
      return true;
    }
    return false;
  };

  var check = function(a, b, message) {
    if (a === b) {
      return true;
    }
    if ((typeof message === 'undefined')
    || (message === null)) {
      message = '';
    } else {
      message = 'Test:' + message + '\n';
    }
    message = message +
        'A != B' + '\n' +
        'A = ' + a + '\n' +
        'B = ' + b;
    alert(message);
    return false;
  };

  //オブジェクトを文字列化する関数
  //JSON.stringify を利用して
  //  {valueA: 123, valueB: "123"}
  //という形式の文字列を作成する
  var objToString = function(obj) {
    var items = JSON.stringify(obj).split(',');
    items = items.map(function(element, index, array) {
      return element.replace(/(.+:)(.*)/,
        function(string, capture1, capture2) {
          return capture1.replace(/\"/g, '') + capture2;
        }).replace(/:/g, ': ');
      //[:]の前後でcapture1/2に分割して、
      //その後に[:]の前だけ["]を削除して
      //[:]は[: ]に置換
    });
    return items.join(', ');
    //[,]は[, ]に置換
  };

  var test_objToString = function() {
    check('{valueA: 123, valueB: "123"}',
      objToString({valueA:123, valueB:"123"}));
  }
  test_objToString();

  var consoleExt = {};
  consoleExt.originalConsoleLog = console.log;
  consoleExt.result = '';
  consoleExt.delimiter = ';';
  consoleExt.logOutput = true;

  consoleExt.log = function(message) {
    if (consoleExt.logOutput) {
      consoleExt.originalConsoleLog(message);
    }
    if (isObject(message)) {
      consoleExt.result += objToString(message) + consoleExt.delimiter;
    } else {
      consoleExt.result += message + consoleExt.delimiter;
    }
  };

  consoleExt.hook = function() {
    if (consoleExt.originalConsoleLog === console.log) {
      console.log = consoleExt.log;
    }
  };
  consoleExt.unhook = function() {
    if (consoleExt.originalConsoleLog !== console.log) {
      console.log = consoleExt.originalConsoleLog;
    }
  };


  consoleExt.hook();
  consoleExt.logOutput = false;
  consoleExt.result = '';

//新しいJavaScriptの仕様の確認はここより下です

  //ES2015 let
  const test_let = () => {
    let a = 1;
    console.log(a);   //1
    {
      let a = 2;
      console.log(a); //2
    }
    console.log(a);   //1
  };
  test_let();
  check('1;2;1;', consoleExt.result);

  //ES2015 const
  consoleExt.result = '';
  const test_const = () => {
    let PI = 3;
    console.log(PI);    //3
    {
      const PI = 3.14;
      console.log(PI);  //3.14
    }
    console.log(PI);    //3
  };
  test_const();
  check('3;3.14;3;', consoleExt.result);

  //ES2015 class
  consoleExt.result = '';
  const test_class = () => {
    class ClassA {
      constructor(arg1) {
        this.prop1 = arg1;
      }
      method1() {
        return this.prop1 + ' ClassA.method1';
      }
      static method2() {
        return 'ClassA.method2';
      }
    }
    class ClassB extends ClassA {
      method1() {
        return this.prop1 + ' ClassB.method1';
      }
    }

    const classA = new ClassA('a');
    console.log(classA.method1());
    console.log(ClassA.method2());
    const classB = new ClassB('b');
    console.log(classB.method1());
    console.log(ClassB.method2());
  };
  test_class();
  check(
    'a ClassA.method1;' +
    'ClassA.method2;' +
    'b ClassB.method1;' +
    'ClassA.method2;' ,consoleExt.result);

  //ES2015 arrow function
  consoleExt.result = '';
  const test_arrowFunction = () => {
    let minus = (x, y) => { return x - y; };
    console.log(minus(3, 2));   //1
    let plus = (x, y) => x + y;
    console.log(plus(10, 20));  //30
    let plusOne = x => x + 1;
    console.log(plusOne(4));    //5
  };
  test_arrowFunction();
  check('1;30;5;', consoleExt.result);

  //ES2015 メソッド定義省略構文
    // メソッド定義 - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions_and_function_scope/Method_definitions
  consoleExt.result = '';
  const test_methodDefinition = () => {
    var obj = {
      foo0 : function (){return 0;},
      foo1(){return 1;},
      ["foo" + 2](){return 2;},
    };
    console.log(obj.foo0());  //0
    console.log(obj.foo1());  //1
    console.log(obj.foo2());  //2
  };
  test_methodDefinition();
  check('0;1;2;', consoleExt.result);

  //ES2015 分割代入
    // 分割代入 - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
  consoleExt.result = '';
  const test_destructuringAssignment = () => {
    let a, b;
    [a, b] = [1, 2]
    console.log(a);   //1
    console.log(b);   //2

    let c;
    [a, b, ...c] = [1, 2, 3, 4, 5];
    console.log(a);   //1
    console.log(b);   //2
    console.log(c.toString());  // c=[3,4,5]

    var x, y, z;
    c = [x, y, z];
    [a, b, ...c] = [1, 2, 3, 4, 5, 6];
    console.log(c.toString());  // c=[3,4,5,6]
    console.log(x);   //undefined
    console.log(y);   //undefined
    console.log(z);   //undefined
    //変数に入れたものの分割代入は不可

    let d;
    ({a=0, b, d} = {a:1, b:2})
    console.log(a);   //1
    console.log(b);   //2
    console.log(d);   //undefined

    ({a=0, b, d} = {b:2})
    console.log(a);   //0
    console.log(b);   //2
    console.log(d);   //undefined

    let e;
    ({a, b, d:e} = {a:1, b:2, c:3, d:4})
    console.log(a);   //1
    console.log(b);   //2
    console.log(e);   //4

    //入れ替え
    a = 2; b = 1;
    [a, b] = [b, a];
    console.log(a);   //1
    console.log(b);   //2

    var f = function() {
      return [1, 2, 3];
    };
    [a, , b] = f();
    console.log(a);   //1
    console.log(b);   //3

    const url = "https://developer.mozilla.org/en-US/Web/JavaScript";
    const parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
    const [, protocol, fullhost, fullpath] = parsedURL;
    console.log(protocol);
    console.log(fullhost);
    console.log(fullpath);
  };
  test_destructuringAssignment();
  check(
    '1;2;' +
    '1;2;3,4,5;' +
    '3,4,5,6;undefined;undefined;undefined;' +
    '1;2;undefined;' +
    '0;2;undefined;' +
    '1;2;4;' +
    '1;2;' +
    '1;3;' +
    'https;developer.mozilla.org;en-US/Web/JavaScript;' +
  '', consoleExt.result);

  //ES2015 スプレッド演算子 配列展開
    // スプレッド演算子 - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_operator
  consoleExt.result = '';
  const test_spreadOperator = () => {
    const arr = [1, 2, 3]
    const f = function (x, y, z) {
      return x + y + z;
    };
    console.log(f(...arr));  //6  f(1,2,3) と同様の結果
    console.log([...arr, 4, 5].toString()); //1,2,3,4,5
  };
  test_spreadOperator();
  check('6;1,2,3,4,5;', consoleExt.result);

  //ES2015 可変長引数
    // Rest parameters - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions_and_function_scope/rest_parameters
  consoleExt.result = '';
  const test_variableLengthArgument = () => {
    var f = function (a, ...b) {
      return 'A:' + a.toString() + ' B:' + b.toString();
    }
    console.log(f(1, 2, 3));
  };
  test_variableLengthArgument();
  check('A:1 B:2,3;',consoleExt.result);

  //ES2015 デフォルト引数
    // デフォルト引数 - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions_and_function_scope/Default_parameters
  consoleExt.result = '';
  const test_defaultArgument = () => {
    function multiply(a, b = 1) {
      return a * b;
    }
    console.log(multiply(2,2));   //4
    console.log(multiply(2));     //2
  };
  test_defaultArgument();
  check('4;2;', consoleExt.result);

  //ES2015 Template String
    // テンプレート文字列 - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/template_strings
  consoleExt.result = '';
  const test_templateString = () => {
    const a = 'abc';
    const b = `123
      ${a}
      678`;
    console.log(b);   //123\n      abc\n      678
  };
  test_templateString();
  check('123\n      abc\n      678;', consoleExt.result);

  //ES2015 for of
    // for...of - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for...of
  consoleExt.result = '';
  const test_forOf = () => {

    let result = 0;
    let iterable = [10, 20, 30];
    for (const value of iterable) {
      result += value;
    }
    console.log(result);  //60

    result = '';
    iterable = "boo";
    for (const value of iterable) {
      result += value + '-';
    }
    console.log(result);  //b-o-o-

    result = '';
    iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);
    for (let entry of iterable) {
      result += entry.toString();
    }
    console.log(result);  //a,1b,2c,3
    result = '';
    for (let [key, value] of iterable) {
      result += key + ':' + value + ' ';
    }
    console.log(result);  //a:1 b:2 c:3

    result = '';
    iterable = new Set([1, 1, 2, 2, 3, 3]);
    for (let value of iterable) {
      result += value;
    }
    console.log(result);  //123

  };
  test_forOf();
  check(
    '60;b-o-o-;a,1b,2c,3;a:1 b:2 c:3 ;123;'
    ,consoleExt.result);

  consoleExt.result = '';
  const test_generator = () => {
    let result = '';
    function* fibonacci() { // ジェネレーター関数
      let [prev, curr] = [1, 1];
      while (true) {
        [prev, curr] = [curr, prev + curr];
        yield curr;
      }
    }
    for (let n of fibonacci()) {
      result += n.toString() + ' ';
      // 100でシーケンスを打ち切る
      if (n >= 100) {
        break;
      }
    }
    console.log(result);
  };
  test_generator();
  check('2 3 5 8 13 21 34 55 89 144 ;',consoleExt.result);

  // ES2015 Object.assign
  //   Object.assign() - JavaScript | MDN
  //   https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
  consoleExt.result = '';
  const test_objectAssign = () => {
    var obj = { a: 1 };
    var copy = Object.assign({}, obj);
    console.log(copy.a);  //1

    var o1 = { a: 1 };
    var o2 = { b: 2 };
    var o3 = { c: 3 };
    var obj = Object.assign(o1, o2, o3);
    console.log(Object.entries(obj).toString());    //a,1,b,2,c,3
    //targetオブジェクト自身が変化する
    console.log(Object.entries(o1).toString());     //a,1,b,2,c,3
    console.log(Object.entries(o2).toString());     //b,2
    console.log(Object.entries(o3).toString());     //c,3

    //プロトタイプチェーン上のプロパティや列挙不可能なプロパティはコピーされない
    var obj = Object.create({ foo: 1 }, { // fooは継承されたプロパティ
      bar: {
        value: 2  // barは列挙不可能なプロパティ
      },
      baz: {
        value: 3,
        enumerable: true  // bazは直接所有で列挙可能なプロパティ
      }
    });
    var copy = Object.assign({}, obj);
    console.log(Object.entries(copy).toString());   //baz,3

    //プリミティブ型はオブジェクトにラップされる
    var v1 = 'abc';
    var v2 = true;
    var v3 = 10;
    // var v4 = Symbol('foo');
    var obj = Object.assign({}, v1, null, v2, undefined, v3);
    console.log(Object.entries(obj).toString());  //0,a,1,b,2,c
  };
  test_objectAssign();
  check(
    '1;' +
    'a,1,b,2,c,3;' +
    'a,1,b,2,c,3;' +
    'b,2;' +
    'c,3;' +
    'baz,3;' +
    '0,a,1,b,2,c;' +
  '', consoleExt.result);

  //ES2015 Map
    // Map - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Map
  consoleExt.result = '';
  const test_map = () => {
    var myMap = new Map();
    var keyString = "文字列",
        keyObj = {},
        keyFunc = function () {};
    // 値を設定する
    myMap.set(keyString, "'文字列' と関連付けられた値");
    myMap.set(keyObj, "keyObj と関連付けられた値");
    myMap.set(keyFunc, "keyFunc と関連付けられた値");
    console.log(myMap.size);    //3
    // 値を取得する
    console.log(myMap.get(keyString));      //'文字列' と関連付けられた値
    console.log(myMap.get(keyObj));         //keyObj と関連付けられた値
    console.log(myMap.get(keyFunc));        //keyFunc と関連付けられた値
    console.log(myMap.get("文字列"));       //'文字列' と関連付けられた値
    console.log(myMap.get({}));             //undefined
    console.log(myMap.get(function() {}));  //undefined

    var myMap = new Map();
    myMap.set(NaN, "not a number");
    console.log(myMap.get(NaN));        //not a number
    var otherNaN = Number("foo");
    console.log(myMap.get(otherNaN));   //not a number

    var result = '';
    var myMap = new Map();
    myMap.set(0, "zero");
    myMap.set(1, "one");
    for (var [key, value] of myMap) {
      result += key + " = " + value + ' ';
    }
    console.log(result);      //0 = zero 1 = one
    var result = '';
    for (var key of myMap.keys()) {
      result += key + ' ';
    }
    console.log(result);      //0 1
    var result = '';
    for (var value of myMap.values()) {
      result += value + ' ';
    }
    console.log(result);      //zero one
    var result = '';
    for (var [key, value] of myMap.entries()) {
      result += key + " = " + value + ' ';
    }
    console.log(result);      //0 = zero 1 = one

    var result = '';
    myMap.forEach(function(value, key) {
      result += key + " = " + value + ' ';
    }, myMap)
    console.log(result);      //0 = zero 1 = one

    var kvArray = [["キー1", "値1"], ["キー2", "値2"]];
    var myMap = new Map(kvArray);
    console.log(myMap.get("キー1"));              //値1

    console.log(([...myMap].toString()));         //キー1,値1,キー2,値2
    console.log(([...myMap.keys()].toString()));  //キー1,キー2

  };
  test_map();
  check(
    '3;' +
    "'文字列' と関連付けられた値;" +
    "keyObj と関連付けられた値;" +
    "keyFunc と関連付けられた値;" +
    "'文字列' と関連付けられた値;" +
    'undefined;' +
    'undefined;' +
    'not a number;' +
    'not a number;' +
    '0 = zero 1 = one ;' +
    '0 1 ;' +
    'zero one ;' +
    '0 = zero 1 = one ;' +
    '0 = zero 1 = one ;' +
    '値1;' +
    'キー1,値1,キー2,値2;' +
    'キー1,キー2;' +
  '', consoleExt.result);

  //ES2015 Iterator/Generator
    // JavaScript の ジェネレータ を極める！ - Qiita
    // https://qiita.com/kura07/items/d1a57ea64ef5c3de8528
  const test_iteratorGenerator = () => {
    consoleExt.result = '';
    var ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    for(var num of ary) { console.log(num); }
    check('1;2;3;4;5;6;7;8;9;10;', consoleExt.result);

    consoleExt.result = '';
    function* gfn1(from, to){ while(from <= to) yield from++; }
    var g = gfn1(1, 10);
    for(var num of g) { console.log(num); }
    check('1;2;3;4;5;6;7;8;9;10;', consoleExt.result);

    consoleExt.result = '';
    function* gfn2(){
        var a = yield 0;
        yield* [1, a, 5];
    }
    var g = gfn2();
    console.log( g.next() );
    console.log( g.next(3) );
    console.log( g.next() );
    console.log( g.next() );
    console.log( g.next() );
    check(
      '{value: 0, done: false};' +
      '{value: 1, done: false};' +
      '{value: 3, done: false};' +
      '{value: 5, done: false};' +
      '{done: true};'
    , consoleExt.result);

    consoleExt.result = '';
    function* gfn3(n){
        n++;
        yield n;
        n *= 2;
        yield n;
        n = 0;
        yield n;
    }
    var g = gfn3(10);
    console.log( g.next() );
    console.log( g.next() );
    console.log( g.next() );
    console.log( g.next() );
    check(
      '{value: 11, done: false};' +
      '{value: 22, done: false};' +
      '{value: 0, done: false};' +
      '{done: true};'
    , consoleExt.result);

    consoleExt.result = '';
    function* gfn4(){
        var a = yield "first";
        var b = yield "second";
        yield a + b;
    }
    var g = gfn4();
    console.log( g.next() );
    console.log( g.next(3) );
    console.log( g.next(5) );
    console.log( g.next() );
    check(
      '{value: "first", done: false};' +
      '{value: "second", done: false};' +
      '{value: 8, done: false};' +
      '{done: true};'
    , consoleExt.result);

    consoleExt.result = '';
    function* gfn5(){
      yield* [1, 3, 5];
    }
    var g = gfn5();
    console.log( g.next() );
    console.log( g.next() );
    console.log( g.next() );
    console.log( g.next() );
    check(
      '{value: 1, done: false};' +
      '{value: 3, done: false};' +
      '{value: 5, done: false};' +
      '{done: true};'
    , consoleExt.result);

    consoleExt.result = '';
    function* gfn6(){
      yield* "あいう";
    }
    var g = gfn6();
    console.log( g.next() );
    console.log( g.next() );
    console.log( g.next() );
    console.log( g.next() );
    check(
      '{value: "あ", done: false};' +
      '{value: "い", done: false};' +
      '{value: "う", done: false};' +
      '{done: true};'
    , consoleExt.result);

    consoleExt.result = '';
    function* gfn7(){
        yield 1;
        yield* [2, 1, 2];
    }
    for(var num of gfn7()) console.log(num);
    check('1;2;1;2;', consoleExt.result);
    consoleExt.result = '';
    console.log( [...gfn7()] ); // [1, 2, 1, 2]
    check('1,2,1,2;', consoleExt.result);
    consoleExt.result = '';
    console.log( Math.max(...gfn7()) ); // 2
    check('2;', consoleExt.result);
    consoleExt.result = '';
    var [a, b, c, d] = gfn7();
    console.log(a);
    console.log(b);
    console.log(c);
    console.log(d);
    check('1;2;1;2;', consoleExt.result);
    consoleExt.result = '';
  };

  //ES2016 Exponentiation Operator (べき乗演算子)
    // 算術演算子 - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators
  consoleExt.result = '';
  const test_exponentiationOperator = () => {
    console.log(2 ** 8);    //256
  };
  test_exponentiationOperator();
  check('256;', consoleExt.result);

  //ES2016 Array.includes
    // Array.prototype.includes() - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
  consoleExt.result = '';
  const test_arrayIncludes = () => {
    const arr = ['abc', 'def', 'ghi'];
    console.log(arr.includes('def'));
    console.log(arr.includes('abcd'));
  };
  test_arrayIncludes();
  check('true;false;', consoleExt.result);

  //ES2017 pasStart/padEnd
    // String.prototype.padStart() - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
  consoleExt.result = '';
  const test_padStartEnd = () => {
    console.log('abc'.padStart(5, '*') );
    console.log('abc'.padStart(10, 'def') );
    console.log('abc'.padEnd(5, '*') );
    console.log('abc'.padEnd(10, 'def') );
  };
  test_padStartEnd();
  check(
    '**abc;' +
    'defdefdabc;' +
    'abc**;' +
    'abcdefdefd;' +
  '', consoleExt.result);

  //ES2017 Object.values/entries
    // Object.values() - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/values
  consoleExt.result = '';
  const test_objectValuesEntries = () => {
    console.log(Object.keys({a:1, b:2}).toString() );     //a,b
    console.log(Object.values({a:1, b:2}).toString() );   //1,2
    console.log(Object.entries({a:1, b:2}).toString() );  //a,1,b,2
  };
  test_objectValuesEntries();
  check(
    'a,b;' +
    '1,2;' +
    'a,1,b,2;' +
  '', consoleExt.result);

  //ES2017 Object.
    // Object.getOwnPropertyDescriptors() - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors
  consoleExt.result = '';
  const test_objectGetOwnPropertyDescriptors = () => {
    const obj = { prop: 123 };
    console.log(
      Object.entries(
        Object.getOwnPropertyDescriptor(obj, "prop")
      ).toString());
    //value,123,writable,true,enumerable,true,configurable,true

    console.log(
      Object.entries(
        Object.getOwnPropertyDescriptors(obj).prop
      ).toString());
    //value,123,writable,true,enumerable,true,configurable,true
  };
  test_objectGetOwnPropertyDescriptors();
  check(
    'value,123,writable,true,enumerable,true,configurable,true;' +
    'value,123,writable,true,enumerable,true,configurable,true;' +
  '', consoleExt.result);

  //ES2017 Trailing commas in function parameter lists and calls
  consoleExt.result = '';
  const test_functionParamTrailingCommas = () => {
    const add = (
      x,
      y,
    ) => {
     return x + y;
    };
    console.log(add(10,20));  //30
  };
  test_functionParamTrailingCommas();
  check('30;', consoleExt.result);

  //ES2017 Async Functions
    // async function - JavaScript | MDN
    // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function
  consoleExt.result = '';
  const test_asyncFunction = async () => {
    (async () => {
      console.log('async start');
      await new Promise((resolve) => setTimeout(resolve, 1000));
      // 1秒後に実行される
      console.log('async end');

      check('async start;async end;', consoleExt.result);

    })().catch((error) => console.log(error));
  };
  test_asyncFunction();

  alert('test finish');

```

この2ファイルをフォルダごとバックアップとっておくと、変換後との差分がわかっていいかもしれません。


# BabelとBrowserify環境構築

もちろん、node.js はインストールしておいてください。

## インストール

Browserifyのグローバルインストール、Babelのローカルインストールをします。特定フォルダをカレントにして、次のコマンドを入れます。

```
> npm install -g browserify
> npm install --save-dev babel-cli
> npm install --save-dev babel-polyfill
> npm install --save-dev babel-preset-env
```

特定フォルダに作成される、package.json は次のとおり。(devDependenciesの欄だけみてください。他は気にしないで)

```json:package.json
{
  "name": "babel",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.6.1"
  },
  "dependencies": {}
```

## 設定ファイル
次は、Babelのための設定ファイルを用意します。

```json:.babelrc
{
  "presets": [
    ["./node_modules/babel-preset-env", {
      "targets": {
        "IE": "11"
      }
    }]
  ]
}
```
書き方がいろいろあるようで、正確なものがよくわからないのですが、とりあえずこのように書いて、カレントフォルダに配置してください。

## HTMLファイル

次は、index.html を少し変更します。

```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title></title>

<script src="output-build.js"></script>
<script>
var output = require('/output.js');
</script>

  </head>
  <body>
  </body>
</html>
```

output-build.js をリンクするようにして、requireで機能を呼び出すようにしています。

## js ファイル
次は、index.js を少し変更します。

といっても、use strict行のあとに require を書くだけです。
(別にuse strict行の前でもいい気がしますが、なんとなく。)

```index.js
"use strict";
require("babel-polyfill");  //追加行
```

これで準備が整いました。

# トランスパイル

次のコマンドでBabelのトランスパイルをして、index.js を output.js に変換します。

```
> .\node_modules\.bin\babel index.js -o output.js
```

この状態で、ES201x が IE11で解釈されるものに変換されます。が、一部は babel-polyfill がないと動かないので、requireでモジュール結合して取り込むために Browserify を使います。

```
> browserify -r ./output.js -o ./output-build.js
```

これで、output.js にbabel-polyfill を取り込み、 output-build.js に変換しています。

これで、index.html と output-build.js の2つのファイルで、IE11でも ES2015/2016/2017 のJavaScriptが動くようになります。

# あとがき

「新しい構文で書きたいけど、古い環境で動かないかどうかわからないから書けない。」と心配する気持ちがあると開発ははかどらないですよね。

新しい構文をしっかり動作確認してから開発にとりくみましょう。


# 参考

HTMLファイルだけでCDNでBabelをリンクしてES2015/2016/2017を動かす - Qiita
https://qiita.com/standard-software/items/f6c18fa6017fbb218cce

Babel コマンドライン変換環境構築 - Qiita
https://qiita.com/standard-software/items/4b712ede34c728dc3b08

JavaScript webpack+babel windows環境設定 - Qiita
https://qiita.com/standard-software/items/60915e40891f70d02ffd