Babel初探

Babel初探,第1张

babel 的介绍

浏览器的发展永远跟不上语言的发展,es6+虽然很普及了,但也不是所有浏览器都可以支持es6+语法。babel的诞生就源于此。


官方文档定义:
Babel 是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

babel 可以帮我们处理以下事情:

语法转换,将ES6+ 语法转换成ES5的代码对新版本ES的feature提供polyfillTS / flow支持(类型)生成source map...

那么他是怎么做到的呢?这就需要了解下babel工作原理了。

babel工作原理

Babel 是 source to source 的转换,可以理解为一个转译器,转译过程分为三个阶段:parsing(解析)、transforming(转化)、generating(生成):

parse:通过 parser 把源码转成抽象语法树(AST)transform:遍历 AST,调用各种 transform 插件对对抽象语法树(AST)进行变换 *** 作generate:把转换后的 AST 打印成目标代码,并生成 sourcemap

babel转译的具体过程如下:⚠️ 参考了掘金社区Babel 插件通关秘籍

在 transform 阶段,会应用各种内置的插件来完成 AST 的转换。

内置插件做的转换包括两部分:

是把不支持的语法转成目标环境支持的语法来实现相同功能是不支持的 api 自动引入对应的 polyfill。

更详细的没有深究,有兴趣的大佬可以参考这篇文章《Babel 插件通关秘籍-babel编译流程》。

babel 配置

接下来我们来详细了解一下babel的配置,及在项目中使用。

理论知识前提

babel将es6+(指es6及以上版本)分为

语法层: let、const、class、箭头函数等,这些需要在构建时进行转译,是指在语法层面上的转译,(比如class...将来会被转译成var function...)api层:Promise、includes、map等,这些是在全局或者Object、Array等的原型上新增的方法,它们可以由相应es5的方式重新定义
babel对这两个分类的转译的做法肯定是不一样的,我们也需要给出相应的配置

1. 安装

在使用babel之前首先要先安装相应的依赖, @babel/core、@babel/cli:

babel-core:Babel 的核心,包含各个核心的 API,供 babel 插件和打包工具使用babel-cli:命令行对 js 文件进行换码的工具
yarn add @babel/core @babel/cli -D

写一段简单的代码在src/index.js中,运行babel,将处理完的文件输出到dist/index.js

// src/index.js
const app = () => {};

//shell

// dist/index.js
const app = () => {};

会发现这时候转译出来的代码跟原来一样,这是为啥呢?

真实的情况是:

⚠️ Babel 本身不具有任何转化功能,当我们不配置任何插件时,经过 Babel 的代码和输入是相同的。Babel把转化的功能都分解到一个个 plugin 里面,每个Plugin都有自己的能力,能处理对应的ES代码。

所以我们需要安装插件

yarn add @babel/core @babel/cli @babel/preset-env -D
yarn add @babel/polyfill 

2. 配置文件

创建 babel.config.json 配置文件 ,data-valid为 🌰

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "modules": false,
                "useBuiltIns": "usage",
                "corejs": 3
            }
        ],
        "@babel/preset-react",
        "@babel/preset-typescript"
    ],
    "env": {
        "test": {
            "presets": [
                "@babel/preset-env",
                "@babel/preset-react",
                "@babel/preset-typescript"
            ]
        }
    },
    "plugins": [
        [
            "treasure",
            {
                "libraryName": "antd",
                "style": false
            }
        ],
        [
            "treasure",
            {
                "libraryName": "dt-react-component",
                "libraryDirectory": "lib",
                "camel2DashComponentName": "lower",
                "style": true
            },
            "dt-react-component"
        ],
        "@babel/transform-runtime",
        [
            "@babel/plugin-proposal-decorators",
            {
                "legacy": true
            }
        ],
        "@babel/plugin-syntax-dynamic-import",
        "@babel/plugin-proposal-class-properties",
        "@babel/plugin-proposal-optional-chaining",
        "@babel/plugin-transform-modules-commonjs"
    ]
}

参数分析:

preset-预设

官方推荐 env 会根据你配置的目标环境,生成插件列表来编译。

target属性:配置taget或者提供.browserlist文件,用于指定目标环境,使代码体积更小 polyfill-垫片(用于处理api层,转换内置函数/方法)

垫平不同浏览器或者不同环境下的差异,让新的内置函数、实例方法等在低版本浏览器中也可以使用。缺点是每次需要转换时,就必须要将其全部引入,会将不必要的在引入至全局。但如何解决呢? babel官方已经给出方法了 接着看!

useBuiltIns-位于预设中的参数,它的值有三种: false: 不对polyfills做任何 *** 作 entry: 根据target中浏览器版本的支持,将polyfills拆分引入,仅引入有浏览器不支持的polyfillusage: 官方推荐,检测代码中ES6/7/8等的使用情况,仅加载代码中用到的polyfills ,即按需加载

配置如下:

{
   "presets": [
       ["@babel/preset-env",{
           "useBuiltIns": "usage",
        	 "corejs":3
       }]
   ]
}
plugins

@babel/plugin-transform-runtime 插件按需加载!

小结一下

名称

作用

备注

babel-cli

允许命令行使用 babel 命令转译文件

babel-node

允许命令行使用 babel-node 直接转译+执行 node 文件

随 babel-cli 一同安装
babel-node = babel-polyfill + babel-register

babel-register

改写 require 命令,为其加载的文件进行转码,不对当前文件转码

只适用于开发环境

babel-polyfill

为所有 API 增加兼容方法

需要在所有代码之前 require,且体积比较大

babel-plugin-transform-runtime & babel-runtime

把帮助类方法从每次使用前定义改为统一 require,解决代码冗余,

解决全局污染

babel-runtime 安装为运行依赖

babel-loader

使用 webpack 时作为一个 loader 在代码混淆之前进行代码转换

3.调用编译(命令方式)

调用babel命令 将src中的文件 编译后放到lib中

// shell

./node_modules/.bin/babel src --out-dir lib
   或
npx babel src --out-dir lib

babel 的编译流程和目的从没有变过,但是完成这个目的的方式却变化很大,我们来回顾一下 babel 6,babel 7 都是怎么设计的,或许可以帮我们真正理解 babel。

babel6.x VS babel7.x

babel提供的能力是基于@babel/core这个核心库实现的,所以提到的版本通常也是@babel/core这个核心包的版本。当@babel/core发布新版本的时候,相关工具集都会随之升级到与之相同的版本号。

babel-loader 8.x对应babel-core 7.x
babel-loader 7.x对应babel-core 6.x

babel6

es 的标准一年一个版本,也就意味着 babel 插件要实时的去跟进,一年实现一系列插件。

想用 es6 语法就用 babel-preset-es2015,es7 就在引入 babel-preset-es2016 等等。如果是想用还没加入标准的特性,则分别用 babel-preset-stage0、babel-preset-stage1 等来引入。这样通过选择不同的 preset,加上手动引入一些插件,就是所有 babel 会做的转换。

babel 6 就是通过这种方式来支持各种目标环境不支持的特性转换的配置,集合求并集的过程。

babel6.x 需要安装的包:

npm install babel-loader --save

npm install babel-core --save

npm install babel-preset-es2015 --save

npm install babel-preset-stage-0 --save

npm install babel-plugin-transform-runtime --save

.babelrc文件

 {
	presets : ['es2015', 'stage-0'],
  plugins : ['transform-runtime']
 }

这样虽然能达到目的,但是是有问题的,主要有两点:

es 的标准每年都在变,现在的 stage-0 可能很快就 stage-2 了,那 preset 怎么维护,要不要跟着变,用户怎么知道这个 stage-x 都支持什么特性?只能转成 es5,那目标环境如果已经支持一些 es6 特性了,那这些转换和 polyfill 岂不是无用功?而且还增加了产物的体积。polyfill 手动引入,比较麻烦,有没有更好的方式

怎么解决 babel 6 的问题呢?babel 7 给出了答案。

我们关注一下 7.0 带来的变化(核心机制方面没有变化,插件,preset,解析转译生成这些都没有变化)

npm package 命名区分

babel6版本所下载的包都是类似这种形式的:babel-preset-*,babel-plugin-*

babel 7 所有的包都迁移到了 @babel 的 scope 下,把所有 babel-* 重命名为 @babel/*

preset 的变更:淘汰 preset-20xx ,删除preset-stage-x ,强推 preset-env

preset-env 默认会支持所有 es 标准的特性,如果没进入标准的,不再封装成 preset,需要手动指定 plugin-proposal-xxx。

不再支持低版本 node

babel 7开始不再支持 nodejs 0.10, 0.12, 4, 5 这四个版本,相当于要求 nodejs >= 6

不再支持,指的是在低版本 node 环境中不能使用 babel 转译代码,但 babel 转译后的代码依然能在这些环境上运行,这点不要混淆。

@babel/node 从 @babel/cli 中独立了

babel 7,要使用 @babel/node,必须单独安装,并添加到依赖中。

babel埋点插件

登录 · 语雀








 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/940477.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-17
下一篇 2022-05-17

发表评论

登录后才能评论

评论列表(0条)

保存