JavaScript
babel

babel 7 触ってみたメモ

babel初学者がBabel 7を使ってみたメモ。
初babelなので認識違いなどあればご指摘ください。 (Qiitaも初めてなので文化的暗黙のルールとかもわかってないです
docs: https://babeljs.io/docs/

node: "10.4.0"
@babel/cli: "7.1.5"
@babel/core: "7.1.6"
@babel/preset-env: "7.1.6"
@babel/polyfill: "7.0.0"

install

$ yarn add --dev @babel/core @babel/cli @babel/preset-env

babel7からはパッケージ名が@babel/xxxに変更になっている。

config

$ touch babel.config.js

babel.config.js

const presets =  [
  ["@babel/preset-env"]
};
module.exports = { presets }

パッケージ名が変更になってるので、"env"とか"preset-env"とかを指定しているとエラーになる

targets

browserslisttargetプロパティに直接渡す。

babel.config.js

const presets =  [
  ["@babel/preset-env", {
    "targets": [">0.25% in JP", "not ie <= 10", "not op_mini all"],
  }]
};
targets.browsersでの指定は廃止予定
const presets =  [
  ["@babel/preset-env", {
    "targets": {
      "browsers": [">0.25% in JP", "not ie <= 10", "not op_mini all"],
    },
  }]
};

babel 7 で動作するけど、browsersでの指定は将来的に廃止予定っぽい

fc. https://babeljs.io/docs/en/babel-preset-env#targetsbrowsers

Note: this will be removed in later version in favor of just setting "targets" to a query directly.

動作チェク

package.jsonにバベるコマンドを作成

"scripts": {
  "babel": "./node_modules/.bin/babel src --out-dir dist/js",
}

src/index.js

import { foo, bar } from './test.js'
console.log( foo() );

const countup = (x) => x + 1;
console.log( countup(1) )

Promise.resolve().then(res => console.log("Promise end") );

バベる

$ yarn run babel

👇 dist/js/index.js

var _test = require("./test.js");

console.log((0, _test.foo)());

var countup = function countup(x) {
  return x + 1;
};

console.log(countup(1));
Promise.resolve().then(function (res) {
  return console.log("Promise end");
});

@babel/polyfill

https://babeljs.io/docs/en/babel-polyfill

PromiseWeakMap, Array.from, Object.assign, Array.prototype.includesなど文法ではなく、機能を対応していないブラウザ用に変換する

=> つまり、コードを直接変換する機能

install

$ yarn add @babel/polyfill

Usage

babel.config.jsuseBuiltIns: "usage"を指定すれば、必要に合わせてプラグインを選び変換してくれるっぽい

Now luckily for us, we're using the env preset which has a "useBuiltIns" option that when set to "usage" will practically apply the last optimization mentioned above where you only include the polyfills you need.

babel.config.js

const presets =  [
  ["@babel/preset-env", {
    "targets": [">0.25% in JP", "not ie <= 10", "not op_mini all"],
    "useBuiltIns": "usage",
  }]
};

動作チェク

Promise.resolve().then(res => console.log("Promise end") );

👇 バベる

require("core-js/modules/es6.promise");

Promise.resolve().then(function (res) {
  return console.log("Promise end");
});

core-js/modules/es6.promiseが追加されている。

async/await

const asyncSampleFunc = () => {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 100, "resolve");
  });
}

async function getAsyncVal() {
  const val = await asyncSampleFunc();
  return `Complete Async: ${val}`
}

getAsyncVal().then((res) => {
  console.log(res);
}).catch((err) => {
  console.log(err);
});

👇 バベる

require("regenerator-runtime/runtime");

require("core-js/modules/es6.promise");

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

var asyncSampleFunc = function asyncSampleFunc() {
  return new Promise(function (resolve, reject) {
    setTimeout(resolve, 100, "resolve");
  });
};

function getAsyncVal() {
  return _getAsyncVal.apply(this, arguments);
}

function _getAsyncVal() {
  _getAsyncVal = _asyncToGenerator(
  /*#__PURE__*/
  regeneratorRuntime.mark(function _callee() {
    var val;
    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.next = 2;
            return asyncSampleFunc();

          case 2:
            val = _context.sent;
            return _context.abrupt("return", "Complete Async: ".concat(val));

          case 4:
          case "end":
            return _context.stop();
        }
      }
    }, _callee, this);
  }));
  return _getAsyncVal.apply(this, arguments);
}

getAsyncVal().then(function (res) {
  console.log(res);
}).catch(function (err) {
  console.log(err);
});

変換できたっぽい。 (以前async/await使ってるプロダクト作ってる人にasync/awaitはバベれないって言われたのでダメなのかと思ってた...

import -> require 問題

デフォルトだと、importrequire(CommonJS?)に変換されてしまう。

modules: falseを指定するとimportのままになる

babel.config.js

const presets =  [
  ["@babel/preset-env", {
    "modules": false,
    "targets": [">0.25% in JP", "not ie <= 10", "not op_mini all"],
    "useBuiltIns": "usage",
  }]
};

動作チェク

src/index.js

import { foo, bar } from './test.js'
console.log( foo() );

const countup = (x) => x + 1;
console.log( countup(1) )

Promise.resolve().then(res => console.log("Promise end") );

👇 バベる

dist/js/index.js

import "core-js/modules/es6.promise";
import { foo, bar } from './test.js';
console.log(foo());

var countup = function countup(x) {
  return x + 1;
};

console.log(countup(1));
Promise.resolve().then(function (res) {
  return console.log("Promise end");
});

import文のまましゅつりょくされた。

cf. https://babeljs.io/docs/en/babel-preset-env#modules

modules
"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false, defaults to "auto".
Enable transformation of ES6 module syntax to another module type.
Setting this to false will not transform modules.
Also note that cjs is just an alias for commonjs.


[WIP]

英語ちからが足りていない...