乐趣区

关于webpack4:webpack单文件懒加载分析实现

log.js文件

module.exports ="lazy load logger"

index.js文件

let oBtn = document.getElementById('btn')

oBtn.addEventListener('click', function () {import( /*webpackChunkName: "log"*/ './log.js').then((log) => {console.log(log)
    })
})
console.log('index.js 内容')

点击按钮时, 控制台显示 lazy load logger
webpack 在打包后,比之前的单文件加载多出了几件事件。懒加载的实现次要通过Promise 来实现。
实现懒加载,要调用 __webpack_require__.e 办法,e 办法是一个 promise 状态保留。e 办法中,jsonP 创立 srcipt 标签,指定 src,通过 Promise.all 把状态往后传,在过程中,动静加载要被导入的内容, 这里会通过 window['webpackJsonP] 调用 push 办法. 调用 webpackJsonpCallback 办法,执行胜利的 resolve 办法,__webpack_require__.e后的 then 办法通过 __webpack_require__.t 办法加载 log 中的内容放在 value 中保留. 这里多出的两个操作一个是jsonP,一个是__webpack_require__.e

// 定义 webpackJsonpCallback,合并模块定义,扭转 promise 状态,还有之后的 then 操作
    function webpackJsonpCallback(data) {
        // 获取要被动静加载的模块 id
        let chunkIds = data[0];
        //  获取须要被动静加载模块的依赖关系对象
        let moreModules = data[1]
        let chunkId
        let resolves = []
        // 循环判断 chunkIds 里对应的模块内容是否曾经实现加载
        for (let i = 0; i < chunkIds.length; i++) {chunkId = chunkIds[i]
            if (Object.prototype.hasOwnProperty.call(inStalledChunks, chunkId) && inStalledChunks[chunkId]) {
                // 数组程序,resolve,reject,promise,这里是曾经加载,所以是 0
                resolves.push(inStalledChunks[chunkId][0])
            }
            // 更新 chunk 状态
            inStalledChunks[chunkId] = 0;
        }

        for (let moduleId in moreModules) {if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {modules[moduleId] = moreModules[moduleId]
            }
        }

        while (resolves.length) {resolves.shift()()}
    }

    // 定义 inStalledChunks 用于标识某个 chunkId 对应的 chunk 是否实现加载
    let inStalledChunks = {main: 0}

    // 定义 jsonpScriptSrc 实现 src 的解决
    function jsonpScriptSrc(chunkId) {return __webpack_require__.p + ""+ chunkId +'.built.js'}

    // 定义 e 办法,用于实现:实现 jsonP 异步加载,利用 promise 来实现异步加载操作
    __webpack_require__.e = function (chunkId) {
        // 定义一个数组用于寄存 promise
        let promises = [];
        // 获取 chunkId 对应的 chunk 是否曾经实现了加载
        let installedChunkData = inStalledChunks[chunkId]
        // 根据以后是否已实现加载的状态来执行后续的逻辑
        if (installedChunkData !== 0) {if (installedChunkData) {
                // push 一个残缺的 promise
                promises.push(installedChunkData[2])
            } else {
                // 执行加载操作
                let promise = new Promise((resolve, reject) => {installedChunkData = inStalledChunks[chunkId] = [resolve, reject]
                })
                promises.push(installedChunkData[2] = promise)
                // 创立标签
                let script = document.createElement('script')
                // 设置 src
                script.src = jsonpScriptSrc(chunkId)
                // 写入 script 标签
                document.head.appendChild(script)
            }
        }

        // 执行 promise
        return Promise.all(promises)
    }
退出移动版