webpack配置解析es6语法

2,219 阅读9分钟

说明文章中的问答都选自极客时间 -- 《玩转webpack》程柳锋老师的留言回答

配置解析es6语法

1.在配置 解析es6语法前我们需要先了解什么是'babel'

什么是babel

1.我们的JavaScript每年都有新功能出现,但是使用JS的浏览器却并不是及时同步更新的。同时,
  我们的用户也不会经常更新浏览器版本。所以,如果我们需要使用一些JS新功能时,就必须将
  新功能的JS代码转换为大部分现代浏览器能运行的JS版本。也就是babel的主要作用了,主要将
  ES6+的JS代码转换为ES5代码。
  简单的说:'主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法'
2.所以Babel 到底能做什么?首先要弄清楚语法 和 api 的两个概念,在后续js新增的功能中其实改动
增加的也是这两个部分
    2.1.语法例如:'箭头函数''let/const','解构'
    2.2.api 也就是新标准引入的全局变量、部分原生对象新增的原型链上的方法例如:'Promise','includes'这些等
然而Babel帮我们解决的是'语法',至于这些'api'我们会采用垫片的形式来解决也就是'polyfill'
3.在使用'babel' 时候我们一般需要安装'@babel/core' '@babel/cli' '@babel/preset-env' '@babel/polyfill'
4.babel.config.json
@babel/core 是个什么
1.刚才已经分析过了'babel' 帮我们转换的是语法,一般这种转换使用'抽象语法树(AST)',在babel中也不例外
整个过程:
    1.1.解析(Parsing):将代码字符串解析成抽象语法树。
    1.2.转换(Transformation):对抽象语法树进行转换操作。
    1.3.生成(Code Generation): 根据变换后的抽象语法树再生成代码字符串。
    简单的说就是:'源代码 -> AST -> 转换过的AST -> 转换过的代码'
2.整个复杂的过程是'@babel/core' 来做当然这个包也是依赖这些包
 '@babel/parser、@babel/traverse、@babel/generator'
3.'@babel/core'主要的作用就是编译

注:关于'AST'东西后续会去看
@babel/preset-env
1.'@babel/core' 既然能帮我们转换这些语法,那每年都会出新的语法,他又是如何帮助转换的呢?
在之前我们需要安装各种预设例如
浏览器:
'babel-preset-es2015,babel-preset-es2016,babel-preset-es2017,babel-preset-latest'
 node:
'babel-preset-node5,babel-preset-es2015-node等'
通过名字也可以知道他们是对应不同的时期的es标准,但是每次都需要你动脑去安装不同时期的预设
不是一个较好的体验因此有'babel/preset-env'
2.所以'babel/preset-env'是一系列插件的集合,包含了我们在babel6中常用的es2015,es2016, es2017
等最新的语法转化插件,允许我们使用最新的js语法,比如 letconst,箭头函数等等,
但不包括stage-x阶段的插件。这样以后只要我们安装一个'babel/preset-env'就解决了大部分问题

babel-preset-env 官网的讲解1 官网的讲解2 Babel 7 升级实践

@babel/cli 是个什么
1.一个脚手架'是允许您从终端使用babel的工具',主要做的就是:
 '这将解析目录中的所有JavaScript文件src,应用我们告诉它的所有转换,并将每个文件输出到lib目录'

关于api 转换几种实现

1.下面是对api这种转化垫片几种实现理解
@babel/polyfill 是什么
1.'babel/polyfill'帮助我们做api转换,他又是如何帮忙转换的呢? 
@babel/polyfill 模块包括 core-js 和一个自定义的 regenerator runtime 模块,可以模拟完整的
 ES2015+ 环境(不包含第4阶段前的提议) 'corejs' 是一个给低版本的浏览器提供接口的库,
如 Promise, map, set 等,当安装.'babel/polyfill'自然会把'corejs' 作为一个依赖安装

安装指令:'npm install --save @babel/polyfill' 通过指令发现这不是一个开发依赖包
2.这样用也产生了问题,当我们在入口文件写上 "import 'babel-polyfill' "
  2.1 就会一次性全部导入,有时候你只是用了其中一小部分需要转换的实例方法/静态方法,
      导入了很大一个文件,其中很大一部分是没有必要的,增加文件体积,虽然可以按需引入,
      但是特别麻烦。
  2.2.为了添加例如es6提供的'Array.from 或 Object.assign 之类的静态方法',polyfill 将添加到全局范围
      这样的内置原型中(会对全局环境造成污染)
@babel/plugin-transform-runtime 和 @babel/runtime
1.既然'@babel/polyfill ' 有上面的两个缺点那可以通过什么方式来解决?
 首先安装下面两个包:    
    'npm install --save-dev @babel/plugin-transform-runtime'
    'npm install --save @babel/runtime'
2.通过安装指令也可以发现,'@babel/plugin-transform-runtime' 通常仅在开发时使用,
但是运行时最终代码需要依赖 '@babel/runtime',所以 '@babel/runtime' 必须要作为生产依赖被安装
现在我们 可以减少编译后代码的体积外,我们使用它还有一个好处,它可以为代码创建一个沙盒环境减少污染

官网对babel-plugin-transform-runtime说明

core js
1.由于自@babel/polyfill7.4.0 起已弃用,建议您core-js通过corejs选项直接添加和设置版本,也就是后来
觉得之前的方案又不爽了,在'babel'7.4.0后 决定通过直接安装' corejs' 一步到位得了,前面也可以发现
上面的api转换的方案不管这么样都需要' corejs',索性直接' corejs'得了
安装:
    'npm install core-js@3 --save' or 'npm install core-js@2 --save'
说明:'如果我们配置的 corejs 是 3 版本,那么不管是实例方法还是全局方法,都不会再污染全局环境'
2.现在我们在入口文件直接"import 'core-js'"
3.但这还没完事,我们还需要在'.babelrc'做如下配置
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry", // 关于这参数具体的看文章链接
        "corejs": 3 // 使用corejs 版本
      }
    ]
  ]
}

Babel 7.4.0开始我非要使用babel-polyfill那就这样用 关于.babelrc文件一些配置讲解 关于.babelrc文件官网说明

polyfill-service
1.根据浏览器缺失哪些特性来补全哪些特性,它能够根据浏览器的UA来判断当前浏览器缺失哪些特性,
进而进行补强,问题是有些浏览器修改了UA,所以部分情况也会有问题
2.这种方案'https://polyfill.io/v3/',通过引入cdn方式
关于浏览器版本

浏览器版本

一些参考的文章

关于抽象语法树

什么是babel,以及各个插件的区别

Babel 插件原理的理解与深入

Babel 是怎么工作的

Babel 7.1介绍 transform-runtime polyfill env

一文搞清楚前端 polyfill

Babel转ES6语法:babel-preset-env和babel-polyfill

配置一些使用

关于Babel你需要知道的那些事

  • 这个比较全

不容错过的 Babel7 知识 -- 推荐必读

在webpack 使用

1.首先遵循'babelrc' 使用配置,在根目录添加一个'.babelrc' 文件目录
2.在webpack 的'loader '配置模块也就是增加 'module 下 rules''babel-loader'使用声明
3.先安装'babel'
 npm i @babel/core @babel/preset-env babel-loader -D  
.babelrc 文件配置
1.'@babel/preset-env' 主要作用是对我们所使用的并且目标浏览器中缺失的功能进行代码转换和加载 polyfill,
在不进行任何配置的情况下,@babel/preset-env 所包含的插件将支持所有最新的JS特性(ES2015,ES2016等,不包含 stage 阶段),
将其转换成ES5代码。例如,如果你的代码中使用了仍在 stage 阶段,
那么只配置 @babel/preset-env,转换时会抛出错误,需要另外安装相应的插件。
2.'@babel/preset-react' 解析react jsx 语法,需要安装对应 '@babel/preset-react ' 当然是安装在开发环境中
1.包含两块内容,一个是 babel presets,另一个是 babel plugins数组。比如 .babelrc 文件:
{
    "presets": [
      "@babel/preset-env"
    ],
    "plugins": [
        "@babel/proposal-class-properties"
    ]
}

plugin 用来支持某个功能,presets 是多个 plugin 的集合
{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ]
}
webpack 的'loader '配置模块
1.无论是对ts 还是 react 还是语法转换为es5的形式,你要更改的是'.babelc'文件里面对应的配置和安装对应的'babelc的包'
 你在webpack 要做的就是在module 的rules 配置好 'babel-loader'相关的匹配规则和使用引入
const path = require('path');

module.exports = {
    mode: 'production',
    entry: {
        index: './src/index.js',
        sreach: './src/hellowWebpack.js'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    // 注意在这里配置的loader
    module: {
        rules: [{
            test: /\.js$/,
            use: 'babel-loader' // 配合babel 解析一些 ES6+的JS代码
        }]
    }
}
~~~js
##### 关于babel 一些疑问
~~~ js
1.babel可以编译箭头函数等语法,但是全局方法例如promise等方法如何编译成es5 ?
    答:'babel' 只转换新的JS语法,而不转换新的API,例如全局方法:MapSetPromise 这些是无法编译成 ES5的哈。
    需要通过 'babel-polyfill' ,进行 'babel-polyfill' 这个在升级版本中已经被替换换了

2.babel的作用是转换ES6语法,那么使用@babel/core和babel-loader就可以了,为什么还要使用@babel/preset-env这个呢?
    答:'babel-loader' 解析ES6的语法也是需要知道哪些语法需要解析,需要通过.babelrc进行配置,这个@babel/preset-env 
    就是告诉 'babel-loader' 要解析ES6的语法,其它的 react 语法可以通过其它的 babel preset 进行

3.如果用了ts,还需要Babel吗?
    答:不需要了,ts使用'ts-loader'即可,首先弄清Babel是用来转换语法到es5一般,ts会帮我们转换
        所以用了ts就不需要Babel,但是注意垫片polyfill 还是需要的
        https://www.zhihu.com/question/322722786
4.为什么我们vue项目没用安装'babel-polyfill'也可以用es6的新API比如Set Map?
    答:如果你不用'babel-polyfill',那么一些低版本的浏览器还没有MapSet这种数据结构的实现,就会报错了