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的方式來達到兼容。

謝謝觀看~

相關文章
相關標籤/搜索