vue-cli踩坑记录

前段时间遇到了一个vue-cli致使的bug,钻研了半天才解决,因而有空写篇文章记录下来。

1、奇怪的bug出现

有用户反馈在ie11下打不开咱们的线上网站,即便开了兼容模式也打不开咱们的网站,页面白屏。
image.pngcss

初步判断,因为css样式资源、页面资源都已经加载到位,排除网络环境问题后,让用户打开控制台截图看一下,白屏的缘由是因为JS执行报错阻塞了后续的逻辑执行和渲染。html

image.png

代码中存在执行错误的逻辑,可是按照打包后的压缩js文件是彻底没法肯定问题的,若是你有接入sentry或者badjs等错误上报模块,那么你能够根据错误信息,快速定位到源码上的问题。
可是问题又出现了,sentry的引入其实最合法合规最正确的引入方式,应该是最页面资源加载的最前面,有些人会其防止在head标签中优先加载,这样页面后续不管是资源加载出错、HTML解析错误 或者 JS逻辑执行报错,均可以捕获到而且进行上报。
然而当初没有考虑到这一点,而是直接在vue-cli中的main.js中直接import sentry的方式引入,这样意味着打包后的bundle若是首次执行出错的话,sentry都未能完成初始化,致使错误内容没法上报。
根据用户的截图也不能很快的肯定问题代码以及报错内容,因而先让有windows电脑的同事用ie11打开网址,查看报错内容,果真,报错了,报的错还不止一个。vue

image.png

定位对应的行代码:
image.pngnode

image.png
第二个问题主要是因为使用v-model绑定type为radio值的input时,还自定义了属性:checked,致使最后编译出来的代码里出现对重复属性的定义,而正式环境下的bundle包通常都是默认'use strict',因此致使触发严格模式,ie11报错,根据属性名即可以快速定位问题并修改。webpack

最后仍是回来说讲第一个问题,智障IE还不支持class?是的 不支持
image.png
可是 为啥咱们的打包产物里会出现莫名其妙的ES6代码?
按理说vue-cli已经帮咱们引入了babel-loader针对ES6代码进行了转换,为啥还会出现class呢?
带着这个问题咱们继续往下看es6

2、分析缘由、肯定问题

根据报错文件chunk-vendors,咱们来开一下咱们的vue.config.js中针对不一样chunk的配置文件:web

optimization: {
      splitChunks: {
        cacheGroups: {
          echarts: {
            name: 'chunk-echarts',
            test: /[\\/]node_modules[\\/]echarts[\\/]/,
            chunks: 'all',
            priority: 10,
            reuseExistingChunk: true,
            enforce: true,
          },
          demo: {
            name: 'chunk-demo',
            test: /[\\/]src[\\/]views[\\/]demo[\\/]/,
            chunks: 'all',
            priority: 20,
            reuseExistingChunk: true,
            enforce: true,
          },
          page: {
            name: 'chunk-page',
            test: /[\\/]src[\\/]/,
            chunks: 'all',
            priority: 10,
            reuseExistingChunk: true,
            enforce: true,
          },
          vendors: {
            name: 'chunk-vendors',
            test: /[\\/]node_modules[\\/]/,
            chunks: 'all',
            priority: 5,
            reuseExistingChunk: true,
            enforce: true,
          },
        },
      },
    },

出现es6代码都来自于node_modules下的chunk包,为啥呢?
接下来为了进一步肯定咱们的es6代码是从哪一个第三方库引入的,咱们须要暂时关闭掉uglify压缩代码,配置以下:vue-cli

module.exports = {
  ...
  optimization: {
    minimize: false,
    ...
  }
};

再进行以上配置,便可以关闭webpack4的默认压缩配置,这时候咱们再来咱们打包产物中找找,大片的const和let,还有咱们要找的罪魁祸首,class:npm

image.png

对应的第三方库的地址为./node_modules/dom7/dist/dom7.modular.jsjson

接下来咱们要继续追查,是哪里引用到了这个包,在package-lock.json里很快锁定到目标:

image.png

swiper是移动端用户轮播的一个第三方库,而这里引用到了dom7模块,
咱们翻一下swiper的源码 在它的源码中的swiper.esm.bundle.js打包产物中,的确看到这么一条引入:

import { $, addClass, removeClass, hasClass, toggleClass, attr, removeAttr, data, transform, transition as transition$1, on, off, trigger, transitionEnd as transitionEnd$1, outerWidth, outerHeight, offset, css, each, html, text, is, index, eq, append, prepend, next, nextAll, prev, prevAll, parent, parents, closest, find, children, remove, add, styles } from 'dom7/dist/dom7.modular';

可是为啥咱们引入的是esm的产物代码呢?默认webpack不会帮咱们引入main字段对应的产物吗?
翻看一下webpack的官方文档,咱们能够看到有这么一个配置项:
resolve.mainFields:
当从 npm 包中导入模块时(例如,import * as D3 from "d3"),此选项将决定在 package.json 中使用哪一个字段导入模块。根据 webpack 配置中指定的 target 不一样,默认值也会有所不一样。

image.png

webpack的默认配置下,mainfields字段所指定的是优先以module为入口,这么设计的缘由是为了顺应时代的潮流,让你们使用es6导出的模块,逐步淘汰掉以往的Commonjs模块规范,毕竟import、export能带来更多的好处。
而咱们的vue-cli在构建编译 默认target是为node,因此咱们的mainFields字段也默认为['module','main']

缘由分析:

到这里咱们已经明白问题的关键是啥了,因为webpack不会对node_modules中引入的第三方库内的代码进行二次的ES6转码处理,而webpack默认又会引入module字段所指向的打包产物,module产物通常是ES6规范输出,main产物通常是commonjs或UMD规范输出,因此部分ES6代码的残留致使IE11不兼容,最终致使报错。

3、修改配置

居然肯定了问题所在,接下来咱们只须要按照vue-cli官方文档所介绍,自行配置一下webpack配置便可:

configureWebpack: {
    resolve: {
      mainFields: ['main', 'module'],
    },

vue-cli中默认引入了一些loader和plugin,因此内部已经有一份webpack的配置了,vue-cli经过暴露configureWebpack参数的方式,容许使用者对webpack进行再配置,若是是以对象形式传入,会与内部的webpack配置对象进行merge操做。

修改完配置后,最后检查一下咱们的打包产物,的确已经没有了const、let、class等这类es6语法,大功告成,bug解决。

固然,若是你的网站须要兼容大多数浏览器和不一样场景的话,你还须要为你的代码引入polyfill,毕竟ES6转ES5只是针对部分语法,然而ES6所新增的部分API是不会进行转换的,这时候只能经过引入前置polyfill的方式来达到兼容。

谢谢观看~

相关文章
相关标签/搜索