>[success] # babel -- 初步上手之各种配置@babel/preset-env ~~~ 1.babel 各种错综复杂的配置,经常让在开发阶段犯难,通过将各种常用的配置说明一遍来弄懂 实际开发 ~~~ >[info] ## @babel/preset-env ~~~ 1.'@babel/preset-env' 是预设是一系列插件的集合,包含了我们在babel6中常用es2015,es2016, es2017 等最新的语法转化插件,允许我们使用最新的js语法,比如 let,const,箭头函数等等, 但不包含低于 Stage 3 的 JavaScript 语法提案。这样以后只要我们安装一个'babel/preset-env'就 解决了大部分问题,简单的说,它是 'babel 一个预设'主要用来帮助我们对语法进行转换,会自动的 根据当前环境对js语法做转换。常用配置属性'targets' 'useBuiltIns' 'corejs' { "presets": [ [ "@babel/env" ] ] } ~~~ >[danger] ##### target -- 指定语法最低版本浏览器兼容 ~~~ 1.'targets'解决:随着低版本的浏览器逐步淘汰,一些新特性的语法在新浏览器已经支持,可能几年后大家已经 不在使用IE,如果一股脑的全部兼容打包的体积也会变大,是否有必要全部转换成'es5',我们更希望 他可以根据你所配置的浏览器的列表,自动的去加载当前浏览器所需要的插件,然后对es语法做 转换。 2.'解决方法': 可以通过配置文件指定语法最低版本浏览器兼容这里其实配合的是'Browserslist',Browserslist 的数据都是来自 'https://caniuse.com/',现在我们知道各个版本浏览器支持的语法接下就是配置文件,配置文件是下面的优先级使用: 2.1.@babel/preset-env 里的 targets 2.2.package.json 里的 browserslist 字段 2.3.browserslistrc 配置文件 3.'使用效果': 描述项目支持的环境/目标环境,支持browserslist查询写法 { "targets": "> 0.25%, not dead" } // 全球使用人数大于0.25%且还没有废弃的版本 支持最小环境版本构成的对象 { "targets": { "chrome": "58", "ie": "11" } } 如果没配置targets, Babel会假设你的目标是最老的浏览器 @babel/preset-env将转换所有 ES2015-ES2020代码为ES5兼容 ~~~ >[danger] ##### useBuiltIns -- api 导入 ~~~ 1.'useBuiltIns'解决:首先'AST'语法树解决是语法层面,可以简单的理解将字符进行转换,但是 新增加'api' 层面具有语义的方法,举个例子当我们使用'Promise' 是其内部定义逻辑让'Prmoise' 具备了实现效果。社区也为我们提供了这类赋予'语义' 的包'corejs',并且对'@babel/preset-env' 提供了一个'useBuiltIns'参数可以设置三个值'entry','usage','false'。默认使用false 2.关于三个值含义,需要知道'api'垫片和使用'target '属性解决语法层面的配置他们都有一个共性 就是浏览器逐步升级普及那相对的有些东西就不需要对其打包时候也要转换进去 2.1."useBuiltIns: false":在不主动import的情况下不使用preset-env来处理polyfills,此时不对 'api 垫片做操作',你可以引入你想要的处理'es api'的垫片例如此时 需要在文件引入'import "core-js/stable"' 和 'import "regenerator-runtime/runtime"',则无视配置的 浏览器兼容,引入所有的 polyfill。简单的说目前社区给的'api'垫片库推荐是'core-js' 你需要在项目 入口引入这个'api'垫片,但不会根据你'target'配置按需引入 2.2."useBuiltIns: entry"根据配置的浏览器兼容,引入浏览器不兼容的 polyfill。需要在入口文件手 文件引入'import "core-js/stable"' 和 'import "regenerator-runtime/runtime"',会自动根据 browserslist 替换成浏览器不兼容的所有 polyfill。这里需要指定 core-js 的版本(也就是要设置'corejs'字段版本) 2.3."useBuiltIns: usage"会根据配置的浏览器兼容,以及你代码中用到的 API 来进行 polyfill,实现了按需添加。 总结 推荐使用."useBuiltIns: usage" 配置他自己动会做帮我们引入'corejs垫片',不用在手动全局引入,并且会对 指定浏览器版本进行配合,'注意和entry不同usage 是按需引入并且是和target 匹配,即你用了符合target没有的垫片才引入' ~~~ * 说明corejs ~~~ 1."useBuiltIns: usage"只是会帮你导入 并不会帮你按照corejs 包,因此记住手动安装corejs 'npm install core-js' ~~~ * 说明'regenerator' ~~~ 1.'regenerator' 是 facebook 实现的 'aync' 的 'runtime' 库,babel 使用 'regenerator-runtime'来支持实现 'async' 'await' 的支持。 2.但是 不用安装因为 @babel/preset-env 依赖里面有 'regenerator-runtime' └─┬ @babel/preset-env@7.16.11 └─┬ @babel/plugin-transform-regenerator@7.16.7 └─┬ regenerator-transform@0.14.5 └─┬ @babel/runtime@7.17.2 └── regenerator-runtime@0.13.9 ~~~ * 2.2图 虽然 转换代码只是new Promise() 但实际符合target 垫片全部引入 ![](https://img.kancloud.cn/5b/58/5b580ace75c12b2b357799202fc49345_1434x574.png) * 2.3.图 之引入了 Promise 相关的垫片 ![](https://img.kancloud.cn/73/33/7333676a639dbaa1bdf9ae1cf8f067e8_760x287.png) >[danger] ##### corejs ~~~ 1.corejs是JavaScript的模块化标准库,其中包括各种ECMAScript特性的polyfill。转换后代码中引 入'api'的polyfill都是来源于corejs。它现有2和3两个版本,目前2版本已经进入功能冻结阶段了,新的功能会添加到3版本中。 2.这个选项只有在和 'useBuiltIns: "usage" '或 'useBuiltIns:"entry" '一起使用时才有效果,该属性默 认为"2.0"。其作用是进一步约束引入的polyfill的数量。 ~~~ >[danger] ##### 总结 ~~~ 1.@babel/preset-env + useBuiltins(entry) + preset-env targets,这样@babel/preset-env 定义了 Babel 所需插件预设,同时由 Babel 根据 preset-env targets 配置的支持环境,自动按需加载 polyfills, 当 useBuiltins 配置为 usage,它可以真正根据代码情况,分析 AST(抽象语法树)进行更细粒度的按需引用 ~~~ * 配置的小例子 ~~~ { "presets": [ [ "@babel/preset-env", { "modules": false, "useBuiltIns": "entry", targets: { chrome: 44 } "corejs": 3, } ] ], "plugins": [] } ~~~ >[info] ## 上手案例 ~~~ 1.准备工作安装'@babel/core' '@babel/cli' '@babel/preset-env'创建好了项目结构目录 ├─ lib │ └─ index.js ├─ src │ └─ index.js ├─ babel.config.json // 也可以是.babelrc文件 ├─ package-lock.json ├─ package.json └─ yarn.lock 2.后续执行的指令'npx babel src/index.js --out-dir lib' 3.如果下面'babel.config.json' 文件的内容仅仅是 { "presets": [ [ "@babel/env" ] ] } 我们执行第二步的运行指令发现lib文件夹下的index.js输入如下: "use strict"; var a = 1; console.log(a); var p = new Promise(function (res) { console.log(res); }); p.then(function (res) { console.log(res); }); 'const' 按照我们的期望变成了'var','Promise' 因为是api而不是语法因此没有转译也符合我们的预期 4.现在将'babel.config.json' 修改成下面的形式,但注意了这时候我们制定的'targets'中为 "chrome": "70" ,因为我们的项目不再想执行这令人糟心的ie了,运行指令后在lib文件夹下的index.js输入如下 "use strict"; const a = 1; console.log(a); const p = new Promise(res => { console.log(res); }); p.then(res => { console.log(res); }); 因为谷歌浏览器70的版本是完美支持const ,因此babel没有必要将'const'转换成'var' 5.这里更多建议配置'.browserslistrc' 因为不单单js可以这种选择形式根据配置决定,后续如果你了解 'postcss-loader' 发现他也是类似的,我们不将这些控制的文件放在他们所属指定配置文件中,而是 放到一个全局这种类似都可以统一进行识别文件'.browserslistrc'这样就可以全局统一管理 ~~~ >[danger] ##### useBuiltIns: false 说明 ![](https://img.kancloud.cn/be/27/be275175745ee895662282dbbc94b924_863x456.png) >[danger] ##### "useBuiltIns" 如何做到引入对应的core-js api ~~~ 1.为什么在配置"useBuiltIns" 时候可以帮助我们引入core-js 符合对应环境适应的api,主要原因 '@babel/preset-env' 通过 targets 参数,按照 browserslist 规范,结 合'core-js-compat', 筛选出适配环境所需的 polyfills(或 plugins),通过合理配置帮助我们按需引入垫片 ~~~ >[danger] ##### 更多配置说明 [当然了实际配置值远远大于'modules','useBuiltIns','corejs'配置项更多可以参考官网](https://babeljs.io/docs/en/babel-preset-env#usebuiltins-usage-experimental)