babel做兼容处理 到底怎么使用?

news2025/7/5 13:28:27

1.背景

  • 日常项目开发中总是避免不了对低版本浏览器做一些兼容处理,最常见的手段就是结合编译工具使用babel来处理一些语法的兼容,但是每次使用的时候其实Babel的配置和使用到的相关库总是云里雾里,网上的各种推荐方案眼花缭乱不知道到底应该怎么选择。
  • 今天抱着学习的心态,和大家一起好好梳理一下

2.准备工作

  • 考虑到大多数项目都在使用webpack,今天就用webpack来学习验证babel
  • 目录结构
    在这里插入图片描述
  • 简单的配置
const path = require('path');
module.exports = {
  entry: './src/main',
  mode: 'development',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/,
      }
    ]
  }
};
  • 需要用的的依赖,先混个眼熟 core-jsregenerator-runtime@babel/preset-env@babel/runtime@babel/runtime-corejs3@babel/plugin-transform-runtime

3.配置bable

我们就以promise为例,看一下打包后补丁的效果

  • main.js
const a = 10;
const b = 11;

let add = (a, b) => {
  return Promise.resolve(a + b);
}
add(a, b);
  • 没有使用babel时,可以看到没有引入任何其他模块,语法也没有做转换
  • bundle.js的结果
    在这里插入图片描述
  • 包体积
    在这里插入图片描述

3.1 直接引入polyfill

  • 安装core-js regenerator-runtime
  • 配置babel.config,js
module.exports = {
  presets: [
    ["@babel/preset-env", {
      useBuiltIns: false // or "entry" "usage" false 
    }]
  ]
}
  • main.js中引入对应补丁
import "core-js/stable";
import "regenerator-runtime/runtime";
const a = 10;
const b = 11;

let add = (a, b) => {
  return Promise.resolve(a + b);
}
add(a, b);
  • bundle.js,可以看到是存在promise的polyfill的
  • 在这里插入图片描述
  • 因为是全局引入包体积明显变大,948k
    在这里插入图片描述
  • 可能有的同学看到过直接引入@babel/polyfill
  • 其实是在 babel7.4.0 之前,可以直接安装 @babel/polyfill 来转换 API,但是在 7.4.0 之后,就会提示让我们分开引入 core-js/stableregenerator-runtime/runtime了。
  • core-js:是整个 core-js 的核心,提供了基础的垫片能力,但是直接使用 core-js 会污染全局命名空间和对象原型
  • regenerator-runtime/runtime:主要用来兼容async generator 等语法

3.2 @babel/preset-env按需引入

  • 首先呢我们先看一下@babel/preset-env有哪些选项

targets

  • targets 可以指定项目的运行环境。如果没有配置 targets,那么 @babel/preset-env 会接着寻找项目中的 browserslist 配置,browserslist 配置只会控制语法的目标环境。如果 targetsbrowserslist 都没有,那么 @babel/preset-env 就会全量处理语法和 API。
  • browserslist 具体配置

useBuiltIns

  • useBuiltIns 决定了 @babel/preset-env 该如何处理 polyfill。可选值有:“usage” 、“entry” 、和 false, 默认为 false。
    • false,polyfill 就不会被按需处理会被全部引入。
    • entry,我们配置了targets,entry就是针对目标环境的全部,所以是对配置目标环境引入的所有 polyfill 扩展包,会自动将import “core-js/stable” 和 import “regenerator-runtime/runtime” 转换为目标环境的按需引入。
    • usage,则不需要手动导入 polyfill,babel 检测出此配置会自动进行 polyfill 的引入。

3.2.1 全局引入

  • 安装 @babel/preset-env
  • 配置babel.config.js 首先看一下全局引入
module.exports = {
  presets: [
    ["@babel/preset-env", {
      targets: {
        browsers: [
          'Android >= 4.4',
          'iOS >= 9.0',
        ],
      },
      useBuiltIns: "entry", // or "entry" "usage"
      corejs: 3
    }]
  ]
}
  • main.js 全局引入,不然useBuiltIns: "entry"也不生效
import "core-js/stable";
import "regenerator-runtime/runtime";
const a = 10;
const b = 11;

let add = (a, b) => {
  return Promise.resolve(a + b);
}
add(a, b);
  • 我们可以和之前的全局引入打包结果对比一下948k=>822k
    在这里插入图片描述

3.2.2 按需引入

  • 接下来我们看一下按需引入
  • 修改babel.config.js 使用 usage
module.exports = {
  presets: [
    ["@babel/preset-env", {
      targets: {
        browsers: [
          'Android >= 4.4',
          'iOS >= 9.0',
        ],
      },
      useBuiltIns: "usage", // or "entry" "usage"
      corejs: 3
    }]
  ]
}
  • main.js中不需要全局引入polyfiill
const a = 10;
const b = 11;

let add = (a, b) => {
  return Promise.resolve(a + b);
}
add(a, b);
  • 打包结果,包体积又从822k => 154k,明显减少
    在这里插入图片描述

3.3 @babel/plugin-transform-runtime进行优化

@babel/plugin-transform-runtime这个插件呢主要有两个作用

  1. 自动移除语法转换后内联的辅助函数,替换为@babel/runtime/helpers里的辅助函数,以节省代码体积
  2. 就是对 API 进行转换的时候,避免污染全局变量。

下面我们针对这两个功能具体看看效果

  1. 安装 @babel/plugin-transform-runtime@babel/runtime@babel/runtime-corejs3

3.3.1 优化体积

  1. 为了方便看效果,我们新建三个文件
    在这里插入图片描述
  • 三个文件都相同,就默认导出一个类
class A {
  a = 1
}
export default A;
  • 在入口文件main.js中引入
import A from './a.js';
import B from './b.js';
import C from './c.js';

const a = 10;
const b = 11;

let add = (a, b) => {
  console.log(A, B, C);
  return Promise.resolve(a + b);
}
add(a, b);
  • 打包一下看看大小,没有配置插件时270k
    在这里插入图片描述
  • 配置 babel.config.js 使用@babel/plugin-transform-runtime
module.exports = {
  presets: [
    ["@babel/preset-env", {
      targets: {
        browsers: [
          'Android >= 4.4',
          'iOS >= 9.0',
        ],
      },
      useBuiltIns: "usage", // or "entry"
      corejs: 3
    }]
  ],
  plugins: [
    ['@babel/plugin-transform-runtime']
  ]
}
  • 再次打包可以看到,270k => 166k,体积明显减小
    在这里插入图片描述
  • 怎么理解这个插件减小体积的功能呢?
  • Babel 在转译时,有时候会使用一些辅助的函数来帮忙,比如我们需要转译 class 类,就会在文件中注入_classCallCheck 这个函数来辅助转换,如果每个文件都有相同的语法,那每个文件都会注入相同的一份辅助函数;
  • 我们使用 @babel/plugin-transform-runtime 自动将需要引入的 helpers 函数替换为从 @babel/runtime 中的引用。
  • 那么配合webpack等打包工具,最终相同的引用只都公用一份,从而减小了体积。

3.3.2 避免全局污染

  • 开头说到@babel/plugin-transform-runtime 还有另一个关键的作用就是对 API 进行转换的时候,避免污染全局变量,但是看截图中引入的对应polyfill包还是从core-js中引用的,和没有使用插件时一样,似并没有改变。

  • 其实这个插件是有一些选项的,具体可以查看官网 https://babeljs.io/docs/en/babel-plugin-transform-runtime/#options

  • 我们上面的配置的默认选项是这样的

 ...
  // plugins: [
  //   ['@babel/plugin-transform-runtime']
  // ]
  plugins: [
    [
      '@babel/plugin-transform-runtime',
      {  // 默认配置
        helpers: true,
        corejs: false,
        regenerator: true,
        useESModules: false,
        absoluteRuntime: false
      }
    ]
  ]
}
  • 可以看到 corejs: false,这个参数就是用来设置是否做API转换以避免污染全局环境的,我们开启看看效果
  plugins: [
    ['@babel/plugin-transform-runtime', {
        "helpers": true,
        "corejs": 3 // 可选值为 2 3 false
    }]
  ]
  • 引入的polyfill的包由原来的core-js => core-js-pure @babel/runtime-cojs3
    在这里插入图片描述
  • 是怎么避免的全局污染呢?

core-js@3其实分为一下几个模块:

  • core-js:是整个 core-js 的核心,提供了基础的垫片能力,但是直接使用 core-js 会污染全局命名空间和对象原型;
  • core-js-pure:core-js-pure 提供了独立的命名空间,不污染全局变量;
  • core-js-compact:根据 Browserslist 维护了不同宿主环境、不同版本下对应需要支持特性的集合;
  • core-js-builder:结合 core-js-compact 以及 core-js,并利用 webpack 能力,根据需求打包出 core-js 的 core-js-bundle
  • 插件可以将 core-js 中 API 的 polyfill 直接修改原型改为从 @babel/runtime-corejs3中获取,避免了对全局变量和原型的污染;

  • 当开启了corejs之后呢,由于@babel/plugin-transform-runtime可以帮我们引入对应的polyfill,所以我们也可以不再使用@babel/preset-env中添加polyfill的能力了

  • 不过API转换主要是给开发JS库或npm包等的人用的,我们的前端工程一般仍然使用polyfill补齐API就可以了;

小小总结一下,一般项目开发就是使用@babel/plugin-transform-runtime默认配置 + @babel/preset-env 按需引入 就可以啦

如有不对的地方,请大家及时指出,避免影响其他同学;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/146704.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自定义DotNetCore 项目模板

在进行代码开发时候,各自的团队或者公司都会有服务自己要求的项目代码模板,再创建新的项目时,都需要按照模板规范进行定义,NET支持自定义项目模板,这样在进行项目创建时就会高效很多。 官方参考文档:dotne…

软测复习01:软件测试概述

文章目录软件测试的目的软件测试的定义软件测试与软件开发软件测试发展软件测试的目的 基于不同的立场,存在着两种完全不同的测试目的 从用户的角度出发,希望通过软件测试暴露软件中隐藏的错误和缺陷,以考虑是否可接受该产品。从软件开发者的…

Java当中的定时器

目录 一、什么是定时器 二、Java当中的定时器 ①schedule()方法: ②TimerTask ​编辑 ③delay 三、实现一个定时器 前提条件: 代码实现: ①确定一个“任务”(MyTask)的描述: ②schedule方法: ③需要一个计时器 属性…

MAT-内存泄漏工具使用

目录 一、MAT简介 1.1 MAT介绍 1.2 MAT工具的下载安装 二、使用MAT基本流程 2.1 获取HPROF文件 2.2 MAT主界面介绍 2.3 MAT中的概念介绍 2.3.1 Shallow heap 2.3.2 Retained Heap 2.3.3 GC Root 2.4 MAT中的一些常用的视图 2.4.1 Thread OvewView 2.4.2 Group 2.…

复杂工况下少样本轴承故障诊断的元学习

摘要:近年来,基于深度学习的轴承故障诊断得到了较为系统的研究。但是,这些方法中的大多数的成功在很大程度上依赖于大量的标记数据,而这些标记数据在实际生产环境中并不总是可用的。如何在有限的数据条件下训练出鲁棒的轴承故障诊…

线程状态到底是5种还是六种?傻傻分不清楚

目录 从操作系统层面上描述线程状态 从javaAPI层面上理解线程的6种状态 线程的状态转换. NEW --> RUNNABLE 1.RUNNABLE <--> WAITING 2.RUNNABLE <--> WAITING 3.RUNNABLE <--> WAITING 1.RUNNABLE <--> TIMED_WAITING 2.RUNNABLE <--&…

开源天气时钟项目删减和更新

开源天气时钟项目删减和更新&#x1f4cc;原项目开源地址&#xff1a;https://gitee.com/liuzewen/ESP8266-SSD1306-Watch-mini ✨本文只针对Arduino IDE平台代码进行删减和更新。 &#x1f4fa;按键菜单功能 &#x1f33c;天气时钟功能整体架构描述 代码中所使用的库&…

【MySQL】十,SQL执行流程

MySQL中的SQL执行流程 MySQL的查询流程 查询缓存 Server 如果在查询缓存中发现了这条 SQL 语句&#xff0c;就会直接将结果返回给客户端 如果没有&#xff0c;就进入到解析阶段&#xff08;MySQL 8.0 已经废弃了查询缓存功能&#xff09;。 解析器 在解析器中对 SQL 语句进行…

36、基于STM32的电子闹钟(DS1302)

编号&#xff1a;36 基于STM32的电子闹钟&#xff08;DS1302&#xff09; 功能描述&#xff1a; 本设计由STM32单片机液晶1602按键DS1302时钟模块声光报警模组成。 1、采用STM32F103最小系统。 2、利用DS1302芯片提供时钟信号 3、液晶1602实时显示年月日、时分秒、星期等信息…

java线程池原理

背景&#xff1a;为什么需要线程池java中的线程池是运用场景最多的并发框架&#xff0c;几乎所有需要异步或并发执行任务的程序都可以使用线程池。在开发过程中&#xff0c;合理的使用线程池能够带来3个好处。降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消…

(1分钟了解)SLAM的七大问题:地图表示、信息感知、数据关联、定位与构图、回环检测、深度、绑架

编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;SLAM问题也被称为是CML问题。编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09;编辑切换为居中添加图片注释&#xff0c;不超过 140 字&#xff08;可选&…

(JMLR-2019)NAS综述鼻祖-神经架构搜索:一项调查

神经架构搜索&#xff1a;一项调查 paper题目&#xff1a;Neural Architecture Search: A Survey paper是博世人工智能中心发表在JMLR 2019的工作 paper链接&#xff1a;地址 Abstract 过去几年&#xff0c;深度学习在图像识别、语音识别和机器翻译等各种任务上取得了显着进步…

【C++】stl---vector的模拟实现(超级详细,万字详解)

文章目录前言vector的成员属性构造函数size函数cacpcity函数begin和end函数reserve函数insert函数push_back函数[]操作符重载析构函数拷贝构造函数赋值操作符重载erase函数pop_back反向迭代器反向迭代器模板反向迭代器的构造函数运算符重载- -运算符重载*引用操作符重载&#x…

Spring AOP 企业级应用 - 统一功能处理

1.统一用户登录权限效验统一用户登录权限效验使用传统的 AOP 能否解决问题呢 ? Component Aspect // 标识当前类为一个切面 public class LoginAOP {// 定义切点 (拦截的规则) - 拦截 UserController 中的所有方法Pointcut("execution(* com.example.demo.controller.Tes…

React Hooks 基础、实现、原理

React Hooks 基础、实现、原理题外话为什么要有Hooks&#xff1f;但是Class Component 的用法也有缺陷&#xff1a;1.组件复用变的困难2.JavaScript本身的缺陷函数式React HooksuseStateuseEffectuseCallback、useMemouseReducer最后题外话 2023了&#xff0c;新年快乐&#x…

【javascript】DOM 案例

点击查看密码 &#xff1a;就是把type等于password改为text即可&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><…

电力系统强大的Gurobi 求解器的学习(PythonMatlab)

到底有多强大&#xff0c;看看就知道&#xff0c;必须&#x1f44d;&#x1f44d;&#x1f44d;&#xff1a; 目录 1 概述 2 算例理解【Python】 2.1 算例1——详细入门 2.2 算例2——一般线性规划问题 2.3 算例3——非凸问题 3 算例升级【Matlab】 3.1 模型 3.2 电力系统…

Python2.x 与 3​​.x 版本到底有啥区别?

嗨害大家好鸭&#xff01;我是小熊猫~ 今天给大家带来一点小干货~ 很多人对于python的版本有些许疑问&#xff0c; 今天就来给大家说说看~ Python学习资料电子书点击此处跳转文末名片 Python 的 3​​.0 版本&#xff0c;常被称为 Python 3000&#xff0c;或简称 Py3k。 相对…

Mybatis-Plus“读-批量写-读”数据不一致的问题分享

在日常开发过程中&#xff0c;时常会遇到一个如下场景&#xff1a; 根据条件x&#xff0c;读取表A&#xff0c;得到多行数据&#xff1b;遍历读取到的数据&#xff0c;对条件x以外的字段进行修改&#xff0c;并进行保存&#xff1b;&#xff08;重点&#xff09;修改后&#x…

基础算法(七)——离散化

离散化 介绍 这里的离散化&#xff0c;特指整数的、保序的离散化 有些题目可能需要以数据作为下标来操作&#xff0c;但题目给出的数据的值比较大&#xff0c;但是数据个数比较小。此时就需要将数据映射到和数据个数数量级相同的区间&#xff0c;这就是离散化&#xff0c;即…