前言问题
当我们使用各种打包工具,需要配置 Babel 的时候,相信大家一开始都会直接网上复制粘贴一个配置,然后运行顺利就万事大吉了吧? 因此,我们有时会遇到打包部署后手机运行白屏等问题; 或者打包后的代码包太大,加载缓慢等。
其实这一切的大部分原因是我们对 Babel 的各种配置没有系统的了解。 因此,即使从网上复制粘贴配置后出现问题,我们也不知道如何分析问题。
准备
如果你已经对 Babel 有一个大概的了解,阅读本文会让你对配置有一个更系统的了解; 如果你刚刚接触Babelentry是什么意思,或者对Babel感到困惑,那么我强烈建议你先阅读这篇文章——想了解Babel? 首先要了解这些包[1],主要介绍和分析一些概念和以下几个包:
他还回答了我们在看官网时提出的一些问题。 因为了解了这些包之后,我们学习配置的时候会更容易理解。
注:我们再来说一下core-js
通过上一篇文章——想了解Babel? 你必须首先了解这些包 [2] 我们知道:core-js 是一种提供旧版本浏览器中缺少的所有 ES6+ API 方法和实现的类型。
在这里,以及下面,我们将引入 core-js 的模块来实现老版本浏览器不支持的 ES6+ API 的过程称为 。
我们看一下core-js包中的主要模块:
pic_5.png
所以,我们可以这样使用它:
以上是我个人的使用习惯,因人而异。 具体介绍可以阅读参考文章。
参考文章:core-js[3]
我们再谈谈@bable/-env
通过上一篇文章——想了解Babel? 首先必须了解这些包[4],我们知道:
那么我们就可以清楚地知道:
我们先看一下@babel/-env的配置项:
// babel.config.js
const presets = [
[
'@babel/preset-env',
{
modules,
targets,
corejs,
useBuiltIns,
spec,
loose,
debug,
bugfixes,
include,
exclude,
forceAllTransforms,
configPath,
ignoreBrowserslistConfig,
browserslistEnv,
shippedProposals
}
]
];
module.exports = {presets};
复制代码
我们可以看到配置项相当多(有些配置项后面可能会被废弃),但实际上我们日常项目中主要使用的是前四种配置,所以这里重点关注前四种配置(尽量不要能学就学吧,太累了)。
参考文章:@babel/-env[5]
当我们设置为 false 时,Babel 编译生成的一些辅助函数的引入方法将变成 ES6 模式引入(A from 'B')。
我们把use--[6]案例中的Babel配置改为如下配置来感受一下这个配置的作用。
// babel.config.js
const plugins = [
'@babel/plugin-transform-runtime'
]
const presets = [
[
'@babel/preset-env',
{
modules: false
}
]
];
module.exports = {plugins, presets};
复制代码
当不设置配置项时,编译后的文件为:
我们会发现途中引入了辅助功能;
设置好配置项后,编译后的文件为:
我们会发现辅助函数已经变成了我们熟悉的ES6模块介绍。
这样做的一个好处是,当我们使用一些打包工具的时候,我们可以对代码进行静态分析,很好的减少代码体积。 因此,我们在配置Babel时,建议设置:false
参考文章:[7]
影响
其用法与[8]一致。 它可以用来设置我们的代码需要兼容的目标环境,所以它:
注意第一点
如果我们不设置这个配置项,它就会去我们的Babel配置文件中寻找最顶层的配置项; 如果没有设置顶层,就会去我们的.json或者根目录中查找; 如果不是,则默认值为 {} 。 搜索过程大致如下,序号代表搜索顺序:
// Babel配置文件
{
targets: 'ie 10', // 2. 如果presets里面没有设置targets,会来这里查找
presets: [
[
'@babel/preset-env',
{
targets: 'ie 9' // 1. 先在这里查找,没的话去顶层targets查找
}
]
]
}
// package.json
{
...,
browserslist: [
'ie 11' // 3. 如果顶层targest里面没有设置,会来这里查找;如果这里也没设置,则为默认值{}
]
}
复制代码
第二点
如果我们不设置这个配置项,Babel 会假设我们要兼容的目标环境是最老的浏览器,因此它会把所有 ES6+ 语法的代码转换为 ES5。 所以我们在配置 Babel 的时候,需要对其进行设置,以减少输出代码的大小。
鉴于此,我们用这个案例-env--[9]来感受一下:
我们会发现ES6+的所有写法都转换成了ES5,并且增加了一些辅助功能(白框)。
好的,我们设置:“80”。 这意味着我们的代码要在80上运行。我们看一下打包结果:
pic_4.png
我们会发现编译出来的代码和我们入口文件中写的代码基本是一样的。 因为80已经实现了编写入口文件代码的方式。 因此,如果我们的代码不需要在一些低端浏览器中运行,那么设置是非常有必要的。
参考文章:[10]
当不为false时,需要设置该配置项
配置
它有两种配置方法:
直接设置core-js版本号
...
{
useBuiltIns: 'usage',
corejs: '3.27.2'
}
...
复制代码
配置
...
{
useBuiltIns: 'usage',
corejs: {
version: '3.27.2',
// 是否编译提案阶段ES6+ API
proposals: false
},
}
...
复制代码
注意
当我们的不为false时,我们需要设置这个配置项
不再推荐 core-js 版本 2; 当然我们必须使用最新版本。 最新版本是 core-js@3.27.2
我们安装的 core-js 必须尽可能保持最新,因为包越新,包含的内容就越多。
当我们设置版本号时,不要直接指定2或3,它会被解析为2.0或3.0。因此,我们应该带上号(3.27.2),这样我们就可以得到最新的
Core-js 默认使用稳定版本entry是什么意思,但如果有时我们想使用仍处于提案阶段的 API 怎么办?
其作用将在下文中一并讨论。
参考文章:[11]
上面我们提到,我们把引入 core-js 的一个模块来实现旧版本浏览器不支持的 ES6+ API 的过程称为 。
该配置用于设置我们的core-js的方法。 它有以下三个值:
为了更好地理解,我们使用这个 ES6+ API 作为示例。 我们都知道:
入口
我们可以这样理解。 中文里的entry是“进入”的意思。 这个值表明我们的应该从某个入口引入来平整它。
表现
我们将配置设置为::'entry'
分析总结
所以我们总结一下它的执行原理大致如下:
我们需要手动全部或某个块
Babel 会根据我们设置的(目标环境)来判断当前是否缺少我们手动设置的全部或某一部分。
如果是这样,我们将手动将所有或某些块拆分为许多小模块,并引入我们的目标环境不支持的模块。
注意
参考文章:[13]
用法
这个值的目的是我们不需要手动做,它会自动帮助我们完成当前缺少的内容。
表现
我们将配置设置为::'usage'
分析总结
所以我们可以总结一下它的执行原理大致如下:
我们不需要手动全部或某个块
Babel 会根据我们当前代码使用的 ES6+ API 来判断当前支持是否支持我们使用的 ES6+ API。
如果不支持,会自动导入对应的ES6+ API。
因为它会自动导入,所以我们可以专注于编写 ES6+。
参考文章:[14]
错误的
这是默认值。 意味着它不会自动添加到每个文件中,也不会根据是否缺失来判断,也不会我们手动将所有或某个块拆分为单个引入。
表现
我们将配置设置为::false
总结
设置为假:
参考文章:[15]
使用适配的IE 11
相信通过上面的讲解,我们对各个配置项已经有了一个大概的了解,下面我们来更深入的体验一下。
我们都知道IE 11基本不支持ES6+。 我们来看看一些常用的ES6+ API:
.png
然后我们将使用 IE 11 作为我们的(目标环境)并研究如何配置 Babel 以便我们编写的 ES6+ 代码可以在 IE 11 中运行。我们使用这个案例 -env--[16]
注意:为了避免打包错误,我们写在.json中,以便识别环境打包
...
"browserslist": [
"ie 11"
]
...
复制代码
我们使用这段代码作为我们的入口文件:
// 如果用`usage`方式,则注释掉这段代码
import 'core-js/stable';
const lMC = {
name: 'limingcan',
like: ['eat', 'drink', 'play', 'fun'],
breath() {
return new Promise(resolve => {
setTimeout(() => resolve(), 1000)
})
}
};
lMC.breath().then(() => console.log('breath'));
console.log(lMC.like.includes('play'));
console.log(Array.of(1, 2, 3));
复制代码
根据我们上面几个配置项的解释,如果我们想要:
常见问题
通过上面的例子,我们会发现:
如果配置是:'entry'
我们扁平化的东西是注入到全局的,或者内置对象的()中,影响全局
一劳永逸的方法会将目前不支持的所有 ES6+ API 扁平化,这很方便,但会导致包变得非常大。
如果配置是:'usage'
它还向全局注入填充。
因为:‘usage’是判断当前的是否支持我们代码中使用的ES6+ API。 如果它不支持它,它会告诉自己。
有一种情况,如果第三方库使用了我们目前不支持的ES6+ API,但是我们自己的代码没有使用这个API,那么这个API就不会被扁平化,从而导致我们的项目报错。
第三方库问题
关于:‘usage’配置的第二个缺点,我们看这个例子use-third-party--[17]来更直接地感受一下。
我们设置为IE 11,我们自己的代码只使用这个ES6+ API,然后使用第三方库tars-utils[18]的方法生成Blob对象(使用``[19]实现) )。
让我们在 IE 11 中运行一下,看看:
.png
通过Babel编译的文件,我们会发现:
我们来看看更高级的浏览器(108):
.png
在108上运行没有问题,因为108内部已经实现了。
总结
看到这里,相信我们对@babel/-env的配置功能有了一个大概的了解。 上述问题对于我们来说确实是非常现实的问题。
所以,到底是设置入口还是使用方式,就看我们项目的实际需要了。 我个人推荐:
我们再聊聊@babel/--
如上所述,@babel/-env配置方法会将当前浏览器中缺少的API注入到全局世界中。 那么有没有办法不将其注入全球世界呢? 答案是肯定的。 接下来我们要讨论的就是@babel/--。
我们先看一下它有多少个配置项(幸好不多):
// babel.config.js
const plugins = [
[
'@babel/plugin-transform-runtime',
{
helpers,
regenerator,
corejs,
version
}
]
];
module.exports = {plugins};
复制代码
&& 解析
我们先看看前两个配置。 因为前两种配置比较简单,所以我们就放在一起说。
通过上一篇文章——想了解Babel? 首先要了解这些包[20],我们知道:
关于@babel/
关于辅助函数
关于
例如,我们使用class语法糖和async(){},然后使用@babel/和@babel/--(默认情况下该值为true)。 编译后如下图所示:
当我们将heel的值设置为false时:
我们会发现我们的辅助函数,并且 - 包返回到内联模式。 所以:
:和 类似,它控制这个包的代码是否不内联到我们的代码中。
注意
官网上的解释大致意思是:如果设置为false,我们需要提供一个全局对象。
但:
解析
一旦这个配置项不为 false英语作文,它就用于设置我们的 ES6+ API 以不污染全局和局部变量的方式进行扁平化。
它有三个值:
该值对应依赖补充
假(默认)
@巴贝尔/
@巴贝尔/-
1.只能编译支持全局变量(如 )和静态属性(如Array.from);
2. 无法编译实例相关方法([].)
@巴贝尔/-
1.不仅可以编译支持全局变量和静态属性,还可以编译实例方法。
2.:true,也可以在阶段编译API
我们用这个例子-[22]来体验一下。
我们会发现实例方法被扁平化了,提出的API(Math.)也被扁平化了; 但它们都是作为局部变量注入的。
因此,如果我们不想以一种全局污染的方式扁平化我们的 ES6+ API,我们就不能将其设置为 false,而更喜欢使用 @babel/- 包进行扁平化(设置为 3)
优化
我们没有设置上述情况,因此 @babel/-- 配置将扁平化我们代码中使用的所有 ES6+ API。 让我们设置一下,看看是否可以平滑我们不支持的 ES6+ API。
我们可以在.json中添加,也可以在配置文件顶层添加(经测试,在@babel/-env中设置不起作用):
// package.json
"browserslist": [
"chrome 80"
]
// 或者在顶层添加
module.exports = {
targets: {chrome: 80}, // 在这里添加
presets: ['@babel/preset-env'],
plugins: [
[
"@babel/plugin-transform-runtime",
{
...
}
]
]
}
复制代码
输出:
我们会发现后跟并没有被压扁,因为80已经支撑好了。
总结
参考文章:babel---[23]
其他最后
通过上面的理解,我们最终总结了这个配置。
文章涉及的例子已上传[30]。 如果您觉得有帮助,欢迎您Star或Fork来学习。
如果读完本文后您觉得确实有帮助,请点赞并保存; 如果有什么相同点或者不同点,欢迎在评论区讨论。
关于本文