Babel

Babel 可以干什么:

  • 语法转换
  • 通过 Polyfill 方式在目标环境中添加缺失的功能
  • 源码转换(codemods

项目中常用的Babel配置

首先,webpack 中 loader 的本质就是一个函数,接受我们的源代码作为入参同时返回新的内容。

我们日常使用的 babel 相关配置主要涉及以下三个相关插件:

  1. babel-loader:本质就是一个函数,我们匹配到对应的文件交给 babel-loader

  2. babel-core:babel-loader 是识别匹配文件和接受对应参数的函数。 babel 在编译代码过程中核心的库就是 @babel/core 这个库。他可以将我们的代码进行词法分析--语法分析--语义分析过程从而生成AST抽象语法树,从而对于"这棵树"的操作之后再通过编译称为新的代码。

  3. babel-preset-env:告诉 babel 需要以为什么样的规则进行代码转义。

PresetPlugin

Preset 就是一些 Plugin 组成的合集,可以将 Preset 理解成一些 Plugin 整合成的一个包。

例如,@babel/preset-env 是一个非常常用的 Preset,它根据目标环境和配置的浏览器列表,自动选择和加载所需的插件,使得开发者无需手动选择和配置大量的插件。

babel-preset-env

将高版本 JavaScript 代码进行转译,根据内置的规则转译成为低版本的JavaScript 代码

仅仅针对语法阶段的转译 ,比如转译箭头函数,const/let 语法。针对一些Api或者Es 6内置模块的 polyfillpreset-env 是无法进行转译的。

常见的 Plugin 其实大多数都集成在了 babel-preset-env 中。

@babel/preset-env 不会包含任何低于 Stage 3 的 JavaScript 语法提案 。如果需要兼容低于 Stage 3 阶段的语法则需要额外引入对应的 Plugin 进行兼容。

ECMAScript(简称 ES)是 JavaScript 的标准化版本,它的新特性通常会经过一个由 TC39(ECMA 技术委员会)管理的提案过程,分为五个阶段,分别是 Stage 0 到 Stage 4。这些阶段代表了新特性从最初的提议到最终成为标准的过程。 具体各个阶段的含义如下:

  1. Stage 0 - Strawman(草案):此阶段是为了提出初步想法而设立的,通常由个人或小组提出,而不是由 TC39 委员会批准的提案。这些提案可能只是一个想法的草图,并不具有实际应用性。
  2. Stage 1 - Proposal(提案):在这个阶段,提案已经详细说明了设计、语法和语义,并且经过了初步讨论。该阶段要求提供详细的说明文档,以及实现和用户反馈等。
  3. Stage 2 - Draft(草案):在这个阶段,提案已经完整地描述了其语法和语义,并且有了初步的实现。这意味着提案已经成为一个可供实际使用的草案。
  4. Stage 3 - Candidate(候选):在这个阶段,提案已经基本完成,所有方面都已经得到了充分的讨论和评审,并且已经有了至少一个实现。这意味着提案已经足够成熟,可以供开发者使用和提供反馈。
  5. Stage 4 - Finished(完成):在这个阶段,提案已经通过了所有的评审流程,并且已经被加入到了 ECMAScript 的标准中。这意味着该特性已经成为了 JavaScript 的一部分,并且可以在任何支持该版本标准的环境中使用。

因此,当说一个特性处于 Stage 3 时,意味着它已经相对成熟,具有可用性,并且很可能会最终成为 ECMAScript 标准的一部分。

babel-preset-react

将 React 中的 jsx 进行转译。

babel-preset-typescript

对于 TypeScript 代码,有两种方式去编译 TypeScript 代码成为JavaScript代码

  1. 使用 tsc 命令,结合 cli 命令行参数方式或者 tsconfig 配置文件进行编译 ts 代码。
  2. 使用 babel ,通过 babel-preset-typescript 代码进行编译 ts 代码。

Babel 的 polyfill

首先我们来理清楚这三个概念:

  1. 最新 ES 语法,比如:箭头函数,let/const
  2. 最新 ES Api ,比如 Promise
  3. 最新 ES 实例/静态方法,比如 String.prototype.include

babel-prest-env 仅仅只会转化最新的 es 语法 ,并不会转化对应的 Api 和实例方法,比如说 ES 6 中的 Array.from 静态方法。 babel 是不会转译这个方法的,如果想在低版本浏览器中识别并且运行 Array.from 方法达到我们的预期就需要额外引入 polyfill 进行在 Array 上添加实现这个方法。

整体而言就是,语法层面的转化 preset-env 完全可以胜任。但是一些内置方法模块,仅仅通过 preset-env 的语法转化是无法进行识别转化的 ,所以就需要一系列类似"垫片"的工具进行补充实现这部分内容的低版本代码实现。这就是所谓的 polyfill 的作用。

针对于 polyfill 方法的内容,babel 涉及如下:

  1. @babel/polyfill:(从 Babel 7.4.0 版本开始,这个软件包已经不建议使用了,建议直接包含 core-js/stable 。)通过往全局对象上添加属性以及直接修改内置对象的Prototype上添加方法实现 polyfill 。比如说我们需要支持String.prototype.include,在引入 babelPolyfill 这个包之后,它会在全局 String 的原型对象上添加 include 方法从而支持我们的Js Api。这种方式本质上是往全局对象/内置对象上挂载属性,所以这种方式难免会造成全局污染

    useBuiltIns 决定了如何在 preset-env 中使用 @babel/polyfill。

    js 复制代码
    {
        "presets": [
            ["@babel/preset-env", {
                "useBuiltIns": false
            }]
        ]
    }

    他有三个可选值:

    1. false:默认值。它表示仅仅会转化最新的ES语法,并不会转化任何Api和方法。
    2. entry :需要我们在项目入口文件中手动引入一次core-js: import "core-js/stable";,它会根据我们配置的浏览器兼容性列表(browserList)然后全量引入不兼容的polyfill 。也就是说比如我们代码中仅仅使用了Array.from这个方法。但是polyfill并不仅仅会引入Array.from,同时也会引入Promise、Array.prototype.include等其他并未使用到的方法。这就会造成包中引入的体积太大了
    3. usage :会根据配置的浏览器兼容,以及代码中 使用到的Api 进行引入polyfill按需添加 。如果我们存在很多个模块,那么无疑会多出很多冗余代码(import语法)
  2. @babel/runtime:@babel/polyfill是存在污染全局变量的副作用,在实现polyfill时Babel还提供了另外一种方式去让我们实现这功能,那就是@babel/runtime。

    1. 简单来讲,@babel/runtime更像是一种按需加载的解决方案,比如哪里需要使用到Promise,@babel/runtime就会在他的文件顶部添加import promise from 'babel-runtime/core-js/promise'

    2. preset-env的useBuintIns配置项,我们的polyfill是preset-env帮我们智能引入。而babel-runtime则会将引入方式由智能完全交由我们自己,我们需要什么自己引入什么。

    存在如下问题:

    • babel-runtime无法做到智能化分析,需要我们手动引入。
    • babel-runtime编译过程中会重复生成冗余代码(一些工具函数)。
  3. @babel/plugin-transform-runtime:和run-time配合使用,解决上述我们提到的run-time存在的问题而提出的插件。

    • @babel/plugin-transform-runtime插件会智能化的分析我们的项目中所使用到需要转译的js代码,从而实现模块化从babel-runtime中引入所需的polyfill实现。
    • @babel/plugin-transform-runtime插件提供了一个helpers参数。开启后可以将上边提到编译阶段重复的工具函数代码转化称为require语句。此时,这些工具函数就不会重复的出现在使用中的模块中了。

两者的选择:

  • 如果项目对打包体积要求很高,或者想要避免全局污染,推荐使用 @babel/plugin-transform-runtime + @babel/runtime。
  • 如果想要快速方便地启用所有可能需要的 polyfills,并且不需要担心打包体积,可以使用 useBuiltIns + @babel/polyfill。

参考

juejin.cn/post/702523...

相关推荐
xiao-xiang2 分钟前
jenkins-通过api获取所有job及最新build信息
前端·servlet·jenkins
C语言魔术师18 分钟前
【小游戏篇】三子棋游戏
前端·算法·游戏
匹马夕阳1 小时前
Vue 3中导航守卫(Navigation Guard)结合Axios实现token认证机制
前端·javascript·vue.js
你熬夜了吗?2 小时前
日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件
前端·vue.js·信息可视化
桂月二二8 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062069 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb9 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角9 小时前
CSS 颜色
前端·css
九酒9 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔10 小时前
HTML5 新表单属性详解
前端·html·html5