前言
ES2015/ES2016/ES2017等新语法,新API的出现让前端写起来更爽,更不用说考虑到面向未来编码。可我们使用这些新语法,新API,代码的运行兼容性势必受到影响。babel的适时出现,解决了我们使用next generation JavaScript的顾虑!它可能是我们最常使用的JavaScript转码工具了,可是你真的了解它的使用了吗?
从TC39说起
TC39是ECMAScript规范的设计制定组织,它的成员包含主流浏览器厂商,它实际推动着JavaScript语言的发展的。我们知道,ECMAScript是规范,而JavaScript语言是参照ECMAScript规范的实现。
1997年,产出ECMAScript。起因是1996年底,Netscape公司将JavaScript提交给ECMA International组织对JavaScript语言进行标准化。
1998年,发布ECMAScript2
1999年,发布ECMAScript3,成为JavaScript的通行标准,得到了各浏览器厂商的广泛支持。
2009年,发布ECMAScript5,其间,ECMAScript4因为改版过于激进,中途夭折。
2015年,ECMAScript6发布,也称为ES2015,ES.Harmony
2016年,ECMAScript7发布,也称为ES2016,ES.Next
2017年,ECMAScript8发布,也称为ES2017
TC39 Process规定了每项新特性纳入规范的过程,分为5个阶段
stage0: strawman,可以理解成idea迸发
stage1: proposal,也就是书面化产出一个提案
stage2: draft,产出规范的草案
stage3: candidate,该特性进入候选阶段
stage4: finished,会尽快随版正式发布
未来,按约定每年会继续发布一个版本,貌似也预示着JavaScript社区的活跃。语言规范迭代这么快,对老版本浏览器的支持这项光荣而伟大的任务就交给了babel。
常用的babel packages
babel-core
babel转码器,提供转码API,babel-core虽然常用,但日常开发很少直接调用,webpack中使用babel-loader加载js,babel-loader其实会直接调用babel-core API对文件进行转码。
babel.transform(code: string, options?: Object)
babel.transformFile(filename: string, options?: Object, callback: Function)
babel.transformFileSync(filename: string, options?: Object)
babel.transformFromAst(ast: Object, code?: string, options?: Object)
babel-cli
主要用于babel转码的命令行调用,前端项目基本已经离不开webpack,所以babel-cli经常用于node项目中的build,因为我们可能会写async/await,但我们的服务端环境是V6.x
babel app --out-dir webapp
babel-polyfill
babel默认只做转码,ployfill的工作(比如一些新内置对象、新的静态方法、实例方法),需要在运行入口引人babel-polyfill来支持,为运行环境提供垫片支持。
需要polyfill:
module.exports = {
builtins: {
Symbol: "symbol",
Promise: "promise",
Map: "map",
WeakMap: "weak-map",
Set: "set",
WeakSet: "weak-set",
Observable: "observable",
setImmediate: "set-immediate",
clearImmediate: "clear-immediate",
asap: "asap"
//parseFloat: "parse-float", // temporary disabled
//parseInt: "parse-int" // temporary disabled
},
methods: {
Array: {
concat: "array/concat", // deprecated
copyWithin: "array/copy-within",
entries: "array/entries",
every: "array/every",
fill: "array/fill",
filter: "array/filter",
findIndex: "array/find-index",
find: "array/find",
forEach: "array/for-each",
from: "array/from",
includes: "array/includes",
indexOf: "array/index-of",
//isArray: "array/is-array", // temporary disabled
join: "array/join",
keys: "array/keys",
lastIndexOf: "array/last-index-of",
map: "array/map",
of: "array/of",
pop: "array/pop", // deprecated
push: "array/push", // deprecated
reduceRight: "array/reduce-right",
reduce: "array/reduce",
reverse: "array/reverse", // deprecated
shift: "array/shift", // deprecated
slice: "array/slice", // deprecated
some: "array/some",
sort: "array/sort",
splice: "array/splice",
unshift: "array/unshift", // deprecated
values: "array/values"
},
JSON: {
stringify: "json/stringify"
},
Object: {
assign: "object/assign",
create: "object/create",
defineProperties: "object/define-properties",
defineProperty: "object/define-property",
entries: "object/entries",
freeze: "object/freeze",
getOwnPropertyDescriptor: "object/get-own-property-descriptor",
getOwnPropertyDescriptors: "object/get-own-property-descriptors",
getOwnPropertyNames: "object/get-own-property-names",
getOwnPropertySymbols: "object/get-own-property-symbols",
getPrototypeOf: "object/get-prototype-of",
isExtensible: "object/is-extensible",
isFrozen: "object/is-frozen",
isSealed: "object/is-sealed",
is: "object/is",
keys: "object/keys",
preventExtensions: "object/prevent-extensions",
seal: "object/seal",
setPrototypeOf: "object/set-prototype-of",
values: "object/values"
},
RegExp: {
escape: "regexp/escape" // deprecated
},
Math: {
acosh: "math/acosh",
asinh: "math/asinh",
atanh: "math/atanh",
cbrt: "math/cbrt",
clz32: "math/clz32",
cosh: "math/cosh",
expm1: "math/expm1",
fround: "math/fround",
hypot: "math/hypot",
imul: "math/imul",
log10: "math/log10",
log1p: "math/log1p",
log2: "math/log2",
sign: "math/sign",
sinh: "math/sinh",
tanh: "math/tanh",
trunc: "math/trunc",
iaddh: "math/iaddh",
isubh: "math/isubh",
imulh: "math/imulh",
umulh: "math/umulh"
},
Symbol: {
for: "symbol/for",
hasInstance: "symbol/has-instance",
isConcatSpreadable: "symbol/is-concat-spreadable",
iterator: "symbol/iterator",
keyFor: "symbol/key-for",
match: "symbol/match",
replace: "symbol/replace",
search: "symbol/search",
species: "symbol/species",
split: "symbol/split",
toPrimitive: "symbol/to-primitive",
toStringTag: "symbol/to-string-tag",
unscopables: "symbol/unscopables"
},
String: {
at: "string/at",
codePointAt: "string/code-point-at",
endsWith: "string/ends-with",
fromCodePoint: "string/from-code-point",
includes: "string/includes",
matchAll: "string/match-all",
padLeft: "string/pad-left", // deprecated
padRight: "string/pad-right", // deprecated
padStart: "string/pad-start",
padEnd: "string/pad-end",
raw: "string/raw",
repeat: "string/repeat",
startsWith: "string/starts-with",
trim: "string/trim",
trimLeft: "string/trim-left",
trimRight: "string/trim-right",
trimStart: "string/trim-start",
trimEnd: "string/trim-end"
},
Number: {
EPSILON: "number/epsilon",
isFinite: "number/is-finite",
isInteger: "number/is-integer",
isNaN: "number/is-nan",
isSafeInteger: "number/is-safe-integer",
MAX_SAFE_INTEGER: "number/max-safe-integer",
MIN_SAFE_INTEGER: "number/min-safe-integer",
parseFloat: "number/parse-float",
parseInt: "number/parse-int"
},
Reflect: {
apply: "reflect/apply",
construct: "reflect/construct",
defineProperty: "reflect/define-property",
deleteProperty: "reflect/delete-property",
enumerate: "reflect/enumerate", // deprecated
getOwnPropertyDescriptor: "reflect/get-own-property-descriptor",
getPrototypeOf: "reflect/get-prototype-of",
get: "reflect/get",
has: "reflect/has",
isExtensible: "reflect/is-extensible",
ownKeys: "reflect/own-keys",
preventExtensions: "reflect/prevent-extensions",
setPrototypeOf: "reflect/set-prototype-of",
set: "reflect/set",
defineMetadata: "reflect/define-metadata",
deleteMetadata: "reflect/delete-metadata",
getMetadata: "reflect/get-metadata",
getMetadataKeys: "reflect/get-metadata-keys",
getOwnMetadata: "reflect/get-own-metadata",
getOwnMetadataKeys: "reflect/get-own-metadata-keys",
hasMetadata: "reflect/has-metadata",
hasOwnMetadata: "reflect/has-own-metadata",
metadata: "reflect/metadata"
},
System: {
global: "system/global"
},
Error: {
isError: "error/is-error" // deprecated
},
Date: {
//now: "date/now" // temporary disabled
},
Function: {
// Warning: /virtual/ method - prototype, not static, version
//bind: "function/virtual/bind" // temporary disabled
}
}
};
babel-register
引人后,require
方法会被重写并绑定一个hook到babel的complier,也就是说当再次通过require
加载其他脚本文件时会在运行时自动通过babel转码之。不适用与生产环境。
require('require-register');
const file = require('file.es'); // 引用的文件会在运行时自动转码
.babelrc
通过在.babelrc文件中指定转码plugin,babel才能达到指定特性的转码效果。
{
plugins: [
'transform-es2015-arrow-functions',
'transform-es2015-block-scoped-functions'
]
}
一个一个plugin添加可能很麻烦?babel提供了preset
,它可以理解为plugin的组合,你可以这样创建一个preset:
为你的preset创建一个git仓库,比如babel-preset-mynamepreset
git clone <仓库地址>
目录结构很简单,如下
编辑index.js
发布到npm仓库
// 目录结构
- package.json
|
- src
|-- index.js
// index.js
import arrowFunctions from "babel-plugin-transform-es2015-arrow-functions";
import blockScopedFunctions from "babel-plugin-transform-es2015-block-scoped-functions";
export default {
plugins: [
arrowFunctions,
blockScopedFunctions
]
};
当然,社区有相对更成熟的presets,可以直接引用, 比如
babel-preset-es2015
babel-preset-stage-0
babel-preset-stage-1
babel-preset-stage-2
babel-preset-stage-3
babel-preset-es2016
babel-preset-es2017
babel-preset-latest
...
可以按需选择使用~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。