mrdulin / blog

Personal Blog - 博客 | 编程技术,软件,生活

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

查找原因

  1. 用USB连接手机和Mac
  2. iPhone设置 - Safari - 高级 - 开启web inspector
  3. 在iPhone Safari中打开要调试的页面
  4. 打开Mac OSX下的Safari浏览器 - 菜单项 - 开发 - 找到要调试的页面,点击会打开“网页检查器”,如下图:

在控制台可以看到,页面脚本已经报错了 TypeError: Map constructor does not accept arguments

点击错误堆栈,跳转到资源文件报错位置:

react 16.2.0这里使用es2015新的数据类型——Map类型,去caniuse查一下Map数据类型的兼容性

IOS Safari下,只有IOS 9.3以上才支持Map数据类型。

解决方案

  1. webpackbabel-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。

这个模块是怎么被引入进来的?原因是.babelrcplugins中的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),所以应该让需要编译转换的文件尽可能少。

别说生产环境,就是开发阶段,首次编译的速度都很慢(导致开发效率降低),所以这种方案是不合理的。

  1. 手动加入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中也报错了;
还是你的方法解决的. 赞一个;