Babel is a compiler that allows you to use the latest versions of the ES specification such as ES2015 (ES6), ES2016 (ES7), and ES2017 (ES8) and compile them into older ES5 versions
* * * * * * * * * * * * * * * * * * * * * * * * *Docs.npmjs.com/cli/v7/usin…The @babel version is only available.
Create the project first (use babel7 here)
npm init -y
Copy the code
Install Babel – cli
npm i -D @babel/cli @babel/core @babel/preset-env
Copy the code
Create SRC folder and create file index.js in SRC folder. Create dist file package.json and add commands
"scripts": {
"babel": "babel ./src/index.js --out-file ./dist/build.js"
}
Copy the code
@babel/preset-env
Index. js writes the code
const arr = [1.2.3.4.5]
arr.forEach((item) = > console.log(item))
arr.reduce((accumulator, item) = > {
return item + accumulator
}, 10)
class a {
constructor(name, age) {
this.name = name
this.age = age
}
getAge() {
const { age } = this
console.log(age)
}
}
const mp = new Map()
mp.set(arr, 'array')
mp.get(arr)
Copy the code
After running NPM run Babel, view the build file for Dist as shown below
"use strict";
function _classCallCheck(instance, Constructor) { if(! (instanceinstanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); }}function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var arr = [1.2.3.4.5];
arr.forEach(function (item) {
return console.log(item);
});
arr.reduce(function (accumulator, item) {
return item + accumulator;
}, 10);
var a = /*#__PURE__*/function () {
function a(name, age) {
_classCallCheck(this, a);
this.name = name;
this.age = age;
}
_createClass(a, [{
key: "getAge".value: function getAge() {
var age = this.age;
console.log(age); }}]);returna; } ();var mp = new Map(a); mp.set(arr,'array');
mp.get(arr);
Copy the code
You can see that @babel/preset-env reincarnates the arrow function, class declaration, in ES5’s syntactic form, just with a syntactic transformation
@bable/polyfill
If you want your browser to be compatible with new native methods such as Map, Promise, array.reduce, use @babel/ Polyfill
npm i @babel/polyfill -S
Copy the code
Note: @bable/ Polyfill (internally integrated with Core-js and Regenerator)
Babel does not convert new apis, such as global objects such as Generator, Set, Proxy, Promise, and new methods such as includes and array.form. This is where some tools are needed to make this compatible for the browser.
Babel-polyfill is designed to simulate a complete ES6+ environment and is intended for use in applications rather than libraries/tools.
The plug-in
Babel is a compiler that parses, transforms, and generates code in three phases at a high-level level.
The official Presets
Env, React, and flow Presets are available if you don’t want to configure them yourself. That is, the plugins configuration is preinstalled.
Stage-x (Experimental Presets, obsolete)
Stage-x presets are any drafts that are not included in official releases such as ES6/ES2015. Anything prior to Stage-3 should be used with caution. There are several experimental versions:
- Stage 0 – Draft: Just an idea that could be a Babel plugin
- Stage 1 – Proposal: Something worth moving forward
- Stage 2 – Draft: Initialization specification
- Stage 3 – Candidates: Full specification and initialization browser implementation
- Stage 4 – Completed: will be added to the next release
Babel7 deprecates es201x, removes stage-x, recommends env
The transformation plug-in
The conversion plug-in can be seen here.
Grammar plug-in
This plug-in allows Babel to parse special types of syntax.
The syntax plug-in is automatically used if the corresponding transformation plug-in already uses the transformation plug-in.
{
"parserOpts": {
"plugins": ["jsx"."flow"]}}Copy the code
The Plugins/Presets path
Use “plugins”: [” babel-plugin-myplugin “] or “plugins:”: [“./node_modules/pluginPath”].
Plugins/Preset shortcuts
If the plugin prefix is babel-plugin-, use “plugins:”: [“myPlugin”], presets” presets”: [“@org/babel-preset-name”]. The same is true for scope packs, “presets”: [“@org/babel-preset-name”] shortcut is: “presets”: [“@org/name”].
The Plugins/Presets order
When the two plug-ins are working on code at the same time, the conversion is preset in either plug-in or preset order.
- The plug-in runs before the Presets
- The plug-in order is from first to last
- Preset is reversed from last to first
Such as:
{
"plugins": [
"transform-decorators-legacy"."transform-class-properties"]}Copy the code
Transform-decorators-legacy followed by transform-class-properties will be run
The order of Presets is reversed:
{
"presets": [
"es2015"."react"."stage-2"]}Copy the code
It will run in stage-2, React, and ES2015 order. This is mainly due to backward compatibility, as most users put ES2015 before stage-0.
@ Babel/runtime and @ Babel/plugin – transform – runtime
But before we do that, let’s just wrap up the package that we introduced @babel/ Polyfill
npm i webapck webapck-cli babel-loader -D
Copy the code
Then add commands to package.json
"webpack": "webpack --config webpack.config.js"
Copy the code
Configure webpack.config.js as follows:
const path = require('path')
module.exports = {
entry:'./src/index.js'.mode: 'development'.output: {filename: 'build.js'.path: path.resolve(__dirname,'dist')},module: {
rules: [{test: /\.js$/,
use: {
loader: 'babel-loader'}}}}]Copy the code
After running NPM Run webpack, we can see that the package volume is very large, but we only use the syntax of Reduce and Map of ES6 +. And Polyfill overrides the method above the object prototype chain
Hash: 641CA6e440eb86f317ed Version: webPack 4.46.0 Time: 2187ms Asset Size Chunks Chunk Names build.js 482 KiB main [emitted] main Entrypoint main = build.js [. / node_modules / _ @ [email protected] @ @ Babel/polyfill/lib/index, js] 694 bytes {main} [built] [. / node_modules / _ @ [email protected] @ @ Babel/polyfill/lib/of noConflict js] 567 bytes {main} [built] [./node_modules/[email protected]@core-js/es6/index.js] 5.91kib {main} [built] [./node_modules/[email protected]@core-js/fn/array/flat-map.js] 108 bytes {main} [built] [./node_modules/[email protected]@core-js/fn/array/includes] 109 bytes {main} [built] [./node_modules/[email protected]@core-js/fn/object/entries.js] 109 bytes {main} [built] [./node_modules/[email protected]@core-js/fn/object/get-own-property-descriptors.js] 148 bytes {main} [built] [./node_modules/[email protected]@core-js/fn/object/values.js] 107 bytes {main} [built] [./node_modules/[email protected]@core-js/fn/promise/ final.js] 168 bytes {main} [built] [./node_modules/[email protected]@core-js/fn/string/pad-end.js] 108 bytes {main} [built] [./node_modules/[email protected]@core-js/fn/string/pad-start.js] 112 bytes {main} [built] [./node_modules/[email protected]@core-js/fn/string/trim-end.js] 114 bytes {main} [built] [./node_modules/[email protected]@core-js/fn/string/trim-start.js] 112 bytes {main} [built] [./node_modules/[email protected]@core-js/library/fn/global.js] 87 bytes {main} [built] [./ SRC /index.js] 1.22kib {main} [built] + 293 hidden modulesCopy the code
So we identified two shortcomings of Polyfill
- use
@babel/polyfill
This will lead to very large packages, many of which are not actually used, which is a waste of resources. @babel/polyfill
You can contaminate global variables, make changes in the prototype chain for many classes, and there are uncontrollable factors
@babel/runtime @babel-plugin-tranform-runtime @babel/runtime Using the @babel/ plugin-transform-Runtime plugin also prevents global contamination by sandbox shim and removes common helper functions to save code redundancy
That is, @babel/ Runtime is the core, the implementation, and @babel/ plugin-transform-Runtime is the butler, responsible for better reuse of @babel/ Runtime
The @babel/ plugin-transform-Runtime plugin also has a corejs parameter to fill in
Comment entry file for polyfill introduction
Configure.bablerc and add the plugins field
"plugins": [["@babel/transform-runtime", {
"absoluteRuntime": "@babel/runtime"
}]
Copy the code
Install corejs3 NPM i@babel/run-time corejs3 -s
Then run NPM run webpack and pack as follows:
Hash: 456b0421200450865ba4 Version: webPack 4.46.0 Time: 1142ms Asset Size Chunks Chunk Names build.js 164 KiB main [emitted] main Entrypoint main = build.js [. / node_modules / _ @ [email protected] @ @ Babel/runtime - corejs3 / core - js - stable/instance/for-each. Js] 66 bytes {main} [built] [. / node_modules / _ @ [email protected] @ @ Babel/runtime - corejs3 / core - js - stable/instance/reduce. Js] 64 bytes {main} [built] [./node_modules/_@[email protected]@@babel/runtime-corejs3/core-js-stable/map.js] 52 bytes {main} [built] [. / node_modules / _ @ [email protected] @ @ Babel/runtime - corejs3 / core - js/object/define - property. Js] 73 bytes . {the main} [built] [/ node_modules / _ @ [email protected] @ @ Babel/runtime - corejs3 / helpers/classCallCheck js], 274 Bytes {main} [built] [. / node_modules / _ @ [email protected] @ @ Babel/runtime - corejs3 / helpers/createClass js], 772 Bytes {main} [built] [. / node_modules / _core - [email protected] @ core - js - pure/es/instance/reduce the js] 250 bytes {main} [built] [./node_modules/[email protected]@core-js-pure/es/map/index.js] 254 bytes {main} [built] [. / node_modules / _core - [email protected] @ core - js - pure/features/object/define - property. Js] 82 bytes {main} [built] [. / node_modules / _core - [email protected] @ core - js - pure/internals/classof js] 1000 bytes {main} [built] [./node_modules/[email protected]@core-js-pure/modules/web.dom-collections.iterator.js] 820 bytes {main} [built] [./node_modules/[email protected]@core-js-pure/stable/instance/for-each. [. / node_modules / _core - [email protected] @ core - js - pure/stable/instance/reduce the js] 75 bytes {main} [built] [./node_modules/[email protected]@core-js-pure/stable/map/index.js] 63 bytes {main} [built] [./ SRC /index.js] 1020 bytes {main} [built] + 96 hidden modulesCopy the code
The packing size is much smaller. Take a look at the webpack wrapped code, captured below
eval("module.exports = __webpack_require__(/*! Core - js - pure/stable/instance/reduce * / \ ".. / node_modules / _core - [email protected] @ core - js - pure/stable/instance/reduce the js \ "); \n\n//# SourceURL = webpack: / / /. / node_modules / _ @ [email protected] @ @ Babel/runtime - corejs3 / core - js - stable/instance/reduc e.js?");
eval("module.exports = __webpack_require__(/*! Core - js - pure/stable/map * / \ ".. / node_modules / _core - [email protected] @ core - js - pure/stable/map/index, js \ "); \n\n//# SourceURL = webpack: / / /. / node_modules / _ @ [email protected] @ @ Babel/runtime - corejs3 / core - js - stable/map. Js?");
Copy the code
You can see that core-js-pure is used to prevent contamination of global variables.
To sum up, the advantages of @babel/ plugin-transform-Runtime are:
- Does not pollute global variables
- Multiple uses will only pack once
- Dependency unification is introduced on demand, without repeated introduction and redundant introduction
Use of babel-preset-env, babel-polyfill
The default @babel/preset-env only converts syntax, which is the arrow function we saw, const, etc. If you further need to convert built-in objects and instance methods, you need to use Polyfill, which requires a bit of configuration.
There is a crucial parameter, useBuiltIns, that controls how @babel/preset-env helps us import polyfill’s core, and it has three values to choose from
entry
This is an import, as long as we say import “core-js” or import “@babel/polyfill” in the package configuration entry or file entry, Babel will introduce the required polyfills for us based on the target browser (Browserslist) that you are currently configuring.
Pack NPM I core-js-s first
Import ‘core-js’ from index.js and comment out //import ‘@babel/polyfill’;
Babelrc adds “useBuiltIns”: “Entry”. Babelrc is configured as follows
{
"presets": [["@babel/preset-env", {
"targets": {
"browsers": [
"last 2 versions"]},"useBuiltIns": "entry"."corejs": "3"}}]]Copy the code
Looking at build.js, you can see that Babel replaces the import “core-js” we filled in with a large polyfill instead
useage
When useBuiltIns = useage, the target browser (Browserslist) and the features used in the code are referenced to add polyfills as needed, because polyfills are automatically loaded, There is no need to introduce polyfill manually, so you can comment out the import ‘core-js’ of the code file; The packaged file is much smaller, as follows
"use strict";
require("core-js/modules/es.array.reduce.js");
require("core-js/modules/es.function.name.js");
require("core-js/modules/es.map.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/es.string.iterator.js");
require("core-js/modules/es.array.iterator.js");
require("core-js/modules/web.dom-collections.iterator.js");
require("core-js");
function _classCallCheck(instance, Constructor) { if(! (instanceinstanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); }}function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var arr = [1.2.3.4.5];
arr.forEach(function (item) {
return console.log(item);
});
arr.reduce(function (accumulator, item) {
return item + accumulator;
}, 10);
var a = /*#__PURE__*/function () {
function a(name, age) {
_classCallCheck(this, a);
this.name = name;
this.age = age;
}
_createClass(a, [{
key: "getAge".value: function getAge() {
var age = this.age;
console.log(age); }}]);returna; } ();var mp = new Map(a); mp.set(arr,'array');
console.log(mp.get(arr));
Copy the code
false
The last one, useBuiltIns = false, is easy. This is also the default, and it is used without introducing polyfill packaged code
"use strict";
function _classCallCheck(instance, Constructor) { if(! (instanceinstanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); }}function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
// import '@babel/polyfill';
// import 'core-js'
var arr = [1.2.3.4.5];
arr.forEach(function (item) {
return console.log(item);
});
arr.reduce(function (accumulator, item) {
return item + accumulator;
}, 10);
var a = /*#__PURE__*/function () {
function a(name, age) {
_classCallCheck(this, a);
this.name = name;
this.age = age;
}
_createClass(a, [{
key: "getAge".value: function getAge() {
var age = this.age;
console.log(age); }}]);returna; } ();var mp = new Map(a); mp.set(arr,'array');
console.log(mp.get(arr));
Copy the code
As you can see, polyfill is not introduced
Entry and @ Babel/runtime
Different from usage, in Entry mode, after @babel/ Runtime processing, there are not only various help functions but also many polyfills, which will lead to an inexorable increase in packaging volume.
The plugin for Babel runs before prset, so preset-env gets the @ Babel/Runtime wrapped with the help function, and useage checks the code to see what new features it uses, so it just gets a bunch of preset functions, No effect, of course.
conclusion
@babel/preset-env
Have according touseBuiltIns
Multiple polyfill implementations of parameters have the advantage of relatively complete coverage, but the disadvantage is that they will pollute the whole world
- Entry covers a full area, but packing volume is naturally large.
- Usage can introduce polyfill as needed and the package size is small, but if the package ignores node_modules then compatibility issues will occur if the third party package is not translated
@babel/runtime
Since Babel 7.4, corejs 3 has also implemented support for various built-in objects, and relies on@babel/plugin-transform-runtime
The ability of sandbox shim and code reuse, avoid the problem of help function repeat inject too much, the advantage of this way is not polluting the global, suitable for use in class library development
It is meaningless to use one of the above two methods (1 and 2), which may cause duplicate polyfill files