Webpack動態導入功能有BUG?部分資源竟沒加載,來看看什麼是webpackJsonp?

本文基於Webpack4,如果你遇到類似問題,又懶得看全文,請直接拖到文章底部查看解決總結部分

事件描述

我做了個小工具(站點訪問點擊熱力圖查看工具),這個小工具通過Webpack進行打包,工具中用到了Webpack的動態導入(Dynamic Imports)功能,本地測試運行良好,上線成功!撒花🎉。

數日後...運營妹子找來:“小白,我那個網站的熱力圖怎麼顯示不出來!!!”

我說:“清緩存再試”、“換瀏覽器再試”、“重啓電腦再試”!

數分鐘後,妹子腦袋上着火了,金燦燦,無比耀眼,向我走來,我都快瞎了,啊,我兩眼都看不見了。

她說,“你自己看,根本不行!”

我一度操作猛如虎,F12開啓,強制刷新,咦,控制檯咋報錯了。。。裝逼失敗!“妹子大怒,熱力圖呢!?”

圖片描述

問題分析

我突然感覺到,問題大了,我開發的工具居然在某些場景下出現不可用!趕緊看看其他已用該產品的工具情況,都是好的!面對這樣的情況,確實有點無從下手了。

從Network面板上觀察,發現有個動態加載的js沒有加載到!這個js就是控制熱力圖渲染邏輯的。資源都沒加載到,程序肯定出問題,那爲啥資源莫名其妙的沒有加載呢?想來想去也沒想出來。

既然這樣,就只能從出問題的網站上的錯誤提示中找線索了。部分代碼如下:

Object(n.a)()).then(function(e) {
  if (200 === e.code)
    return document.getElementById("JlaHeatmapLayer").style.display = "none",
    new Promise(function(t, n) {
      t(r.e(0).then(r.bind(null, 9)).then(function(t) {
        var r = t.default;
        setTimeout(function() {
          r(e.data)
        }, 600)
      }))
    }
    );
  alert(e.msg)
}).catch(function(e) {
  alert(e),
  console.warn(e)
})

上面試壓縮後的代碼進行chrome的format後的結果,因爲寫這篇文章,生產線已經修復,只能簡單描述下錯誤,錯誤出現在r(e.data),提示r未定義,這裏動態導入功能利用promise,t其實就是resolve,裏面執行了一個r.e(0),這個r方法,就是管理需要加載的文件。

這裏面的細節我就不多說了,簡單描述下:因爲是動態載入,那肯定有個數組或對象存放需要載入的文件id,在這個方法內他會在合適的時候取出對象中的對應的文件。

而在工具使用正常的頁面中,發現這個對象,只有1個,確實是我需要用的文件,而出問題的頁面中,這個對象居然有10個!!!這就不對了!我沒有寫那麼多動態導入,爲啥出來這麼多?

我經過斷點反複分析,從Stack內查看運行邏輯,終於發現了類似的這段代碼:
// 工具正常頁面
(window.webpackJsonp = window.webpackJsonp || []).push([[0], [, , , , , , , , , function(e, t, n) {
// ...

// 工具異常頁面
(window.webpackJsonp = window.webpackJsonp || []).push([[10], {
// ...

這個大大的window確實十分可疑!針對這個繼續深入研究一下!

這裏插一段工具的動態導入的源碼片段
window.onload = () => {
  // init方法用來鑑權的
  init()
    .then((result) => {
      if (result.code !== 200) {
        alert(result.msg)
        return
      }
      document.getElementById('JlaHeatmapLayer').style.display = 'none'
      return new Promise((resolve, reject) => {
        resolve(import(/* webpackChunkName: "draw" */ './draw').then((module) => {
          const draw = module.default
          setTimeout(() => {
            draw(result.data)
          }, 600)
        }))
      })
    }).catch((err) => {
      alert(err)
      console.warn(err)
    })
}

有興趣可以看看~

解決

那遇到問題自然查文檔,打開官網,搜索webpackJsonp,一下就找到了output.jsonpFunction

原來這是webpack打包輸出選項中的一個配置。用來做什麼的呢,jsonp一看還以爲是跨域有關的,哈哈。其實他是一個異步加載chunks的函數。看到這裏再思考下爲啥這個頁面就出問題呢,哈!這個出問題的頁面是用KOA + NUXT,Nuxt自帶了動態加載的功能,到這裏真相大白。Nuxt中的webpackJsonp全局變量和我工具中的webpackJsonp全局變量發生衝突,導致工具中的動態導入出現異常,工具就完蛋了。

於是趕緊打開工具項目,參考文檔進行了修改:

output: {
  path: path.resolve(__dirname, 'dist/dist/client/'),
  publicPath: IS_DEV ? '' : `//${process.env.BUILD_HOST}.51.la/dist/`,
  filename: 'heatmapDraw.js',
  jsonpFunction: 'wpJsonp51LAHeatmapTool'
},

重新打包,更新上線(專注面向正式線編程、就是這麼自信:P)。啊哈,一切正常,看看代碼,已經變成了如下:

(window.wpJsonp51LAHeatmapTool = window.wpJsonp51LAHeatmapTool || []).push([[0], [, , , , , , , , , function(e, t, n) {
// ...

問題解決,簡直完美,繼續撒花🎉🎉🎉~開開心心找妹子原諒去咯。

總結

其實一直對Webpack都有不斷的學習,但是Webpack功能太強大了,確實很多疏忽的地方,不過我個人感覺Webpack之所以強大,真的是隻要你想得到的需求配置幾乎全都能滿足,確實值得深入研究。

另外Webpack這種會暴露全局變量的確實也讓我意想不到,有遇到類似問題的朋友可以參考下咯~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章