babel的安装和使用 {ignore}
官网:babeljs.io/ 民间中文网:www.babeljs.cn/
babel简介
babel一词来自于希伯来语,直译为巴别塔
巴别塔象征的统一的国度、统一的语言
而今天的JS世界缺少一座巴别塔,不同版本的浏览器能识别的ES标准并不相同,就导致了开发者面对不同版本的浏览器要使用不同的语言,和古巴比伦一样,前端开发也面临着这样的困境。
babel的出现,就是用于解决这样的问题,它是一个编译器,可以把不同标准书写的语言,编译为统一的、能被各种浏览器识别的语言
由于语言的转换工作灵活多样,babel的做法和postcss、webpack差不多,它本身仅提供一些分析功能,真正的转换需要依托于插件完成
babel的安装
babel可以和构建工具联合使用,也可以独立使用
如果要独立的使用babel,需要安装下面两个库:
- @babel/core:babel核心库,提供了编译所需的所有api
- @babel/cli:提供一个命令行工具,调用核心库的api完成编译
npm i -D @babel/core @babel/cli
babel的使用
@babel/cli的使用极其简单
它提供了一个命令babel
# 按文件编译
babel 要编译的文件 -o 编辑结果文件
# 按目录编译
babel 要编译的整个目录 -d 编译结果放置的目录
babel的配置
可以看到,babel本身没有做任何事情,真正的编译要依托于babel插件和babel预设来完成
babel预设和postcss预设含义一样,是多个插件的集合体,用于解决一系列常见的兼容问题
如何告诉babel要使用哪些插件或预设呢?需要通过一个配置文件.babelrc
{
"presets": [],
"plugins": []
}
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.8.4"
}
}
----------------------华丽分割线-------------------------
babel预设
babel有多种预设,最常见的预设是@babel/preset-env
@babel/preset-env可以让你使用最新的JS语法,而无需针对每种语法转换设置具体的插件
配置
{
"presets": [
"@babel/preset-env"
]
}
兼容的浏览器
@babel/preset-env需要根据兼容的浏览器范围来确定如何编译,和postcss一样,可以使用文件.browserslistrc来描述浏览器的兼容范围
last 3 version
> 1%
not ie <= 8
自身的配置
和postcss-preset-env一样,@babel/preset-env自身也有一些配置
具体的配置见:www.babeljs.cn/docs/babel-…
配置方式是:
{
"presets": [
["@babel/preset-env", {
"配置项1": "配置值",
"配置项2": "配置值",
"配置项3": "配置值"
}]
]
}
其中一个比较常见的配置项是usebuiltins,该配置的默认值是false
它有什么用呢?由于该预设仅转换新的语法,并不对新的API进行任何处理
例如:
new Promise(resolve => {
resolve()
})
转换的结果为
new Promise(function (resolve) {
resolve();
});
如果遇到没有Promise构造函数的旧版本浏览器,该代码就会报错
而配置usebuiltins可以在编译结果中注入这些新的API,它的值默认为false,表示不注入任何新的API,可以将其设置为usage,表示根据API的使用情况,按需导入API
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3
}]
]
}
.babelrc
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3
}]
]
}
.browserslistrc
last 3 version
> 1%
not ie <= 8
core-js:常规es6向下兼容库
regenerator-runtime: 处理类似 async等新语法
package.josn
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "babel js -d dist -w"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.8.4",
"@babel/preset-env": "^7.8.4"
},
"dependencies": {
"core-js": "^3.6.4",
"regenerator-runtime": "^0.13.3"
}
}
js/index.js
async function Test() {}
const a = { a: 1 };
const b = { b: 2 };
const c = { ...a, ...b };
执行命令 ./node_modules/.bin/babel js/index.js -d dist
"use strict";
require("core-js/modules/es.symbol");
require("core-js/modules/es.array.filter");
require("core-js/modules/es.array.for-each");
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.keys");
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
require("core-js/modules/web.dom-collections.for-each");
require("regenerator-runtime/runtime");
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
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); }); }; }
function Test() {
return _Test.apply(this, arguments);
}
function _Test() {
_Test = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return _Test.apply(this, arguments);
}
var a = {
a: 1
};
var b = {
b: 2
};
var c = _objectSpread({}, a, {}, b);
----------------------华丽分割线-------------------------
babel插件
上节课补充:@babel/polyfill 已过时,目前被
core-js和generator-runtime所取代
除了预设可以转换代码之外,插件也可以转换代码,它们的顺序是:
- 插件在 Presets 前运行。
- 插件顺序从前往后排列。
- Preset 顺序是颠倒的(从后往前)。
通常情况下,@babel/preset-env只转换那些已经形成正式标准的语法,对于某些处于早期阶段、还没有确定的语法不做转换。
如果要转换这些语法,就要单独使用插件
下面随便列举一些插件
@babel/plugin-proposal-class-properties
该插件可以让你在类中书写初始化字段
class A {
a = 1;
constructor(){
this.b = 3;
}
}
@babel/plugin-proposal-function-bind
该插件可以让你轻松的为某个方法绑定this
function Print() {
console.log(this.loginId);
}
const obj = {
loginId: "abc"
};
obj::Print(); //相当于:Print.call(obj);
遗憾的是,目前vscode无法识别该语法,会在代码中报错,虽然并不会有什么实际性的危害,但是影响观感
@babel/plugin-proposal-optional-chaining
const obj = {
foo: {
bar: {
baz: 42,
},
},
};
const baz = obj?.foo?.bar?.baz; // 42
const safe = obj?.qux?.baz; // undefined
babel-plugin-transform-remove-console
该插件会移除源码中的控制台输出语句
console.log("foo");
console.error("bar");
编译后
@babel/plugin-transform-runtime
用于提供一些公共的API,这些API会帮助代码转换
.babelrc
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3
}]
],
"plugins": [
["@babel/proposal-class-properties", {
"loose": true
}],
"@babel/proposal-function-bind",
"@babel/proposal-optional-chaining",
"transform-remove-console",
"@babel/transform-runtime"
]
}
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "babel js -d dist -w"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.8.4",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-function-bind": "^7.8.3",
"@babel/plugin-proposal-optional-chaining": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"babel-plugin-transform-remove-console": "^6.9.4"
},
"dependencies": {
"@babel/runtime": "^7.8.4",
"core-js": "^3.6.4",
"regenerator-runtime": "^0.13.3"
}
}
----------------------华丽分割线-------------------------
在webpack中使用babel
.babelrc
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3
}]
]
}
.browserslistrc
last 3 version
> 1%
not ie <= 8
packge.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/preset-env": "^7.8.4",
"babel-loader": "^8.0.6",
"core-js": "^3.6.4",
"regenerator-runtime": "^0.13.3",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10"
}
}
webpack.config.js
module.exports = {
mode: "development",
devtool: "source-map",
module: {
rules: [
{ test: /\.js$/, use: "babel-loader" }
]
}
}