TypeError: Map constructor does not accept arguments
mrdulin opened this issue · comments
问题:移动设备调试时,页面白屏,这个见的多了,很有可能又是兼容性问题,程序报错导致应用crash。
测试环境:
- iPhone 6P - ios 8.1.2 - Safari
"react": "^16.2.0"
- Mac OSX
查找原因:
- 用USB连接手机和Mac
iPhone
设置 - Safari - 高级 - 开启web inspector- 在iPhone Safari中打开要调试的页面
- 打开Mac OSX下的Safari浏览器 - 菜单项 - 开发 - 找到要调试的页面,点击会打开“网页检查器”,如下图:
在控制台可以看到,页面脚本已经报错了 TypeError: Map constructor does not accept arguments
点击错误堆栈,跳转到资源文件报错位置:
react 16.2.0
这里使用es2015
新的数据类型——Map类型,去caniuse查一下Map数据类型的兼容性
IOS Safari下,只有IOS 9.3以上才支持Map数据类型。
解决方案:
- 在
webpack
的babel-loader
中配置如下:
module: {
rules: [
{
test: /\.js$/,
include: [
src,
path.resolve(__dirname, 'node_modules/react')
],
loader: 'babel-loader'
}
]
}
{
"presets": [
"env",
"react"
],
"plugins": [
"transform-runtime"
]
}
再来看一下结果:
可以看到,Map数据类型,已经被编译转换了,new _map2.default([['children', true], ['key', true]])
那么这个_map2
是什么呢?搜一下,找到了:
var _map = __webpack_require__(/*! babel-runtime/core-js/map */ 46);
var _map2 = _interopRequireDefault(_map);
是babel-runtime/core-js/map
这个模块,core-js是一个es2015标准库,用来polyfill。
这个模块是怎么被引入进来的?原因是.babelrc
中plugins
中的transform-runtime
配置,依赖的模块是babel-plugin-transform-runtime,这个模块的作用要细说有不少(闲了再写一篇针对此模块的说明),这里简单说下,遇到es2015
新的数据类型Map
, Set
,会自动require
core-js
标准库中相应的polyfill,不像babel-polyfill
一次性引入所有的polyfill。
再次访问,页面正常显示了。
这种解决方案由于要babel-loader
编译转换整个react
库,而babel-loader
编译转换是比较慢的(https://github.com/babel/babel-loader#babel-loader-is-slow),所以应该让需要编译转换的文件尽可能少。
别说生产环境,就是开发阶段,首次编译的速度都很慢(导致开发效率降低),所以这种方案是不合理的。
- 手动加入
core-js
相应的polyfill模块
entry: {
app: src,
vendors: [
'core-js/es6/map', //这里必须要加在最前面,后面`react`中的`Map`才能用到`core-js/es6/map`
'react',
'react-dom',
'react-router-dom',
'react-tap-event-plugin'
]
}
module: {
rules: [
{
test: /\.js$/,
include: [
src,
// path.resolve(__dirname, 'node_modules/react')
],
loader: 'babel-loader'
}
]
},
再次访问页面,错误消失。
这是一种比较好的方式,单独为Map
数据结构加了一个polyfill,不会影响babel-loader
编译转换的速度。
演示仓库在此:https://github.com/mrdulin/react-tap-event-plugin-issues
在入口文件如顶端引入整个babel-polyfill
低版本Safari中也报错了;
还是你的方法解决的. 赞一个;