加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

浅谈 Webpack 背后的运行机制

发布时间:2019-08-15 21:36:41 所属栏目:优化 来源:Alan
导读:副标题#e# 在平时开发中我们经常会用到 Webpack这个时下最流行的前端打包工具。它打包开发代码,输出能在各种浏览器运行的代码,提升了开发至发布过程的效率。 我们知道一份 Webpack配置文件主要包含入口( entry)、输出文件( output)、模式、加载器( Loader

可以看到 webpackBootstrap 的函数体部分增加了一些内容,参数部分移除了 "./src/utils/math.js" 模块。跟着包裹函数的执行顺序,我们先聚焦到 「JSONP 初始化」部分:

  1. // 存储 jsonp 的数组,首次运行为 [] 
  2. var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []; 
  3. // 保存 jsonpArray 的 push 函数,首次运行为 Array.prototype.push 
  4. var oldJsonpFunction = jsonpArray.push.bind(jsonpArray); 
  5. // 将 jsonpArray 的 push 重写为 webpackJsonpCallback (加载其他 chunk 后的回调函数) 
  6. jsonpArray.push = webpackJsonpCallback; 
  7. // 将 jsonpArray 重置为正常数组,push 重置为 Array.prototype.push 
  8. jsonpArray = jsonpArray.slice(); 
  9. // 由于 jsonpArray 为 [],不做任何事 
  10. for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]); 
  11. // Array.prototype.push 
  12. var parentJsonpFunction = oldJsonpFunction; 

初始化结束后,变化就是 window 上挂载了一个 webpackJsonp 数组,它的值为 [];此外,这个数组的 push 被改写为 webpackJsonpCallback 函数,我们在后面会提到这些准备工作的作用。

接着是 __webpack_require__ 入口模块,由于 __webpack_require__ 函数没有改变,我们继续观察入口模块执行函数有了什么变化。

显然, import( ../utils/math.js ) 被转化为 __webpack_require__.e(0).then(__webpack_require__.bind(null,"./src/utils/math.js"))。0 是 ./src/utils/math.js 所在 chunk 的 id,「同步加载模块」的逻辑拆分成了「先加载 chunk,完成后再加载模块」。

我们翻到 __webpack_require__.e 的定义位置:

  1. __webpack_require__.e = function requireEnsure(chunkId) { 
  2. var promises = []; 
  3. // installedChunks 是在 webpackBootstrap 中维护的 chunk 缓存 
  4. var installedChunkData = installedChunks[chunkId]; 
  5. // chunk 未加载 
  6. if(installedChunkData !== 0) { 
  7. // installedChunkData 为 promise 表示 chunk 加载中 
  8. if(installedChunkData) { 
  9. promises.push(installedChunkData[2]); 
  10. } else { 
  11. /*** 首次加载 chunk: ***/ 
  12. // 初始化 promise 对象 
  13. var promise = new Promise(function(resolve, reject) { 
  14. installedChunkData = installedChunks[chunkId] = [resolve, reject]; 
  15. }); 
  16. promises.push(installedChunkData[2] = promise); 
  17. // 创建 script 标签加载 chunk 
  18. var head = document.getElementsByTagName( head )[0]; 
  19. var script = document.createElement( script ); 
  20. var onScriptComplete; 
  21. // ... 省略一些 script 属性设置 
  22. // src 根据 publicPath 和 chunkId 拼接 
  23. script.src = jsonpScriptSrc(chunkId); 
  24. // 加载结束回调函数,处理 script 加载完成、加载超时、加载失败的情况 
  25. onScriptComplete = function (event) { 
  26. script.onerror = script.onload = null; // 避免 IE 内存泄漏问题 
  27. clearTimeout(timeout); 
  28. var chunk = installedChunks[chunkId]; 
  29. // 处理 script 加载完成,但 chunk 没有加载完成的情况 
  30. if(chunk !== 0) { 
  31. // chunk 加载中 
  32. if(chunk) { 
  33. var errorType = event && (event.type === load ? missing : event.type); 
  34. var realSrc = event && event.target && event.target.src; 
  35. var error = new Error( Loading chunk + chunkId + failed. 
  36. ( + errorType + : + realSrc + ) ); 
  37. error.type = errorType; 
  38. error.request = realSrc; 
  39. // reject(error) 
  40. chunk[1](error); 
  41. // 统一将没有加载的 chunk 标记为未加载 
  42. installedChunks[chunkId] = undefined; 
  43. }; 
  44. // 设置 12 秒超时时间 
  45. var timeout = setTimeout(function(){ 
  46. onScriptComplete({ type: timeout , target: script }); 
  47. }, 120000); 
  48. script.onerror = script.onload = onScriptComplete; 
  49. head.appendChild(script); 
  50. /*** 首次加载 chunk ***/ 
  51. return Promise.all(promises); 
  52. }; 

看起来有点长,我们一步步剖析,先从第一行和最后一行来看,整个函数将异步加载的过程封装到了 promise 中,最终导出。

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读