来会会babel这个重要且神奇的工具

babel 在前端工程化开发中发挥着至关重要的作用,它能将较高级的语法转成浏览器可识别的代码,无论中 es6 中 const 、promise 还是 React、TypeScript。

以下babel在线工具中左侧输入代码,右侧为编译后的结果,设置需要浏览器兼容的版本后,可以看到 "const" 编译成 "var","箭头函数" 编译成 "普通函数"。

1_babel网页编译.png

命令行使用

babel 和之前说到的 postcss 一样,可以通过命令行运行,解析文件夹或者文件。安装命令行工具所需要的依赖,npm install @babel/cli @babel/core -D

通过 npx 执行 .bin 目录下的指令,--out-file 表示输出文件地址,执行编译语句 npx babel src --out-file dist/main.js

2_babel-cli没有转化.png

可我们发现,目标文件和源文件代码是一样的,const 和 箭头函数都没有被编译。这是因为,我们没有设置编译代码所需要的插件。

上面代码中有标识符和箭头函数,需要【安装】并使用这些插件

  • 转换箭头函数:@babel/plugin-transform-arrow-functions
  • 转换const:@babel/plugin-transform-block-scoping

插件需要通过 --plugins 添加在命令后面

npx babel src --out-file dist/function.js --plugins=@babel/plugin-transform-arrow-functions
npx babel src --out-file dist/const.js --plugins=@babel/plugin-transform-block-scoping
npx babel src --out-file dist/plugins.js --plugins=@babel/plugin-transform-arrow-functions, @babel/plugin-transform-block-scoping

指定插件之后,babel 就会根据插件的功能再进行编译

3_plugins.png

但插件只能实现单一功能,我们代码里一般也不只有 const 、箭头函数这种语法,当需要处理的代码种类变多,可能就要罗列出非常多的插件来执行,所以 babel 提供了一种插件的集合,叫做"预设","预设"会根据我们所配置的需要兼容处理的逻辑来进行编译。

安装 @babel/preset-env 依赖后,在命令行使用 --presets 来替代 --plugins。npx babel src --out-file dist/presets.js --presets=@babel/preset-env

4_presets.png

babel-loader

除了在命令行中直接通过 babel 编译文件,更多情况下会在项目中对批量文件进行处理,这时候就需要用到 babel-loader 来进行处理啦。

安装依赖 npm install babel-loader @babel/core @babel/core是babel的核心

在webpack.config.js文件中配置对于js的处理规则,如果对配置不清楚可以参考 webpack初体验loader配置方式,这里和在命令行中执行一样,需要配置"插件"或者"预设"。

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "./bundle.js",
    path: path.resolve(__dirname, "./dist"),
  },
  mode: "development",
  devtool: "source-map",
  module: {
    rules: [
      {
        test: /\.js/,
        exclude: /node_modules/,
        use: [
          {
            loader: "babel-loader",
            options: {
              // "插件"是这样配置,这里直接使用"预设"
              // plugins: [
              //   "@babel/plugin-transform-arrow-functions",
              //   "@babel/plugin-transform-block-scoping",
              // ],
              presets: ["@babel/preset-env"],
            },
          },
        ],
      },
    ],
  },
};

这样 babel 就会把代码编译成我们所需要的兼容要求

5_babel-loader.png

这里我们没有设置到底需要对什么样的浏览器进行兼容,使用的就是browserslist默认配置,browserslist作用及详细介绍

有两种方式可以设置babel兼容性处理的规则

  • browserslist:设置的兼容规则对css和js都通用,可配置在 .browserslist 或 package.json 文件中
  • targets:webpack.config.js 中配置在 loader 的options里

以上两种方式都可以配置,但更建议使用 browserslist,因为 css 和 js 需要兼容的浏览器版本一般来说是一致的,使用 browserslist 只需要配置一套规则即可。

比如我们设置 兼容谷歌浏览器版本99

// package.json
"browserslist": [
    "chrome 99"
]

// 配置在 webpack.config.js 中
use: [
  {
    loader: "babel-loader",
    options: {
      presets: [
        [
          "@babel/preset-env",
          {
            targets: ["chrome 99"],
          },
        ],
      ],
    },
  },
],

因为 chrome 99 是最新的浏览器版本,对于高级的js语法都能够支持,所以不需要将es6编译成es5的语法。

6_只兼容chrome99.png

babel 处理文件不止在 js 中需要,如果是 react 项目的话,还需要支持 jsx 文件、可能还存在 ts 文件,所以可以将 babel 配置信息放到一个单独的文件中,达到共享的目的。

// webpack.config.js 
rules: [
    {
      test: /\.js/,
      exclude: /node_modules/,
      use: [
        {
          loader: "babel-loader",
        },
      ],
    },
],

// babel.config.js
module.exports = {
  presets: ["@babel/preset-env"],
};

polyfill

以上 babel 可以对于一些 js 语法进行处理,但有些新特性比如 promise 在默认情况下不会被处理,这样不能被低版本浏览器所识别。

7_无polyfill.png

那么我们需要借助"polyfill"来打补丁,对某些特定的语法做处理,这样编译后的代码中就能包含这些新特性。

  • babel 7.4 以前,通过 @babel/polyfill
  • babel 7.4 以后,通过 core-js regenerator-runtime

这里使用的 babel 版本是7.17,所以使用第二种方式,安装依赖 npm install core-js regenerator-runtime @babel/runtime-corejs3,在 babel.config.js 中给 preset 配置 polyfill 相关的属性

  • useBuiltIns:规定以什么方式来使用 polyfill
    • false:不使用 polyfill,不用配置 corejs
    • usage:自动检测源代码所需要使用的 polyfill,需配置corejs
    • entry:导入所有 polyfill,文件体积很大,需配置corejs,以及在入口文件中引入 core-js 与 regenerator-runtime
  • corejs:所使用的 corejs 版本
// babel.config.js
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        useBuiltIns: "entry",
        corejs: 3,
      },
    ],
  ],
};

// 入口文件
import "core-js/stable";
import "regenerator-runtime/runtime";

使用所有的 polyfill ,编译后的代码行数达到了一万七,里面包括很多新特性的实现

8_有polyfill.png

对React的支持

react 使用的是 jsx 语法,babel 可以直接对其处理,与 js 文件的处理方式一样,可以选择使用"插件"或者插件的集合"预设"。

插件

  • @babel/plugin-syntax-jsx
  • @babel/plugin-transform-react-jsx
  • @babel/plugin-transform-react-display-name

预设

  • @babel/preset-react
// babel.config.js
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        useBuiltIns: "entry",
        corejs: 3,
      },
    ],
    ["@babel/preset-react"],
  ],
};

react 代码被处理且编译成功,可以在浏览器上看到渲染的页面效果

9_对react的处理.png

处理TypeScript文件

在项目中处理 ts 文件有两种方式

  • ts-loader:将ts文件编译成js文件,有类型检测,但没有polyfill
  • babel-loader:有polyfill,没有类型检测,代码错误不会提示

首先来看 ts-loader 处理的情况,安装 ts-loader,ts-loader 依赖于 typescript 这个工具,npm install ts-loader typscript -D

在 webpack.config.js 配置 ts-loader 处理 ts 文件

module: {
  rules: [
    {
      test: /\.ts$/,
      exclude: /node_modules/,
      use: [
        {
          loader: "ts-loader",
        },
      ],
    },
  ],
},

可以看到,ts 代码已经被完全编译成了 js 代码,但是 Promise 是没有被处理的

10_ts-loader.png

换成 babel-loader 来处理,和 react 、js 一样,可以选择"插件"或者插件的集合"预设"。

  • 插件 @babel/plugin-transform-typescript
  • 预设 @babel/preset-typescript

将webpack.config.js 中的 ts-loader 替换成 babel-loader,以及在 babel.config.js 中进行配置。

// babel.config.js
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        useBuiltIns: "usage",
        corejs: 3,
      },
    ],
    ["@babel/preset-typescript"],
  ],
};

这种情况下,编译后文件就增加了 polyfill 的处理,这里 useBuiltIns 使用的是 usage,比 entry 这种模式下代码量要少一些。

11_babel-loader处理ts文件.png

从 polyfill 的角度来说,babel-loader 处理 ts 文件会更好,毕竟我们写的代码可能会有新特性和兼容性要求,但 babel-loader 存在的问题是无法进行错误类型检测,也就是检测不到代码出错,仍然会编译通过。

12_babel-loader与ts-loader对比.png

但我们是希望能够在开发阶段尽早的发现错误,这样就能避免测试阶段或者发布线上存在问题,在这里可以配合编译的命令来解决这个问题。

tsc 就是 typescript 工具的命令行语法,执行 npm run build通过 tsc 来检测代码是否正确,正确时才使用 webpack 编译,或者执行 npm run type-check-watch实时检测ts代码是否正确

// package.json
"scripts": {
    "build": "npm run type-check && webpack",
    "type-check": "npx tsc --noEmit",
    "type-check-watch": "npx tsc --noEmit --watch"
},

当代码中存在错误语法时,会直接报错。

13_type-check.png

这样就可以对ts文件达到类型错误的检测以及polyfill的效果了。

以上关于 babel-loader 处理 js、react、ts 文件,以及对于新特性的 polyfill,设置浏览器兼容版本,babel 配置文件 都非常的重要, 更多有关webpack的内容可以参考我其它的博文,持续更新中~

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

推荐阅读更多精彩内容