1.前言:
JS开发的时候,少不了跨浏览器这一项烦人的活计。不仅仅针对浏览器种类的不同,还有浏览器的版本的不同,我们编写的JS代码多少会受到影响,这将严重的复杂化我们编码的过程,因为需要考虑不同浏览器以及不同版本之间的js代码的可用性。是的我们的代码变得冗长。同时,由于JS社区的活跃,其针对于JS的语法规范,或者是JS标准的版本日新月异,如何将不同于法写出来的JS代码,轻松地放在另一个环境下使用变得迫在眉睫。babel就是这样一款利器,他可以帮我们省去这些烦恼,专注于即系习惯的语法,开发我们的应用。
2.正文:
babel官网:babeljs.io/。
我们首先来看一看babel的接口。它是由多个依赖包组成:
核心依赖包:
-
@babel/core:babel转译器本身,提供了babel的转译API,如babel.transform等,用于对代码进行转译。像webpack的babel-loader就是调用这些API来完成转译过程的。
-
@babel/parse:JS解释器模块内容。提供parse接口解释,最新的ecmascript标准,以及JSX,Flow,TypeScript,和其他实验性语言。(这个模块便是以前的babylon)。
-
@babel/traverse:JS遍历AST节点模块。用于遍历解释器模块解析出来的AST节点。
-
@babel/generator:JS生成器,主要用于将解释器解释得到的AST生成成为可解析的JS代码。
由上面可得出babel在解析文件倒得出可运行JS文件的一个过程是: input string -> @babel/parser parser -> AST -> transformer[s] -> AST -> @babel/generator -> output string
其他功能包:
-
@babel/cli:少不得的命令行工具。cmd运行babel解析过程。并可以设置包括输出路径等等信息。
-
@babel/types:用于验证,构建,和修改AST节点。
-
@babel/polyfill:包装了core-js和 regenerate-runtime。
-
@babel/runtime:和polyfill相似,但是不会修饰全局环境将会和plugin-transform-runtime一同使用。
-
@babel/registor:通过使用node.js的require字段来引入。会自动的通过babel解析当前文件。
除此之外还有许多的相关的模块或者依赖包,暂时先不细说了。
.babelrc文件:
在我们使用babel的时候常常可以看到如影随形的.babelrc文件内容。他主要是用来配置我们的babel在编译JS的时候需要使用到的相关的插件或者其他的设置的,所以十分的重要,我们先来学习一下吧。P.S.当然babel配置也可以在package.json之中直接的编写,使用babel关键字就可以了。
.babelrc主要是为了配置preset和plugins内容项。
1.preset :预设。在配置文件之中我们可以先添加我们需要的预设环境。当然添加在配置文件之中的preset需要下载到本地。这样配置之后才会生效。我们先来简单的编写一段配置,然后慢慢的填充的方式来学习怎么对babel进行配置。先看原始数据。
{
"presets": ["@babel/preset-env"]
}
复制代码
上面表示的是引用preset-env预设。当然我们可以对当前的引入的预设添加带参设置。例如
{
"presets": [
["@babel/preset-env", options]
]
}
复制代码
其中的options可以有许多的关键字段,其中一个options是一个对象内容,当然依据不同的preset和plugins会提供不太相同的options的字段进行设置,这里我们是使用了preset-env预设所以暂时只介绍相关的字段,具体的options信息请点击这里查看。其中主要可用字段是有:
-
targets: String | Array | { [String]: string } 。默认为{},这一属性说明了当前的项目的适用环境。可以编写字符串的内容,作为boswerlist的遍历条件。例如:
"targets": "> 0.25%, not dead"
或者也可以使一个对象。来设置对于每一个浏览器最低版本的控制。例如:{ "targets": { "chrome": "58", "ie": "11" } }
,其中的浏览器关键字从如下之中选取:chrome, opera, edge, firefox, safari, ie, ios, android, node, electron
。 -
targets.esmodules:布尔值,是targets属性对象之中的一个值,其表示的是是否开启ES模式。可以和
type='module'
结合是用,来简化脚本。当检查到当前的属性的时候,targets之中的浏览器属性设置将会被无视。 -
module:其可以取值是:
"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | "auto" | false
默认值是false
。将当前的ES编译模式转化成为其他的语法模式,其中的cjs是commonjs的别名。 -
debug:布尔值,默认是
false
。将当前版本号和环境输出到控制台。 -
include:Array<String|RegExp>。这一属性表示的是永远包含的插件内容。当然输入的字符串内容是有一定规范的。要么是全名输入,或者可以使用*号表示,某一目录下所有的内容,或者是使用正则表达式的形势匹配需要引入的插件内容。
-
exclude:同include相同,不过它表示的是需要排除或者移除的插件内容。
-
useBuiltIns:
"usage" | "entry" | false
三个值之一,这一属性确定preset-env如何处理polyfills。
当然还有其他的属性字段,具体使用的时候可以查询官方文档,这里只是为了说明所以以preset-env作为例子。以上字段是preset-env所有的设置字段,其他预设不一定有哟需要注意这一点。
2.plugins:在设置文件之中我们也可以引入plugins(插件内容)。常见内容也和preset的是相通的,只是引入属性的关键字变成了plugins。当然每个插件也有自己的属性字段可以设置咯。
3.ignore:忽视文件属性配置。例如:
{
ignore:[
index.js //当前文件将会被babel忽略编译。
]
}
复制代码
4.minified:用于设置编译后是否压缩,当使用cli的进行打包配置的时候将会产生效果,但是如果使用其他的架构引入babel的话,当前配置可能会无效果。
5.comments:布尔类型,表示打包编译之后不产生注释内容。在webpack之中使用UglifyJsPlugin插件也是一样的效果。
6.env:设置对应环境下的配置。其可设置方式是在文件的最外层给定对象的关键字,并使用环境设置作为对象属性关键字,并在属性对象之中进行当前环境下的内容配置。这么说可能不太清楚,我们看一下例子吧:
{
"env": {
// test 是提前设置的环境变量,如果没有设置BABEL_ENV则使用NODE_ENV,如果都没有设置默认就是development
"test": {
"presets": ["env", "stage-2"],
// instanbul是一个用来测试转码后代码的工具
"plugins": ["istanbul"]
}
}
}
复制代码
当然在打包编译的时候,env的值将会从process.env.BABEL_ENV
之中获取,如果没有,则将会获取pocess.env.NODE_ENV
,如果还是没有信息的话,将会默认是development
。
babel的使用
接下来了解了相关的包之后,我们应该开始了解一下BABEL是如何使用的了。我们将会依据不同的使用情况来说明babel的使用方式。
1.端开发:在没有任何的框架或者包管理的时候,我们需要运用babel来开发端内容的情况下,应该如何使用。
-
安装引入:我们可以直接的使用script标签来引入相关的插件包内容,我们需要引入的是babel-standalone包。这个包的地址是https://unpkg.com/babel-standalone@6/babel.min.js。当我们引入了这个包的时候,babel的api将会暴露给我们。
-
使用:当引入了插件包的情况之后,babel会自动的解析 标签属性 type = “text/babel” 或者“text/jsx” 的标签其中的信息。同时,我们可以使用data-plugins或者data-presets属性来引入plugins或者presets文件来使用。
<script type="text/babel" data-presets="es2015,stage-2">
const getMessage = () => "Hello World";
document.getElementById('output').innerHTML = getMessage();
</script>
复制代码
-
注意:是用这种方式引入的babel时,.babelrc文件是不可以用的。需要使用presets或者plugins的时候需要传递给babel.transform的。
-
APIs:Babel.transform(input [,options]):返回的是依据传递代码得出的对照代代码为主的封装的对象内容。可见例子如下:
var input = 'class Test{
constructor(x){
this.msg = x;
}
show(){
console.log(this.msg);
}
setMsg(msg){
this.msg = msg;
}
}
let t = new Test("testing");
t.show();';
var output = Babel.transform(input, { presets: ['es2015'] });
console.log(output);
复制代码
P.S.:在使用in-boswer-babel编程的时候要十分注意一个问题,在Benin编程测试的时候,当我们在引入了babel-standalone的之后,当script标签之中使用了type=“text/babel”的时候,src引入本地的js文件的时候,可能会出现跨域的问题(本地运行测试的时候,我又出现这个问题,不知道布在服务器之后会不会)。 例如 报错如下:
还有就是同这样的script标签下,使用require之类的引入语法,会报出错误。如下:
报错如下: 如上文中可见,如有任何错误,希望能帮忙指出,或者有知道问题所在的朋友能帮帮我。之后也会持续的更新这一块的内容。当然还有一点要注意的就是,端编程之中.babelrc文件是没有用处的。
2.babel-cli 相对于端开发的使用babel在node或者其他框架下使用的更为常见。首先我们来看一看babel的命令行工具吧。
首先我们需要下载babel-cli。本地安装会更好一些。我们可以通过shell命令来进行下载。
npm install --D @babel/core @babel/preset-env @babel/cli
其中的core是babel的核心库,前面提到了,preset-env则是帮助我们可以绊住我们转义最新的javascript语法内容。
P.S.什么是preset? 我们可以理解为,preset是babel预设的一连串的plugins。用于专门处理某一方面的问题,并不需要用户在一个个的导入plugins。从而方便开发。
在这里我们还需要注意的一点是babel^7的版本,我们下载包的时候不再是和之前使用babel-XXX的形势了。而是如上面例子一样使用 @babel/XXX的形势。一定要注意版本问题。
当我们下载好了相应的内容并写好了相关的代码的时候,我们可以通过cli来进行编译工作了。命令如下
babel src -d lib
src表示的是你要编辑的内容的位置(文件夹,或者是js文件)。lib表示的是编译好之后的内容将会放在什么目录下。 我们同样也可以再package.json之中配置script属性。例如:
"script":{
"build" : "babel src -d lib"
}
复制代码
之后,我们就可以直接在命令行之中通过npm run build来运行babel的编译功能。
当然我们在在编译之前要记得配置好.babelrc文件内容。因为babel编译的时候将会以.babelrc之中的设置为准。
3.webpack
大量的项目之中都会使用到webpack,进行管理和打包工作。babel也有专门的针对webpack环境下的babel使用。
webpack之中常常可以运用到许多的loader来方便我们的开发。而babel也可以通过webpack的loader来进行引入和使用。但是单单引入babel-loader,是不可行的,绝对要记得babel-core也需要一并视同npm下载到本地,否则要报错的哟(始终要记得 babel-core是babel的核心库,所有的解析方面的核心内容都是在这个包之中。)还有就是一些必要的预设和插件,具体命令可使用如下:
npm install babel-loader@8.0.0-beta.0 @babel/core @babel/preset-env webpack
上面这一行代码是将babel的7.x的版本进行引入,如果需要使用6.x的版本的话可以运行如下代码。
npm install babel-loader babel-core babel-preset-env webpack
当下在好我们的依赖包之后,我们可以通过.babelrc文件来进行配置,或者我们也可以通过webpack.config.js来进行配置。.babelrc文件的重要字段请看上文(2.babel-cli之中)。
webpack.config.js之中我们可以怎么配置呢。我们来举个例子说明吧:
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
复制代码
上图可见:我们将会在module之中的rules中对babel-loader进行配置。rules是webpack专门用于配置loader的一个属性。我们在配置babel-loader的时候,可以通过关键参数的配置来确定当前的babel的运行基准。
下面我们可以来了解一下options之中可以传递的参数内容:
- cacheDirectory:默认的值是false, 当有设置值的时候,指定的目录将会用来缓存loader的执行结果。之后webpack将会尝试读取缓存,来避免高兴能消耗的babel的重新编译过层。如果设置了一个空值
(loader: 'babel-loader?cacheDirectory')
或者true (loader: babel-loader?cacheDirectory=true)
,loader 将使用默认的缓存目录node_modules/.cache/babel-loader
,如果在任何根目录下都没有找到node_modules
目录,将会降级回退到操作系统默认的临时文件目录。 - cacheIdentifier:默认是一个由
babel-core
版本号,babel-loader
版本号,.babelrc
文件内容(存在的情况下),环境变量BABEL_ENV
的值(没有时降级到NODE_ENV
)组成的字符串。可以设置为一个自定义的值,在identifier
改变后,强制缓存失效。 - forceEnv:默认将解析
BABEL_ENV
然后是NODE_ENV
。允许你在loader
级别上覆盖BABEL_ENV/NODE_ENV
。对有不同babel
配置的,客户端和服务端同构应用非常有用。
当然我们可以见.babelrc的属性配置到webpack.config.js的内容之中,如下:
module: {
rules:[
{
test:/\.js/,
exclude:/(node_modules|bower_components)/,
use:[{
loader:'babel-loader',
options:{
presets:[['@babel/preset-env',{
debug:true
}]]
}
}
]
}
]
}
复制代码
但是有一点十分重要的就是在如下
presets:[['@babel/preset-env',{
debug:true
}]]
复制代码
的代码之中,我们不能使用module的配置关键字,因为如果此处传入了这一参数内容webpack在打包编译的时候将会错误。
所以需要额外注意。当然在我们的webpack.config.js之中如果有相关的配置了之后,我们实际上可以不用再另外的编写.babelrc文件来再去确定当前的babel的配置的。3.结束:
babel的应用场景有很多,而且其也提供了许许多多的插件内容方便我们的使用。内容将会在之后持续的更新上来。如果文章有错误的话,希望读者们可以帮忙指出。十分感谢。