前阵子重构了一个挺有意思的项目,是一个基于浏览器环境的数据采集sdk。公司各个产品的前端页面中都嵌入了这个sdk,用于采集用户的行为数据,上传到公司的大数据平台,为后续的运营决策分析提供数据支撑。

笔者接手这个项目的时候,前任开发者已经把功能都写差不多了。唯一需要做的就是做下模块化拆分和代码规范,以便后续的开发维护。模块化拆分用webpack,代码规范用eslint。既然要重构,那就顺手用es6重写吧。callback也不要了,全换成promise,async、await也用起来,反正怎么爽怎么写。

问PM浏览器最低兼容到哪个版本,PM说兼容公司各个产品所兼容的最低版本就行。和公司各个产品的前端负责人沟通后发现,居然有兼容IE8的,真是我了个fk。

google了一下Webpack+Babel+ES6兼容IE8,果然坑很多。试了好几篇博客给出的方案,都跑不通。也没怎么研究具体哪里有问题,因为那些解决方案里面的webpack和babel都是旧版的,跑通了也不高兴用。笔者分析了那些博客中提出的几个关键性问题,然后参考webpack和babel最新的官方文档,总结出一套最新的Webpack4+Babel7+ES6兼容IE8的方案。

ES6兼容IE8需要解决四个问题

语法支持

IE浏览器不支持ES6的语法,只在IE10、IE11中支持了部分ES6的API,所以在IE浏览器中使用ES6需要把ES6的代码编译成ES5才能执行。方法也很简单,就是用babel-loader。这部分没什么坑,所以我也就不细说了。给个网站,大家可以自行查看ES5、ES6在各浏览器版本中的支持情况

kangax.github.io/compat-tabl…

ES3保留关键字

如果在IE8下通过object.propertyName的方式使用ES3中的保留关键字(比如default、class、catch),就会报错

SCRIPT1048: 缺少标识符
复制代码

webpack有一款loader插件es3ify-loader专门用来处理ES3的关键字兼容问题。这个插件的作用就是把这些保留字给你加上引号,使用字符串的形式引用。

// 编译前
function(t) { return t.default; }// 编译后
function(t) { return t["default"]; }
复制代码

然而,笔者亲身实践后发现,UglifyJS本来就已经提供了对IE浏览器的支持,不需要额外引入es3ify-loader。webpack默认的UglifyJS配置不支持ie8,需要手动配下。

{mode: 'production',optimization: {minimizer: [new UglifyJsPlugin({uglifyOptions: {ie8: true}})]}
}
复制代码

执行环境

解决了前面两个问题只能保证语法上不报错,但使用ES6中的API(比如Promise)还是会报错。另外,IE8对ES5的API支持也很差,只支持了少量的API,有些API还只是支持部分功能(比如Object.defineProperty)。所以,要在IE8中完美运行ES6的代码,不仅需要填充ES6的API,还要填充ES5的API。

babel为此提供了两种解决方案:@babel/polyfill、@babel/runtime。具体使用方法官方文档已经写的很详细了,笔者就不赘述了。想了解两者之间的差别的同学可以看下大搜车墨白同学的文章,babel-polyfill VS babel-runtime

这里纠正墨白同学文中的一个错误,就是@babel/polyfill现在已经支持按需加载,准确的说也不能算是错误,因为墨白同学在写这篇文章的时候还不支持按需加载。具体方法我就不细说了,文档里都有,配置下browserlist和@babel/preset-envuseBuiltsIns属性就可以了。

我只说下我在实际开发过程中碰到的坑。

虽然@babel/polyfill@babel/runtime都支持按需加载,但都只能识别出业务代码中使用到的缺失的API,如果第三方库有用到这些缺失的API,babel不能识别出来,自然也就不能填充进来。比如regenerator-runtime中用到的Object.createArray.prototype.forEach。解决办法是,在入口文件处手动引入缺失的API。

模块化加载

笔者原来是想用ES6的模块化加载方案,因为这样可以利用webpack的tree shaking,移除冗余代码,使打包出来的文件体积更小。但在IE8下测试发现Object.defineProperty会报错'Accessors not supported!'。报错代码如下

if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!');
复制代码

我用@babel/plugin-transform-modules-commonjs转成commonjs加载就可以把这个坑绕过去,但同时也意味着放弃了tree shaking

总结

package.json

{"devDependencies": {"@babel/core": "^7.2.2","@babel/plugin-transform-runtime": "^7.2.0","@babel/preset-env": "^7.1.0","@babel/runtime": "^7.3.4","babel-loader": "^8.0.4","core-js": "^3.0.1","uglifyjs-webpack-plugin": "^2.0.1","webpack": "^4.20.2","webpack-cli": "^3.1.2","webpack-dev-server": "^3.1.9","webpack-merge": "^4.1.4"}
}
复制代码

webpack配置

{module: {rules: [{test: /\.js$/,exclude: /(node_modules|bower_components)/,use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env'],plugins: [['@babel/plugin-transform-runtime'],[// 笔者为了兼容IE8才用了这个插件,代价是不能tree shaking// 没有IE8兼容需求的同学可以把这个插件去掉'@babel/plugin-transform-modules-commonjs']]}}}]},optimization: {minimizer: [new UglifyJsPlugin({sourceMap: true,uglifyOptions: {ie8: true,}})]}
}
复制代码

入口文件按需引入缺失的API

require('core-js/features/object/define-property')
require('core-js/features/object/create')
require('core-js/features/object/assign')
require('core-js/features/array/for-each')
require('core-js/features/array/index-of')
require('core-js/features/function/bind')
require('core-js/features/promise')
复制代码

最后附上文章开头提到的sdk源码,笔者已将公司业务相关代码去除,将通用部分开源。github.com/xtTech/dc-s…

Webpack4+Babel7+ES6兼容IE8相关推荐

  1. 记一次webpack4.x打包兼容ie8 的经历

    记一次webpack4.x打包兼容ie8 的经历 写在前面 打包经历中没有用到Promise等语法,只用到了es6的一些语法书写逻辑 webpack使用的是4.x ; babel 使用的是7.x 不一 ...

  2. 兼容ie8_兼容IE8的一些笔记

    最近在做项目,要求兼容主流浏览器之外,还得兼容win7的IE8版本,因为很多客户还是老式win7电脑,甚至还有XP系统的,突然一口老血吐出... 好了,话不多说,上点自己平时踩坑后的一些心得. 一.框 ...

  3. React兼容IE8

    查找网上的React兼容IE8的方法,也发现不少的项目去兼容,而且都修改成功了,但我按照他们的修改方法去改我的框架的时候还是发现很多细节和他们的不一样.下面进行一个修改总结: 一.按照官方微博的公布信 ...

  4. vue兼容IE8以上解决方案

    一.说明背景 vue主要采用了ES6 Promise,我们知道的,在 JavaScript 中,所有代码都是单线程的,也就是同步执行的.而 Promise 就为异步编程提供了一种解决方案. 二.解决方 ...

  5. 兼容ie8 rgba()用法

    滤镜filter的用法 在一个页面中设置一个半透明的白色div. [css] view plaincopy background: rgba(255,255,255,.1); 但是ie8不支持rgba ...

  6. 让Bootstrap 3兼容IE8浏览器

    看到这篇文章有越来越多的人看,我决定给大家节省时间,废话少说.有几个点大家要注意. 1.本地调试需要Web Server(如IIS.Apache,Nginx),单纯地本地打开文件不能看到兼容效果. 2 ...

  7. 关于让bootstrap3兼容ie8

    官网上有说Internet Explorer 8 和 9 是被支持的,然而,你要知道,很多 CSS3 属性和 HTML5 元素 -- 例如,圆角矩形和投影 -- 是肯定不被支持的.另外, Intern ...

  8. html中两个标签上对齐,css将两个元素水平对齐的方法(兼容IE8)

    css实现水平对齐,如图 有人会说css实现这种水平对齐要兼容ie8还不简单吗?使用float: left,或者display: inline-block,不就可以了吗?是的,最常用的最简单方式就是上 ...

  9. java websocket ie8_websocket兼容IE8

    最近由于项目需要做实时聊天功能,选择了html5的websocket方案(事实上node.js+socket.io兼容性更好,个人觉得这个方案更加完美),websocket实现实时聊天的demo网上很 ...

最新文章

  1. IronPython系列:Composite Pattern及其实现
  2. Tensorflow的基本运行方式--demo程序
  3. leetcode-合并两个有序链表
  4. Java使用JDBC连接随意类型数据库(mysql oracle。。)
  5. Collection和Collections区别
  6. 带有Swagger的Spring Rest API –公开文档
  7. sql中查询类型为int的字段,返回null的异常
  8. java.lang.NumberFormatException: For input string: 0.7
  9. 隐马尔可夫模型基础介绍
  10. Servlet的Mapping
  11. 华为p20nfc怎么复制门禁卡_华为荣耀手机的NFC功能怎么用?怎么刷门禁卡
  12. 找不到局域网计算机网络路径,分享解决Win10局域网找不到网络路径的技巧
  13. 阿里矢量图标iconfont在微信小程序的使用
  14. 交叉编译qt5.11.3源码(不带opengl)
  15. pdf会签_设备验收管理办法20140604(会签签批版).pdf
  16. 纳什均衡-- 硬币正反
  17. 阅读作业第一弹——移山之道 by 吴煜
  18. Unity制作Animation帧动画
  19. mmc0: error -84 whilst initialising SD card
  20. 【RPG Maker MV】使用技巧1:用自己绘制的图片当做地图

热门文章

  1. 自然语言处理python培训
  2. 什么是 数据,数据库,数据库管理系统,数据库系统?
  3. oracle语句调试,Oracle中使用fnd_log_messages调试的步骤
  4. 群控 云控营销神器代码研究
  5. Django-(6)
  6. KVC基本原理和用法
  7. Unity快速入门之四 - Unity模型动画相关
  8. Struggling
  9. java-php-python-ssm网上拍卖系统计算机毕业设计
  10. js和ts两种 将 小写金额转中文大写汉字,阿拉伯数字金额格式化成中文大写汉字,数字金额转换成财务发票大写中文