Webpack学习笔记——js兼容性

1.babel的安装与使用

babel简介

babel一词来自于希伯来语,直译为巴别塔,巴别塔象征的统一的国度、统一的语言。

而今天的JS世界缺少一座巴别塔,不同版本的浏览器能识别的ES标准并不相同,就导致了开发者面对不同版本的浏览器要使用不同的语言,和古巴比伦一样,前端开发也面临着这样的困境。

babel的出现,就是用于解决这样的问题,它是一个编译器,可以把不同标准书写的语言,编译为统一的、能被各种浏览器识别的语言。
Webpack学习笔记——js兼容性_第1张图片
由于语言的转换工作灵活多样,babel的做法和postcss、webpack差不多,它本身仅提供一些分析功能,真正的转换需要依托于插件完成。
Webpack学习笔记——js兼容性_第2张图片

babel的安装

babel可以和构建工具联合使用,也可以独立使用

如果要独立的使用babel,需要安装下面两个库:

  • @babel/corebabel核心库,提供了编译所需的所有api
  • @babel/cli提供一个命令行工具,调用核心库的api完成编译
npm i -D @babel/core @babel/cli

babel的使用

@babel/cli的使用极其简单

它提供了一个命令babel

# 按文件编译
babel 要编译的文件  -o  编辑结果文件

# 按目录编译
babel 要编译的整个目录 -d  编译结果放置的目录

babel的配置

可以看到,babel本身没有做任何事情,真正的编译要依托于babel插件babel预设来完成

babel 预设和 postcss 预设含义一样,是多个插件的集合体,用于解决一系列常见的兼容问题

如何告诉babel要使用哪些插件或预设呢?需要通过一个配置文件.babelrc

// .babelrc 文件配置
{
    "presets": [],
    "plugins": []
}

2.babel预设

babel有多种预设,最常见的预设是@babel/preset-env ;安装: npm i -D @babel/preset-env

@babel/preset-env可以让你使用最新的JS语法,而无需针对每种语法转换设置具体的插件。

通常会配合两个库core-jsregenerator-runtime(下面有说明)

了解一下:在之前是用的@babel/polyfill这个库,不过它已过时了,目前被 core-jsgenerator-runtime 所取代

配置

// .babelrc 文件配置
{
    "presets": [
        "@babel/preset-env"
    ]
}

兼容的浏览器

@babel/preset-env需要根据兼容的浏览器范围来确定如何编译,和postcss一样,可以使用文件.browserslistrc描述浏览器的兼容范围

// .browserslistrc 文件配置
last 3 version
> 1%
not ie <= 8

自身的配置

postcss-preset-env一样,@babel/preset-env自身也有一些配置

具体的配置见:https://www.babeljs.cn/docs/babel-preset-env#options

配置方式是:

// .babelrc 文件配置
{
    "presets": [
        ["@babel/preset-env", {
            "配置项1": "配置值",
            "配置项2": "配置值",
            "配置项3": "配置值"
        }]
    ]
}

其中一个比较常见的配置项是usebuiltins,该配置的默认值是false

它有什么用呢?由于该预设仅转换新的语法,并不对新的API进行任何处理

例如:

new Promise(resolve => {
    resolve()
})

转换的结果为

new Promise(function (resolve) {
  resolve();
});

如果遇到没有Promise构造函数的旧版本浏览器,该代码就会报错

而配置usebuiltins可以在编译结果中注入这些新的API,它的值默认为false,表示不注入任何新的API,可以将其设置为usage,表示根据API的使用情况,按需导入API,使用的是core-js 这个第三方库,该库里边包含了新的API的具体实现;

安装:npm i core-js

https://www.npmjs.com/package/core-js

// .babelrc 文件配置
{
    "presets": [
        ["@babel/preset-env", {
            "useBuiltIns": "usage",
            "corejs": 3  // 告知使用的corejs的版本是3,之前默认使用的是2
        }]
    ]
}

还是上边那个例子:

new Promise(resolve => {
    resolve()
})

这下转换的结果为

"use strict";

require("core-js/modules/es6.promise");
require("core-js/modules/es6.object.to-string");
new Promise(function (resolve) {
  resolve();
});

这里有时还会有一些特殊的语法 例如 async await等,这样的语法就不好转换,因此还需要一个新的
库来处理,就需要 regenerator-runtime 来进行处理转换。

安装: npm i regenerator-runtime

https://www.npmjs.com/package/regenerator-runtime

3.babel插件

除了预设可以转换代码之外,插件也可以转换代码,它们的顺序是:

  • 插件在 Presets(预设) 前运行。
  • 插件的顺序从前往后排列。
  • Preset (预设)的顺序是颠倒的(从后往前)。

通常情况下,@babel/preset-env只转换那些已经形成正式标准的语法,对于某些处于早期阶段、还没有确定的语法不做转换。

如果要转换这些语法,就要单独使用插件

https://www.babeljs.cn/docs/plugins

下面随便列举一些插件

  • @babel/plugin-proposal-class-properties

    该插件可以让你在类中书写初始化字段

class A {
   a = 1;
   constructor(){
       this.b = 3;
   }
}
//.babelrc 文件配置
{
    "presets": [
        ["@babel/preset-env", {
            "useBuiltIns": "usage",
            "corejs": 3
        }]
    ],
    "plugins": [
       //"@babel/proposal-class-properties"
        ["@babel/proposal-class-properties", {  // 可配置参数
            "loose": true  // 配置参数,默认为false,表示生成的代码宽松一点,没有那么花里胡哨了(一般情况不需要配置)
        }],
    ]
}
  • @babel/plugin-proposal-function-bind

    该插件可以让你轻松的为某个方法绑定this

function Print() {
    console.log(this.loginId);
}

const obj = {
    loginId: "abc"
};

obj::Print(); //相当于:Print.call(obj); 
// 遗憾的是,目前vscode无法识别该语法,会在代码中报错,虽然并不会有什么实际性的危害,但是影响观感

//.babelrc 文件配置
{
    "presets": [
        ["@babel/preset-env", {
            "useBuiltIns": "usage",
            "corejs": 3
        }]
    ],
    "plugins": [
        ["@babel/proposal-class-properties", {
            "loose": true
        }],
        "@babel/proposal-function-bind",
    ]
}
  • @babel/plugin-proposal-optional-chaining

    访问深度嵌套的属性

    https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining

const obj = {
 foo: {
   bar: {
     baz: 42,
   },
 },
};

const baz = obj?.foo?.bar?.baz; // 42

const safe = obj?.qux?.baz; // undefined
//.babelrc 文件配置
{
    "presets": [
        ["@babel/preset-env", {
            "useBuiltIns": "usage",
            "corejs": 3
        }]
    ],
    "plugins": [
        ["@babel/proposal-class-properties", {
            "loose": true
        }],
        "@babel/proposal-function-bind",
        "@babel/proposal-optional-chaining",
    ]
}
  • babel-plugin-transform-remove-console

    该插件会移除源码中的控制台输出语句

console.log("foo");
console.error("bar");

编译后


  • @babel/plugin-transform-runtime

用于提供一些公共的API,这些API会帮助代码转换,需要配合@babel/runtime这个库

//.babelrc 文件配置
{
    "presets": [
        ["@babel/preset-env", {
            "useBuiltIns": "usage",
            "corejs": 3
        }]
    ],
    "plugins": [
        ["@babel/proposal-class-properties", {
            "loose": true
        }],
        "@babel/proposal-function-bind",
        "@babel/proposal-optional-chaining",
        "transform-remove-console",
        "@babel/transform-runtime"
    ]
}

4.在webpack中使用babel

babel-loader

https://www.babeljs.cn/setup#installation

以下是简单的基本配置:(具体配置上面都有说明)

// webpack.config.js 文件配置
module.exports = {
    mode: "development",
    devtool: "source-map",
    module: {
        rules: [
            { test: /\.js$/, use: "babel-loader" }
        ]
    }
}
// .babelrc 文件配置
{
    "presets": [
        ["@babel/preset-env", {
            "useBuiltIns": "usage",
            "corejs": 3
        }]
    ]
}

你可能感兴趣的:(笔记)