美文网首页
webpack基础源码 & 懒加载

webpack基础源码 & 懒加载

作者: JerrySi | 来源:发表于2022-01-24 21:55 被阅读0次
(function (modules) {
  // 01 定义对象用于将来缓存被加载过的模块
  let installedModules = {}

  // 02 定义一个 __webpack_require__ 方法来替换 import require 加载操作
  function __webpack_require__(moduleId) {
    // 2-1 判断当前缓存中是否存在要被加载的模块内容,如果存在则直接返回
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports
    }

    // 2-2 如果当前缓存中不存在则需要我们自己定义{} 执行被导入的模块内容加载
    let module = installedModules[moduleId] = {
      i: moduleId,
      l: false,
      exports: {}
    }

    // 2-3 调用当前 moduleId 对应的函数,然后完成内容的加载
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__)

    // 2-4 当上述的方法调用完成之后,我们就可以修改 l 的值用于表示当前模块内容已经加载完成了
    module.l = true

    // 2-5 加载工作完成之后,要将拿回来的内容返回至调用的位置 
    return module.exports
  }

  // 03 定义 m 属性用于保存 modules 
  __webpack_require__.m = modules

  // 04 定义 c 属性用于保存 cache 
  __webpack_require__.c = installedModules

  // 05 定义 o 方法用于判断对象的身上是否存在指定的属性
  __webpack_require__.o = function (object, property) {
    return Object.prototype.hasOwnProperty(object, property)
  }

  // 06 定义 d 方法用于在对象的身上添加指定的属性,同时给该属性提供一个 getter 
  __webpack_require__.d = function (exports, name, getter) {
    if (!__webpack_require__.o(exports, name)) {
      Object.defineProperty(exports, name, { enumerable: true, get: getter })
    }
  }

  // 07 定义 r 方法用于标识当前模块是 es6 类型
  __webpack_require__.r = function (exports) {
    if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
      Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" })
    }
    Object.defineProperty(exports, '__esModule', { value: true })
  }

  // 08 定义 n 方法,用于设置具体的 getter 
  __webpack_require__.n = function (module) {
    let getter = module && module.__esModule ?
      function getDefault() { return module['default'] } :
      function getModuleExports() { return module }

    __webpack_require__.d(getter, 'a', getter)

    return getter
  }

  // 1 接收二个参数,f是value F用于表示被加载的模块id ,第二个值mode是一个二进制的数值
  // 2 t方法内部做的第T牛事情就是调用自定义的require方法加载value对应的模块导出,重新赋值给value
  // 3 当获取到了这个value值之后余下的8 4 ns 2都是对当前的内容进行加工处理,然后返回使用
  // 4 当mode & 8成立是直接将value返回(commonJS )
  // 5 当mode & 4成立时直接将value返回(esModule)
  // 6 如果都不成立,还是要继续处理value,定义一个 ns {}
  //  6-1如果拿到的value是一个可以直接使用的内容,例如是一个字符串,将它挂载到ns的default属性上
  //  6-2如果是一个对象,遍历key添加对应属性

  // 11 定义 t 方法,用于加载指定 value 的模块内容,之后对内容进行处理再返回
  __webpack_require__.t = function (value, mode) {
    // 01 加载 value 对应的模块内容( value 一般就是模块 id )
    // 加载之后的内容又重新赋值给 value 变量
    if (mode & 1) {
      value = __webpack_require__(value)
    }

    if (mode & 8) {  // 加载了可以直接返回使用的内容
      return value
    }

    if ((mode & 4) && typeof value === 'object' && value && value.__esModule) {
      return value
    }

    // 如果 8 和 4 都没有成立则需要自定义 ns 来通过 default 属性返回内容
    let ns = Object.create(null)

    __webpack_require__.r(ns)

    Object.defineProperty(ns, 'default', { enumerable: true, value: value })

    if (mode & 2 && typeof value !== 'string') {
      for (var key in value) {
        __webpack_require__.d(ns, key, function (key) {
          return value[key]
        }.bind(null, key))
      }
    }

    return ns
  }

  // 09 定义 P 属性,用于保存资源访问路径
  __webpack_require__.p = ""


    // 懒加载start======

    // 标识chunk是否完成加载
    // 0 代表加载完成
    // undefine 代表没有加载
    // Promise 代表加载中
    let installedChunks = {
      main: 0
  }

  // webpackJsonpCallBack实现:合并模块定义,改变promise状态执行后续行 
  function webpackJsonpCallBack(data) {
      // 获取需要被动态加载的模块id
      let chunkIds = data[0]
      // 获取需要被动态加载的模块依赖关系对象
      let moreModules = data[1]

      let chunkld, resolves =[]
      // 循环判断chunklds里对应的模块内容是否已经完成了加载
      for (let i = 0; i < chunklds.length; i++) {
          chunkld =  chunkld[i]
          if (Object.prototype.hasOwnProperty.call(inStalledChunksₜ, chunkld) && inStalledChunks[chunkld]) {
              // 0里面存储的是resolve 1是reject 2是promise本身
              resolves.push(installedChunks[chunkld][0])
          }
          // 加载完成
          installedChunks[chunkld] = 0
      }

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

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

  // hook push方法
  let jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []
  let oldJsonp = jsonpArray.push.bind(jsonpArray)
  jsonpArray.push = webpackJsonpCallBack


  // 生成路径
  function jsonScriptSrc(chunkId) {
      return __webpack_require__.p + "" + chunkId + '.built.js'
  }

  // 使用json加载内容,
  __webpack_require__.e = function(chunkId) {
      let promises = []

      let installedChunkData = installedChunks[chunkId]

      // 判断是否完成加载
      if (installedChunkData != 0) {
          // 非0, 非undefined, 代表 Promise 加载中
          if (installedChunkData) {
              // 2才是真正存储的promise
              promises.push(installedChunkData[2])
          } else {
              // 没有加载,就创建一个promise
              let promise = new Promise((resolve, reject) => {
                  installedChunkData = installedChunks[chunkId] = [resolve, reject]
              })
              
              promise.push(installedChunkData[2] = promise)

              // 创建标签
              let script = document.createElement('script')
              script.src = jsonScriptSrc(chunkId)
              document.head.appendChild(script)
          }
      }

      return Promise.all(promises);
  }
  // 懒加载end======

  // 10 调用 __webpack_require__ 方法执行模块导入与加载操作
  return __webpack_require__(__webpack_require__.s = './src/index.js')

})
  ({/**/})

相关文章

  • webpack基础源码 & 懒加载

  • 用webpack实现模块懒加载、预取/预加载

    模块懒加载本身与webpack没有关系,webpack可以让懒加载的模块代码打包到单独的文件中,实现真正的按需加载...

  • webpack vue 异步组件加载 按需加载

    webpack分包:减少首屏加载时间-路由懒加载 使用webpack中的syntax-dynamic-import...

  • webpack打包代码实现

    webpack模块加载 异步模块加载 通过 import()实现指定模块的懒加载操作 懒加载的核心原理就是创建js...

  • webpack打包优化 - 懒加载

    webpack 懒加载 分割代码会产生chunk,异步加载的时候也会产生chunk 引入动态数据 -> 懒加载(当...

  • 懒加载

    知识点 webpack代码拆分动态倒入懒加载 1.懒加载 懒加载我们都知道,不即时加载所有资源,而是在需要的时候才...

  • Vue路由异步组件

    vue异步组件和懒加载可以优化vue的性能 一、 原理 利用webpack对代码进行分割是懒加载的前提,懒加载就是...

  • vue 懒加载

    懒加载 为什么需要懒加载? 像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常的大...

  • webpack 懒加载

    使用 import 的动态引入方式,实现代码分割并异步的加载相应的内容具体步骤如下 1、安装 @babel/plu...

  • vue异步组件 懒加载& webpack按需加载——性能优化

    利用webpack对代码进行分割是懒加载的前提,懒加载就是异步调用组件,需要时候才下载(按需加载)。 为什么需要懒...

网友评论

      本文标题:webpack基础源码 & 懒加载

      本文链接:https://www.haomeiwen.com/subject/cgrihrtx.html