1
本文基于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这种会暴露全局变量的确实也让我意想不到,有遇到类似问题的朋友可以参考下咯~


whidy
984 声望77 粉丝

喜欢玩游戏听歌写东西 ฅʕ•̫͡•ʔฅ