@babel/polyfill と core-js
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ @babel/polyfill は deprecated になってた
◆ 代替は core-js と regenerator-runtime のインポート
◆ core-js だとモジュールごとにロードできるので IE が消えれば 最低限の polyfill のみにできて効率よさそう
◆ 代替は core-js と regenerator-runtime のインポート
◆ core-js だとモジュールごとにロードできるので IE が消えれば 最低限の polyfill のみにできて効率よさそう
@babel/polyfill が deprecated になってた
ES2015+ のバンドル時に IE 用に @babel/polyfill を使ってたのですが 7.4 から deprecated になってたようですhttps://babeljs.io/docs/en/babel-polyfill
大きく赤色で警告っぽい見た目じゃなかったので ドキュメントは一応見てたはずなのにスルーしてしまっていました
変わった理由は core-js の方に書いてます
https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md#babelpolyfill
2 から 3 への移行の問題みたいです
これまでの @babel/polyfill は core-js の stable な機能のみと 非同期関数などを従来機能に置き換えたときに使用する regenerator-runtime/runtime をまとめたものでした
なのでそれを直接ロードする形にして
import "@babel/polyfill"
を
import "core-js/stable"
import "regenerator-runtime/runtime"
に置き換えると良いようです
core-js は 3 からは非標準機能はなくして完全な polyfill になったみたいですし 直接使うほうが便利なのかもしれませんね
置き換えてみる
置き換えてみて比べてみますbrowserslist で IE 11 をターゲットにして webpack でバンドルします
@babel/polyfill
import "@babel/polyfill"
window.onload = eve => document.body.innerHTML = "ok"
minify なしだと出力は 11597 行でした
core-js
import "core-js/stable"
import "regenerator-runtime/runtime"
window.onload = eve => document.body.innerHTML = "ok"
に変更してみると
16598 行
増えてます……
一応 Chrome のみにしてみたら 16462 行でちょっとだけ減ってますが @babel/polyfill よりは多いです
これだけみるとあまり良くなったようには思えません
useBuiltIns: entry
@babel/preset-env では corejs に 3 を指定して useBuiltIns に entry を指定すると import 文を直接モジュールのロードに置き換えることができるようですモジュールごとになるのでいらないのは除去してくれて規模が小さくなるはずです
presets: [
["@babel/preset-env", {
useBuiltIns: "entry",
corejs: 3,
}],
],
と設定を変更して
import "core-js/stable"
import "regenerator-runtime/runtime"
window.onload = eve => document.body.innerHTML = "ok"
を試してみました
すると
15644 行
減ってはいますが @babel/polyfill よりは多いです
ちなみに Chrome だと たった 1374 行でした
ターゲットに設定するブラウザの機能があるほど polyfill サイズも小さくなるので基本的にはこれを使うと良さそうです
ただ なぜか
catch ステートメントでは適用されますが、throw ステートメントでは適用されません。
という IE でのみエラーが出る場合がありました
最初試した環境だと何も問題なくて ブログ用にもう一回別の環境でやると発生しました
別のビルドですが 出力行数は同じなので同じ結果になってると思うのですけど
useBuiltIns: usage
useBuiltIns には usage も指定できて こっちの場合は自分で core-js を import する必要がありませんというかしたらダメです
各ソースファイル中のコードから使用された機能を判断して必要な polyfill のみロードしてくれます
eval とか動的な部分は限界がありそうですが すごそうです
presets: [
["@babel/preset-env", {
useBuiltIns: "usage",
corejs: 3,
}],
],
import "core-js/stable"
import "regenerator-runtime/runtime"
window.onload = eve => document.body.innerHTML = "ok"
で試してみると 13146 行
Chrome 用は 821 行
更に小さくなりました
気をつけるところは core-js 自体はインポートしないことです
自動で import 文を追加してくれるので core-js 自体のインポートを書いていると二重にインポートすることになります
core-js を手動ロードした場合の行数は 23912 になってました
ただ こっちにも問題はあって
$({
target: 'Array',
proto: true,
forced: ES3_STRINGS || SLOPPY_METHOD
}, {
join: function join(separator) {
return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
}
});
の部分で
関数を指定してください。
というエラーが起きていました
こっちは Chrome も
$ is not a function
というエラーです
var $ = __webpack_require__(/*! ../internals/export */ "./node_modules/core-js/internals/export.js");
で代入している $ が関数ではなくオブジェクトになってます
まぁ usage はまだ experimental の実験的な機能みたいなので今後に期待です
babel のみ
ここまでやって webpack 通すから複雑になるので単純に babel のみ通したほうがわかりやすい気がしましたなのでやってみます
いつもは webpack なので webpack.config.js に設定を書いていましたが @babel/cli の babel コマンドの場合は babel.config.js になります
babel.config.js
module.exports = {
presets: [["@babel/preset-env", {
targets: {
ie: 11
},
}]]
}
実行は babel コマンドにエントリポイントファイルを指定すれば標準出力に結果が出ます
babel index.js
@babel/polyfill
まずは @babel/polyfillimport "@babel/polyfill"
window.onload = eve => document.body.innerHTML = "ok"
`@babel/polyfill` is deprecated. Please, use required parts of `core-js`
and `regenerator-runtime/runtime` separately
"use strict";
require("@babel/polyfill");
window.onload = function (eve) {
return document.body.innerHTML = "ok";
};
deprecated で core-js を使うようにちゃんと注意書きがでました
webpack だと隠蔽されてて気づけないです
変換自体は単純な require 化とアロー関数の通常関数化のみです
core-js
つぎは core-js 版import "core-js/stable"
import "regenerator-runtime/runtime"
window.onload = eve => document.body.innerHTML = "ok"
"use strict";
require("core-js/stable");
require("regenerator-runtime/runtime");
window.onload = function (eve) {
return document.body.innerHTML = "ok";
};
こっちも require 化だけで展開はされていません
useBuiltIns: entry
今度は useBuiltIns を entry に設定しますmodule.exports = {
presets: [["@babel/preset-env", {
targets: {
ie: 11
},
corejs: 3,
useBuiltIns: "entry",
}]]
}
import "@babel/polyfill"
window.onload = eve => document.body.innerHTML = "ok"
`@babel/polyfill` is deprecated. Please, use required parts of `core-js`
and `regenerator-runtime/runtime` separately
"use strict";
require("@babel/polyfill");
window.onload = function (eve) {
return document.body.innerHTML = "ok";
};
@babel/polyfill だと変わらずです
core-js にしてみると
import "core-js/stable"
import "regenerator-runtime/runtime"
window.onload = eve => document.body.innerHTML = "ok"
"use strict";
require("core-js/modules/es.symbol");
require("core-js/modules/es.symbol.description");
require("core-js/modules/es.symbol.async-iterator");
require("core-js/modules/es.symbol.has-instance");
require("core-js/modules/es.symbol.is-concat-spreadable");
require("core-js/modules/es.symbol.iterator");
require("core-js/modules/es.symbol.match");
require("core-js/modules/es.symbol.replace");
require("core-js/modules/es.symbol.search");
require("core-js/modules/es.symbol.species");
require("core-js/modules/es.symbol.split");
require("core-js/modules/es.symbol.to-primitive");
require("core-js/modules/es.symbol.to-string-tag");
require("core-js/modules/es.symbol.unscopables");
require("core-js/modules/es.array.concat");
require("core-js/modules/es.array.copy-within");
require("core-js/modules/es.array.fill");
require("core-js/modules/es.array.filter");
require("core-js/modules/es.array.find");
require("core-js/modules/es.array.find-index");
require("core-js/modules/es.array.flat");
require("core-js/modules/es.array.flat-map");
require("core-js/modules/es.array.from");
require("core-js/modules/es.array.includes");
require("core-js/modules/es.array.iterator");
require("core-js/modules/es.array.join");
require("core-js/modules/es.array.map");
require("core-js/modules/es.array.of");
require("core-js/modules/es.array.slice");
require("core-js/modules/es.array.species");
require("core-js/modules/es.array.splice");
require("core-js/modules/es.array.unscopables.flat");
require("core-js/modules/es.array.unscopables.flat-map");
require("core-js/modules/es.array-buffer.constructor");
require("core-js/modules/es.date.to-primitive");
require("core-js/modules/es.function.has-instance");
require("core-js/modules/es.function.name");
require("core-js/modules/es.json.to-string-tag");
require("core-js/modules/es.map");
require("core-js/modules/es.math.acosh");
require("core-js/modules/es.math.asinh");
require("core-js/modules/es.math.atanh");
require("core-js/modules/es.math.cbrt");
require("core-js/modules/es.math.clz32");
require("core-js/modules/es.math.cosh");
require("core-js/modules/es.math.expm1");
require("core-js/modules/es.math.fround");
require("core-js/modules/es.math.hypot");
require("core-js/modules/es.math.imul");
require("core-js/modules/es.math.log10");
require("core-js/modules/es.math.log1p");
require("core-js/modules/es.math.log2");
require("core-js/modules/es.math.sign");
require("core-js/modules/es.math.sinh");
require("core-js/modules/es.math.tanh");
require("core-js/modules/es.math.to-string-tag");
require("core-js/modules/es.math.trunc");
require("core-js/modules/es.number.constructor");
require("core-js/modules/es.number.epsilon");
require("core-js/modules/es.number.is-finite");
require("core-js/modules/es.number.is-integer");
require("core-js/modules/es.number.is-nan");
require("core-js/modules/es.number.is-safe-integer");
require("core-js/modules/es.number.max-safe-integer");
require("core-js/modules/es.number.min-safe-integer");
require("core-js/modules/es.number.parse-float");
require("core-js/modules/es.number.parse-int");
require("core-js/modules/es.number.to-fixed");
require("core-js/modules/es.object.assign");
require("core-js/modules/es.object.define-getter");
require("core-js/modules/es.object.define-setter");
require("core-js/modules/es.object.entries");
require("core-js/modules/es.object.freeze");
require("core-js/modules/es.object.from-entries");
require("core-js/modules/es.object.get-own-property-descriptor");
require("core-js/modules/es.object.get-own-property-descriptors");
require("core-js/modules/es.object.get-own-property-names");
require("core-js/modules/es.object.get-prototype-of");
require("core-js/modules/es.object.is");
require("core-js/modules/es.object.is-extensible");
require("core-js/modules/es.object.is-frozen");
require("core-js/modules/es.object.is-sealed");
require("core-js/modules/es.object.keys");
require("core-js/modules/es.object.lookup-getter");
require("core-js/modules/es.object.lookup-setter");
require("core-js/modules/es.object.prevent-extensions");
require("core-js/modules/es.object.seal");
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.object.values");
require("core-js/modules/es.promise");
require("core-js/modules/es.promise.finally");
require("core-js/modules/es.reflect.apply");
require("core-js/modules/es.reflect.construct");
require("core-js/modules/es.reflect.define-property");
require("core-js/modules/es.reflect.delete-property");
require("core-js/modules/es.reflect.get");
require("core-js/modules/es.reflect.get-own-property-descriptor");
require("core-js/modules/es.reflect.get-prototype-of");
require("core-js/modules/es.reflect.has");
require("core-js/modules/es.reflect.is-extensible");
require("core-js/modules/es.reflect.own-keys");
require("core-js/modules/es.reflect.prevent-extensions");
require("core-js/modules/es.reflect.set");
require("core-js/modules/es.reflect.set-prototype-of");
require("core-js/modules/es.regexp.constructor");
require("core-js/modules/es.regexp.flags");
require("core-js/modules/es.regexp.to-string");
require("core-js/modules/es.set");
require("core-js/modules/es.string.code-point-at");
require("core-js/modules/es.string.ends-with");
require("core-js/modules/es.string.from-code-point");
require("core-js/modules/es.string.includes");
require("core-js/modules/es.string.iterator");
require("core-js/modules/es.string.match");
require("core-js/modules/es.string.pad-end");
require("core-js/modules/es.string.pad-start");
require("core-js/modules/es.string.raw");
require("core-js/modules/es.string.repeat");
require("core-js/modules/es.string.replace");
require("core-js/modules/es.string.search");
require("core-js/modules/es.string.split");
require("core-js/modules/es.string.starts-with");
require("core-js/modules/es.string.trim");
require("core-js/modules/es.string.trim-end");
require("core-js/modules/es.string.trim-start");
require("core-js/modules/es.string.anchor");
require("core-js/modules/es.string.big");
require("core-js/modules/es.string.blink");
require("core-js/modules/es.string.bold");
require("core-js/modules/es.string.fixed");
require("core-js/modules/es.string.fontcolor");
require("core-js/modules/es.string.fontsize");
require("core-js/modules/es.string.italics");
require("core-js/modules/es.string.link");
require("core-js/modules/es.string.small");
require("core-js/modules/es.string.strike");
require("core-js/modules/es.string.sub");
require("core-js/modules/es.string.sup");
require("core-js/modules/es.typed-array.float32-array");
require("core-js/modules/es.typed-array.float64-array");
require("core-js/modules/es.typed-array.int8-array");
require("core-js/modules/es.typed-array.int16-array");
require("core-js/modules/es.typed-array.int32-array");
require("core-js/modules/es.typed-array.uint8-array");
require("core-js/modules/es.typed-array.uint8-clamped-array");
require("core-js/modules/es.typed-array.uint16-array");
require("core-js/modules/es.typed-array.uint32-array");
require("core-js/modules/es.typed-array.copy-within");
require("core-js/modules/es.typed-array.every");
require("core-js/modules/es.typed-array.fill");
require("core-js/modules/es.typed-array.filter");
require("core-js/modules/es.typed-array.find");
require("core-js/modules/es.typed-array.find-index");
require("core-js/modules/es.typed-array.for-each");
require("core-js/modules/es.typed-array.from");
require("core-js/modules/es.typed-array.includes");
require("core-js/modules/es.typed-array.index-of");
require("core-js/modules/es.typed-array.iterator");
require("core-js/modules/es.typed-array.join");
require("core-js/modules/es.typed-array.last-index-of");
require("core-js/modules/es.typed-array.map");
require("core-js/modules/es.typed-array.of");
require("core-js/modules/es.typed-array.reduce");
require("core-js/modules/es.typed-array.reduce-right");
require("core-js/modules/es.typed-array.reverse");
require("core-js/modules/es.typed-array.set");
require("core-js/modules/es.typed-array.slice");
require("core-js/modules/es.typed-array.some");
require("core-js/modules/es.typed-array.sort");
require("core-js/modules/es.typed-array.subarray");
require("core-js/modules/es.typed-array.to-locale-string");
require("core-js/modules/es.typed-array.to-string");
require("core-js/modules/es.weak-map");
require("core-js/modules/es.weak-set");
require("core-js/modules/web.dom-collections.for-each");
require("core-js/modules/web.dom-collections.iterator");
require("core-js/modules/web.queue-microtask");
require("core-js/modules/web.url");
require("core-js/modules/web.url.to-json");
require("core-js/modules/web.url-search-params");
require("regenerator-runtime");
window.onload = function (eve) {
return document.body.innerHTML = "ok";
};
長いですが core-js がひとつひとつのモジュールの require に置き換えられています
targets を chrome: 75 に置き換えてみると
"use strict";
require("core-js/modules/web.immediate");
window.onload = eve => document.body.innerHTML = "ok";
になりました
ところで immediate って stable だっけ?
nodejs であるだけで非標準のままだったような?
useBuiltIns: usage
usage にしてみるとimport "regenerator-runtime/runtime"
window.onload = eve => document.body.innerHTML = "ok"
"use strict";
require("regenerator-runtime/runtime");
window.onload = function (eve) {
return document.body.innerHTML = "ok";
};
特に polyfill が必要な機能を使ってないので何も追加されていません
ちょっと修正して ES2015 機能をいくつか入れてみます
import "regenerator-runtime"
window.onload = eve => {
Array.from([1], e => [2].includes(e))
String.raw`a`.repeat(10)
}
"use strict";
require("core-js/modules/es.array.from");
require("core-js/modules/es.array.includes");
require("core-js/modules/es.array.slice");
require("core-js/modules/es.object.freeze");
require("core-js/modules/es.string.iterator");
require("core-js/modules/es.string.raw");
require("core-js/modules/es.string.repeat");
require("regenerator-runtime");
function _templateObject() {
var data = _taggedTemplateLiteral(["a"]);
_templateObject = function _templateObject() {
return data;
};
return data;
}
function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
window.onload = function (eve) {
Array.from([1], function (e) {
return [2].includes(e);
});
String.raw(_templateObject()).repeat(10);
};
使った機能の polyfill だけ入ってますね
これを見ると webpack のときの usage だけの問題とか起きなさそうですけど なんでなんでしょうね
Chrome の場合は追加なしになります
"use strict";
require("regenerator-runtime");
window.onload = eve => {
Array.from([1], e => [2].includes(e));
String.raw`a`.repeat(10);
};