webpack 懒加载原理

Posted 前端精髓

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack 懒加载原理相关的知识,希望对你有一定的参考价值。

分析

__webpack_require__.f = 
__webpack_require__.e = (chunkId) => 
  return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => 
    // promises = [], key = "j"
    // chunkId = src_title_js, promises = []
    __webpack_require__.f[key](chunkId, promises);
    return promises;
  , []));
;

var installedChunks = 
  "main": 0
;
__webpack_require__.f.j = (chunkId, promises) => 
  var installedChunkData = installedChunks[chunkId]
  if(installedChunkData) 
    promises.push(installedChunkData[2]);
   else 
    var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
		promises.push(installedChunkData[2] = promise);
    __webpack_require__.l(url);
  


__webpack_require__.l = (url) => 
  var script;
  script = document.createElement('script');
  script.src = url;
  document.head.appendChild(script);

当懒加载的时候会调用push方法

// install a JSONP callback for chunk loading
var webpackJsonpCallback = (parentChunkLoadingFunction, data) => 
  var [chunkIds, moreModules, runtime] = data;
  var moduleId, chunkId, i = 0;
  for(moduleId in moreModules) 
    if(__webpack_require__.o(moreModules, moduleId)) 
      // 把返回的模块定义合并到当前的模块定义里面
      __webpack_require__.m[moduleId] = moreModules[moduleId];
    
  
  if(runtime) var result = runtime(__webpack_require__);
  if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
  for(;i < chunkIds.length; i++) 
    chunkId = chunkIds[i];
    if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) 
      // installedChunks[chunkId][0] 是 resolve 方法,调用之后就加载成功
      installedChunks[chunkId][0]();
    
    installedChunks[chunkIds[i]] = 0;
  



var chunkLoadingGlobal = self["webpackChunkwebpack5"] = self["webpackChunkwebpack5"] || [];
chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));

源码

src_titile_js.bundle.js

(self["webpackChunkwebpack5"] = self["webpackChunkwebpack5"] || []).push([["src_title_js"],

/***/ "./src/title.js":
/*!**********************!*\\
  !*** ./src/title.js ***!
  \\**********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => 

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, 
/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ );
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ('hello world');

/***/ )

]);

bundle.js

(() =>  // webpackBootstrap
	var __webpack_modules__ = ();
/************************************************************************/
	// The module cache
	var __webpack_module_cache__ = ;
	
	// The require function
	function __webpack_require__(moduleId) 
		// Check if module is in cache
		var cachedModule = __webpack_module_cache__[moduleId];
		if (cachedModule !== undefined) 
			return cachedModule.exports;
		
		// Create a new module (and put it into the cache)
		var module = __webpack_module_cache__[moduleId] = 
			// no module.id needed
			// no module.loaded needed
			exports: 
		;
	
		// Execute the module function
		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
	
		// Return the exports of the module
		return module.exports;
	
	
	// expose the modules object (__webpack_modules__)
	__webpack_require__.m = __webpack_modules__;
	
/************************************************************************/
	/* webpack/runtime/define property getters */
	(() => 
		// define getter functions for harmony exports
		__webpack_require__.d = (exports, definition) => 
			for(var key in definition) 
				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) 
					Object.defineProperty(exports, key,  enumerable: true, get: definition[key] );
				
			
		;
	)();
	
	/* webpack/runtime/ensure chunk */
	(() => 
		__webpack_require__.f = ;
		// This file contains only the entry chunk.
		// The chunk loading function for additional chunks
		__webpack_require__.e = (chunkId) => 
			return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => 
				__webpack_require__.f[key](chunkId, promises);
				return promises;
			, []));
		;
	)();
	
	/* webpack/runtime/get javascript chunk filename */
	(() => 
		// This function allow to reference async chunks
		__webpack_require__.u = (chunkId) => 
			// return url for filenames based on template
			return "" + chunkId + ".bundle.js";
		;
	)();
	
	/* webpack/runtime/global */
	(() => 
		__webpack_require__.g = (function() 
			if (typeof globalThis === 'object') return globalThis;
			try 
				return this || new Function('return this')();
			 catch (e) 
				if (typeof window === 'object') return window;
			
		)();
	)();
	
	/* webpack/runtime/hasOwnProperty shorthand */
	(() => 
		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
	)();
	
	/* webpack/runtime/load script */
	(() => 
		var inProgress = ;
		var dataWebpackPrefix = "webpack5:";
		// loadScript function to load a script via script tag
		__webpack_require__.l = (url, done, key, chunkId) => 
			if(inProgress[url])  inProgress[url].push(done); return; 
			var script, needAttach;
			if(key !== undefined) 
				var scripts = document.getElementsByTagName("script");
				for(var i = 0; i < scripts.length; i++) 
					var s = scripts[i];
					if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key)  script = s; break; 
				
			
			if(!script) 
				needAttach = true;
				script = document.createElement('script');
		
				script.charset = 'utf-8';
				script.timeout = 120;
				if (__webpack_require__.nc) 
					script.setAttribute("nonce", __webpack_require__.nc);
				
				script.setAttribute("data-webpack", dataWebpackPrefix + key);
				script.src = url;
			
			inProgress[url] = [done];
			var onScriptComplete = (prev, event) => 
				// avoid mem leaks in IE.
				script.onerror = script.onload = null;
				clearTimeout(timeout);
				var doneFns = inProgress[url];
				delete inProgress[url];
				script.parentNode && script.parentNode.removeChild(script);
				doneFns && doneFns.forEach((fn) => (fn(event)));
				if(prev) return prev(event);
			
			;
			var timeout = setTimeout(onScriptComplete.bind(null, undefined,  type: 'timeout', target: script ), 120000);
			script.onerror = onScriptComplete.bind(null, script.onerror);
			script.onload = onScriptComplete.bind(null, script.onload);
			needAttach && document.head.appendChild(script);
		;
	)();
	
	/* webpack/runtime/make namespace object */
	(() => 
		// define __esModule on exports
		__webpack_require__.r = (exports) => 
			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) 
				Object.defineProperty(exports, Symbol.toStringTag,  value: 'Module' );
			
			Object.defineProperty(exports, '__esModule',  value: true );
		;
	)();
	
	/* webpack/runtime/publicPath */
	(() => 
		var scriptUrl;
		if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + "";
		var document = __webpack_require__.g.document;
		if (!scriptUrl && document) 
			if (document.currentScript)
				scriptUrl = document.currentScript.src
			if (!scriptUrl) 
				var scripts = document.getElementsByTagName("script");
				if(scripts.length) scriptUrl = scripts[scripts.length - 1].src
			
		
		// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration
		// or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.
		if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");
		scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\\?.*$/, "").replace(/\\/[^\\/]+$/, "/");
		__webpack_require__.p = scriptUrl;
	)();
	
	/* webpack/runtime/jsonp chunk loading */
	(() => 
		// no baseURI
		
		// object to store loaded and loading chunks
		// undefined = chunk not loaded, null = chunk preloaded/prefetched
		// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
		var installedChunks = 
			"main": 0
		;
		
		__webpack_require__.f.j = (chunkId, promises) => 
				// JSONP chunk loading for javascript
				var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
				if(installedChunkData !== 0)  // 0 means "already installed".
		
					// a Promise means "currently loading".
					if(installedChunkData) 
						promises.push(installedChunkData[2]);
					 else 
						if(true)  // all chunks have JS
							// setup Promise in chunk cache
							var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
							promises.push(installedChunkData[2] = promise);
		
							// start chunk loading
							var url = __webpack_require__.p + __webpack_require__.u(chunkId);
							// create error before stack unwound to get useful stacktrace later
							var error = new Error();
							var loadingEnded = (event) => 
								if(__webpack_require__.o(installedChunks, chunkId)) 
									installedChunkData = installedChunks[chunkId];
									if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
									if(installedChunkData) 
										var errorType = event && (event.type === 'load' ? 'missing' : event.type);
										var realSrc = event && event.target && event.target.src;
										error.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';
										error.name = 'ChunkLoadError';
										error.type = errorType;
										error.request = realSrc;
										installedChunkData[1](error);
									
								
							;
							__webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
						 else installedChunks[chunkId] = 0;
					
				
		;
		
		// install a JSONP callback for chunk loading
		var webpackJsonpCallback = (parentChunkLoadingFunction, data) => 
			var [chunkIds, moreModules, runtime] = data;
			// add "moreModules" to the modules object,
			// then flag all "chunkIds" as loaded and fire callback
			var moduleId, chunkId, i = 以上是关于webpack 懒加载原理的主要内容,如果未能解决你的问题,请参考以下文章

Fragment 数据懒加载及原理

webpack4 系列教程: 单页面解决方案--代码分割和懒加载

使用Webpack的代码拆分在Vue中进行懒加载

第1215期基于Webpack4使用懒加载分离打包React代码

vue+webpack2实现路由的懒加载

webpack性能优化:分隔/分包/异步加载+组件与路由懒加载