关于Babel,包你入门

一、 关于Babel

Babel 是一个JavaScript编译器

Babel 主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。

babel 有3种使用方式: 命令行(cli);构建工具的插件 (webpack 的 @babel/loader);单体文件 (standalone script)

3种使用方式只是入口不同,其核心都相同, 即包括3个步骤:

babel 总共分为3个阶段:解析,转换,生成。

  • 解析阶段: @babel/parser 将源码解析成AST
  • 转换阶段: @babel/core本身不具有任何转化功能,它把转化的功能都分解到一个个 plugin 里面
  • 生成阶段:@babel/generator将转好的AST重新生成代码

使用babel工具可以在3处配置: .babelrc/.babelrc.js 、package.json 的 babel 、babel.config.js

常说的 plugins & presets 的配置 就是 使用babel时主要的配置参数,如下:
cli工具中的参数.png

另外需要注意的是: babel 转换只能处理语法,不能处理新增的API。对于API的处理需要使用polyfill。

二、Plugins

babel 本身不具有任何转化功能,它把转化的功能都分解到一个个 plugin 里面。因此当我们不配置任何插件时,经过 babel 的代码和输入是相同的:

没有安装plugin时使用babel编译.png

一个插件一般支持一个语法的转化(插件是小型的 JavaScript 程序), 如添加插件@babel/plugin-transform-arrow-functions, 然后使用@babel/cli 编译:

npm install --save-dev @babel/plugin-transform-arrow-functions
npx babel src --out-dir dir --plugins=@babel/plugin-transform-arrow-functions
安装插件后的编译.png

一个插件支持一个语法。对于一套规范(比如 es2015 )包含大概十几二十个转译插件。如果每次要开发者一个个添加并安装,配置文件很长不说,npm install 的时间也会很长,更不谈我们可能还要同时使用其他规范。 所以 就有了插件套餐preset。

各规范下的插件列表: https://www.babeljs.cn/docs/plugins-list

三、Presets

安装@babel/preset-env, 使用@babel/cli 编译:

npm install --save-dev @babel/preset-env
npx babel src --out-dir dir --presets=@babel/env
presets进行编译.png

官方提供的Presets包:

  • @babel/preset-env for compiling ES2015+ syntax
  • @babel/preset-typescript for TypeScript
  • @babel/preset-react for React
  • @babel/preset-flow for Flow

其中最重要的需要关注的是 @babel/preset-env

四、Polyfill

babel 默认只转换 js 语法,而不转换新的 API; 对于新API 需使用Polyfill
用法1: 在所有代码运行之前增加 require(‘babel-polyfill’)
用法2: webpack.config.js 中将 @babel/polyfill 作为第一个 entry
注意:必须把 @babel/polyfill 作为 dependencies 而不是 devDependencies

使用@babel/polyfill 存在的问题:
1、@babel/polyfill 会导致打出来的包非常大,因为@babel/polyfill 是一个整体,把所有方法都加到原型链上。这个问题可以通过单独使用 core-js 的某个类库来解决,core-js 都是分开的。
2、@babel/polyfill 会污染全局变量,给很多类的原型链上都作了修改

babel7 后推荐使用 core-js/stable 和 regenerator-runtime/runtime

image.png

或者使用@babel/preset-env 中的useBuiltIns 配置

五、最重要的Preset @babel/preset-env

preset-env配置:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ]
  ]
}
  • module:用来设置是否把ES6的模块化语法改成其它模块化语法,默认为 auto,也就是会将ESM转为CJS。项目配置设置module为false也就是仍使用ESM,这样在webpack打包时可以使用 tree-shaking 去除无用代码减小包体积。

  • useBuiltIns:该配置项的值有 entry、usage、false。该配置主要和polyfill的行为相关。

  1. 值为false。preset-env不做额外处理,需要在入口文件引入 @babel/polyfill(全量)

  2. 值为entry。在入口文件引入 @babel/polyfill,转码时会根据 browerlist 引入polyfill。
    image.png

    由于 @babel/polyfill 推荐使用 core-js/stable 和 regenerator-runtime/runtime 替换,所以会有提示。替换为core-js后 如下:
    替换为core-js.png
  3. 值为usage。不用再显示引入 polyfill文件,转码时会根据 browerlist 和 编写的代码按需引入polyfill。


    image.png

    使用usage 时,不需要再引入 @babel/polyfill or core-js。 如下:
    直接使用usage.png

六、其他重要的包

  • @babel/cli: 命令行中使用, 如上面的使用方式

  • @babel/node : 命令行中直接执行+转译node文件,@babel/node = @babel/register + @babel/polyfill。 即 可以直接 @babel/node xxx.js, 如图所示:
    i@babel/node.png
  • @babel/register : 用法: require("@babel/register"); node 后续运行时所需要 require 进来的扩展名为 .es6、.es、.jsx、 .mjs 和 .js 的文件将由 Babel 自动转换。实时转码,所以 只适合在开发环境使用。

  • @babel/runtime
    语法转换时, 创建了helper函数。而在实际项目中我们的js文件很多,在语法转换过程中每个文件都会创建很多这种helper函数,这样会导致最终生成的包体积十分臃肿。


    image.png

这个时候 @babel/runtime 上场了,涉及到语法转换的helper函数都打包到 @babel/runtime 中,所以在语法转换的时候不用重复创建,只要引入 @babel/runtime 内的模块就可以了。

但是打包的文件那么多,总不可能每个都手动修改吧。 这时候就需要@babel/plugin-transform-runtime 了。

运行环境使用, 放在 dependencies中 而不是devDe..

  • @babel/plugin-transform-runtime
    @babel/plugin-transform-runtime 这个包的作用就是移除语法转换生成的helper函数,然后使用 @babel/runtime 中的辅助函数来替换。这样就避免了我们手动替换也减小了包的体积。


    image.png
  • @babel/loader
    与webpack等构建工具交互,可在webpack中配置,优先级最高

  • @babel/parser
    原babel 解析语法的内核 babylon

  • @babel/core
    babel 核心功能, 执行下面代码:

var babelCore = require("@babel/core");
var sourceCode = `let fn = (num) => num + 2`;

var options = {
  //是否生成解析的代码
  code: true,
  //是否生成抽象语法树
  ast: true,
  //是否生成sourceMap
  sourceMaps: true,
  plugins: [],
  presets: [],
};

babelCore.transform(sourceCode, options, function (err, result) {
  console.log(sourceCode);
  console.log(result.code);
  console.log(result.map);
  console.log(result.ast);
});

结果:
image.png

七、思维导图

我将上面的思路整理成了思维导图,方便记忆。 自行取用。


Babel.jpg

参考文档:

1、 一口(很长的)气了解 babel
2、一文彻底读懂Babel

hi~~ 学废了吗~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容