加入收藏 | 设为首页 | 会员中心 | 我要投稿 新余站长网 (https://www.0790zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

浅谈 Webpack 背后的运行机制

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

执行顺序是:入口模块 -> 工具模块 -> 入口模块。入口模块中首先就通过 __webpack_require__("./src/utils/math.js") 拿到了工具模块的 exports 对象。再看工具模块, ES 导出语法转化成了 __webpack_require__.d(__webpack_exports__, [key], [getter]),而 __webpack_require__.d 函数的定义在 webpackBootstrap 内:

  1. // 定义 exports 对象导出的属性。 
  2. __webpack_require__.d = function (exports, name, getter) { 
  3. // 如果 exports (不含原型链上)没有 [name] 属性,定义该属性的 getter。 
  4. if (!__webpack_require__.o(exports, name)) { 
  5. Object.defineProperty(exports, name, { 
  6. enumerable: true, 
  7. get: getter 
  8. }); 
  9. }; 
  10. // 包装 Object.prototype.hasOwnProperty 函数。 
  11. __webpack_require__.o = function (object, property) { 
  12. return Object.prototype.hasOwnProperty.call(object, property); 
  13. }; 

可见 __webpack_require__.d 其实就是 Object.defineProperty 的简单包装.

引用工具模块导出的变量后,入口模块再执行它剩余的部分。至此,Webpack 基本的模块执行过程就结束了。

好了,我们用流程图总结一下 Webpack 模块的加载思路:

浅谈 Webpack 背后的运行机制

异步加载

有上面的打包我们发现将不同的打包进一个 main.js 文件。 main.js 会集中消耗太多网络资源,导致用户需要等待很久才可以开始与网页交互。

一般的解决方式是:根据需求降低首次加载文件的体积,在需要时(如切换前端路由器,交互事件回调)异步加载其他文件并使用其中的模块。

Webpack 推荐用 ES import() 规范来异步加载模块,我们根据 ES 规范修改一下入口模块的 import 方式,让其能够异步加载模块:

  1. src/index.js 
  2.  
  3. console.log( Hello webpack! );window.setTimeout(() => {  import( ./utils/math ).then(mathUtil => {  console.log( 1 + 2:   + mathUtil.plus(1, 2));  });}, 2000); 

工具模块 (src/utils/math.js)依然不变,在 webpack 配置里,我们指定一下资源文件的公共资源路径 (publicPath),后面的探索过程中会遇到。

  1. const path = require( path ); 
  2. const MyPlugin = require( ./src/MyPlugin.js ) 
  3.  
  4.  
  5. module.exports = { 
  6. mode: development , 
  7. devtool: source-map , 
  8. entry: ./src/index.js , 
  9. output: { 
  10. path: path.resolve(__dirname, dist ), 
  11. publicPath: /dist/ 
  12. }, 
  13. plugins:[ 
  14. new MyPlugin() 
  15. }; 

接着执行一下打包,可以看到除了 dist/main.js 外,又多了一个 dist/0.js ./src/utils/math.js。模块从 main chunk 迁移到了 0 chunk 中。而与 demo1 不同的是, main chunk 中添加了一些用于异步加载的代码,我们概览一下:

  1. // webpackBootstrap 
  2. (function (modules) { 
  3. // 加载其他 chunk 后的回调函数 
  4. function webpackJsonpCallback(data) { 
  5. // ... 
  6. // ... 
  7. // 用于缓存 chunk 的加载状态,0 为已加载 
  8. var installedChunks = { 
  9. "main": 0 
  10. }; 
  11. // 拼接 chunk 的请求地址 
  12. function jsonpScriptSrc(chunkId) { 
  13. // ... 
  14. // 同步 require 函数,内容不变 
  15. function __webpack_require__(moduleId) { 
  16. // ... 
  17. // 异步加载 chunk,返回封装加载过程的 promise 
  18. __webpack_require__.e = function requireEnsure(chunkId) { 
  19. // ... 
  20. // ... 
  21. // defineProperty 的包装,内容不变 
  22. __webpack_require__.d = function (exports, name, getter) {} 
  23. // ... 
  24. // 根据配置文件确定的 publicPath 
  25. __webpack_require__.p = "/dist/"; 
  26. /**** JSONP 初始化 ****/ 
  27. var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []; 
  28. var oldJsonpFunction = jsonpArray.push.bind(jsonpArray); 
  29. jsonpArray.push = webpackJsonpCallback; 
  30. jsonpArray = jsonpArray.slice(); 
  31. for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]); 
  32. var parentJsonpFunction = oldJsonpFunction; 
  33. /**** JSONP 初始化 ****/ 
  34. return __webpack_require__(__webpack_require__.s = "./src/index.js"); 
  35. })({ 
  36. "./src/index.js": (function(module, exports, __webpack_require__) { 
  37. document.write( Hello webpack! ); 
  38. window.setTimeout(() => { 
  39. __webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./utils/math */ "./src/utils/math.js")).then(mathUtil => { 
  40. console.log( 1 + 2: + mathUtil.plus(1, 2)); 
  41. }); 
  42. }, 2000); 
  43. }) 
  44. }) 

(编辑:新余站长网)

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

热点阅读