babel-填坑之旅

裴鸿熙
2023-12-01

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的应用场景有很多,而且其也提供了许许多多的插件内容方便我们的使用。内容将会在之后持续的更新上来。如果文章有错误的话,希望读者们可以帮忙指出。十分感谢。

转载于:https://juejin.im/post/5be4f535e51d45053d5c3d3d

 类似资料: