问题说明:
在使用压缩工具压缩并内置babel
将ES2015
转换成ES5
打包js时,代码出现问题,代码简化后问题如下图1-1所示:
图1-1
this
被识别成了
undefined
。
以下为问题查找记录。
问题结果预说明:
之所以加个预说明是因为通篇记录对于该bug的查找过程,结果并没有达到完全解决,解决bug以去掉某些模块为前提,直接看结果请拉到最下方结果说明。
问题查找过程:
-
问题原因
通过搜索,在github issue查找到对于该问题的讨论github issue:this is undefined for React components #37;issue中对于该问题讨论如下图1-2:
图1-2
图上说导致原因为
babel-plugin-transform-es2015-modules-commonjs
,在进入该js的src目录下得
index.js
文件中,通过查找有一块代码如下图1-3:
图1-3
也就是说当
allowTopLevelThis!=true
时,会把
this
变成
undefined
,那么解决方式应该为把
allowTopLevelThis
设置属性值为
true
。
-
属性配置
通过 babel-plugin-transform-es2015-modules-commonjs的
readme
文件可以找到更改配置的方式有三种如图1-4:
图1-4
.babelrc
配置文件,第三种为在引入
babel-core
模块或者进行转换时进行配置.
- 配置测试
环境说明:使用ezpack
压缩如下代码:
(function(){
}).call(this)
在babel-plugin-transform-es2015-modules-commonjs>lib>index.js
中增加了三个console.log代码:如下图1-5所示:
图1-5
.babelrc
中配置代码:
{
presets: [
["es2015"]
],
"plugins": [
["transform-es2015-modules-commonjs", {
"allowTopLevelThis": true
}]
]
}
但是控制台中打印出来的结果确不是我们想要的结果,打印结果如下1-6:
图1-6
控制台中仍然打印出了undefined,而不是只有true,也就是说我们配置的属性
allowTopLevelThis
并没有完全的起作用,更令人费解的是既打出了
true
又打出了
undefined
面对这种情况开始了更苦逼的查bug之路。
- 继续查找bug
继续查找bug过程中主要分为两个部分:
1. 找到了代替的babel-preset-es2015-script
打开github
连接直接就是readme
文件,在.babelrc
中配置如下,presets
中不再配置es2015
,而是配置es2015-script
,代码如下:
{
"presets": ["es2015-script"]
}
测试发现转换后的文件是call(this)
,而非call(undefined)
,转换成功,至于调试的babel-plugin-transform-es2015-modules-commonjs
中的console.log
,根本就没有出现,通过查看babel-preset-es2015-script
的index.js
文件,发现里面并没有引用babel-plugin-transform-es2015-modules-commonjs
模块,这个提供了一个思路就是如果在babel-es2015-script
中也不引用该模块,那么是否就可以解决问题了呢?然后我们回到babel-es2015-script
中的index.js
文件,如下图1-7所示:
图1-7
commonjs
模块的部分全都注释掉,然后采用配置测试中的
babelrc
文件执行,控制台打印如下图1-8:
图1-8
注释掉该模块后就不再打印
undefined
,而true存在的原因则是因为配置文件中的属性更改起了作用,模块注释并不代表这个文件不存在,通过跟踪堆栈发现,当检索到
.babelrc
时,依然引用了该模块,这也可以解释为什么图1-6中打印出的信息为既有
true
又有
undefined
,也不知道为什么配置文件没有pk过原来的引用模块。
2. 查找babel-preset-2015 readme文件
readme文件如下图1-9所示:
图1-9
个人理解是在配置文件中增加
loose
配置,可以使得配置属性覆盖默认属性,此时
.babelrc
代码如下:
{
presets: [
["es2015", {"loose": true}]
],
"plugins": [
["transform-es2015-modules-commonjs", {
"allowTopLevelThis": true
}]
]
}
但是!
控制台中打出的信息仍然和图1-6一模一样,既有true,又有undefined,(内心崩溃泪流满面……),然后我把配置文件改成了这样:
{
presets: [
["es2015", {"loose": true,"modules": false}]
],
"plugins": [
["transform-es2015-modules-commonjs", {
"allowTopLevelThis": true
}]
]
}
结果正常通过,结果如图1-8,一切转换正常。这个配置和babel-preset-es2015-script
起的作用是一样的,不引用modules
模块,也就是说如果在es2015转换为es5的过程中不需要转换成这四种"amd", "umd", "systemjs", "commonjs"
module type,也可以把模块去掉。
结果说明:
.babelrc
中配置如下:
{
presets: [
["es2015", {"loose": true,"modules": false}]
],
"plugins": [
["transform-es2015-modules-commonjs", {
"allowTopLevelThis": true
}]
]
}
若不想放在babelrc中可以写在代码中transform转换时刻:
var babel = require('babel-core');
var js =babel.transform(this.file, {
presets:[['es2015',{loose:true,modules: false}]],
plugins:[["transform-es2015-modules-commonjs", { allowTopLevelThis:true}]],
});
即可把this
改成undefined
,但是通过配置去掉了es2015-modules-amd、es2015-modules-commonjs、es2015-modules-systemjs
、es2015-modules-umd四个模块。
不足之处:
由于测试时是在构建工具ezpack
中测试,没有单独剥离babel
环境,所以无法判定配置中属性"allowTopLevelThis": true
无法pk过引用模块的原因是babel本身所致,还是ezpack引起的,需后续单独剥离babel
环境继续测试,文中若有不足或错误之处,或者更好的解决方式,还请多多指出。
个人博客:
进击的程序茗