webpack 异步组件的缺陷

799 查看

webpack本身自带切割代码(code splitting)的功能,脚本按需加载,简单好用

用法如下:

require.ensure(["module-a", "module-b"], function(require) {
    var a = require("module-a")
    // ...
})

//或

require(['./my-async-component'], resolve, reject) //vue组件自带错误回掉方法

但是,该功能也不是完美的,在3g、4g网络下出现了无法加载异步组件的问题!!!坑爹呀!!!

经过分析,得出下面的结论:

1、运营商3g、4g网络 阶段性断网 ,尤其 联通 最严重
2、webpack本身 无法捕获异步组件加载失败 的情况 (webpack2支持捕获组件状态

既然第一个问题无法解决,那我们就解决第二个问题。


方法一(不可分离公共代码):

1、 安装 require-error-handler-webpack-plugin 插件,用它捕获异步组件的加载失败的状态

// webpack.config.js

var  requireErrorHandlerPlugin = require('require-error-handler-webpack-plugin'),
    JsonpMainTemplatePlugin = require('webpack/lib/JsonpMainTemplatePlugin')

2、 使用这个插件

// webpack.config.js

plugins: [
    new requireErrorHandlerPlugin.JsonpErrorHandlerPlugin(JsonpMainTemplatePlugin),
    new requireErrorHandlerPlugin.RequireEnsureErrorHandlerPlugin(),
    new requireErrorHandlerPlugin.AMDRequireErrorHandlerPlugin()
]

3、项目中使用方法(这个方法不能完全遏制,但是可以减少加载失败的概率)

// app.vue

export default {
    components:{
        a: (resolve, reject) => {
            const tryMax = 15
            let tryCount = 0,
                _time = null //隔1.5秒执行一次

            getComponents()
            
            //递归调用组件
            //因为运营商网络会出现短暂的断网现象,所以每隔1500ms就唤醒一次,对多唤醒11次
            function getComponents() {
                require(['../view/a'], (response) => {
                    //成功后执行
                    resolve(response)
                }, () => {
                    //异步组件加载失败后调用
                    
                    tryCount += 1

                    if (tryCount > tryMax) { // 若超出最大尝试次数则 reject
                        reject()
                    } else {
                        _time = setInterval(() => {
                            clearInterval(_time)
                            getComponents()
                        }, 1500)
                    }
                })
            }
        }
    }
}

方法二(推荐,可分离公共代码):

1、 安装 async-module-loader 插件,用它捕获异步组件的加载失败的状态

// webpack.config.js

var  AsyncModulePlugin = require('async-module-loader/plugin')

2、 使用这个插件

// webpack.config.js

plugins: [
    new AsyncModulePlugin()
]

3、项目中使用方法

// common.js

//按需加载组件的公共方法,因为运营商网络会出现短暂的断网现象,所以每隔1500ms就唤醒一次,对多唤醒11次
function getComponents(requireModel, tryMax, tryCount, resolve, reject) {
    let _time = null

    requireModel(function onLoad(response) {
        resolve(response)
    }, function onError() {
        tryCount += 1

        if (tryCount > tryMax) { // 若超出最大尝试次数则 reject
            reject()
        } else {
            _time = setInterval(() => {
                clearInterval(_time)
                getComponents(requireModel, tryMax, tryCount, resolve, reject)
            }, 1500)
        }
    })
}

// app.vue

export default {
    components:{
        a: (resolve, reject) => {
            //调用方式
           getComponents(require('async-module!./view/Login'), 10, 0, resolve, reject)
        },
        b: (resolve, reject) => {
            //调用方式
           getComponents(require('async-module!./view/help'), 10, 0, resolve, reject)
        }
    }
}

当项目访问量很大,甚至超过 1000万 pv/天的访问量,就会发现一些恶心的问题,而这些问题的暴露都要感谢我们的用户,因为他们,我们才会知道运营商网络的不稳定性,知道了我们代码中的缺陷