webpack 代码分割一点事

admin 2018-12-07 阅读


webpack 俨然已经成为前端最主流的构建工具,其功能多种多样,我们今天就来分析下关于代码分割这部分的一点事,并在最后讲述如何实现在webpack编译出的代码里手动添加一个异步chunk。

什么是chunkId与moduleId?

每个chunkId对应的是一个js文件,每个moduleId对应的是一个个js文件的内容的模块(一个js文件里面可以require多个资源,每个资源分配一个moduleId),所以它两的关系就是一个chunkId可能由很多个moduleId组成。

在webpack 编译出来的代码有定义了一个名称为__webpack_require__的函数,这个函数就是用来加载模块的,所以它的参数自然就是moduleId,如下:

/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}

  

这里我们要讲代码分割,那自然也要看看webpack编译出来的代码是通过什么方法进行异步加载js文件的,从代码中我们可以找到一个名为requireEnsure的函数,这个函数便是来做这个事情的,那自然而然它的参数就是chunkId了,如下:

/******/ 	__webpack_require__.e = function requireEnsure(chunkId) {
/******/ 		var installedChunkData = installedChunks[chunkId];
/******/ 		if(installedChunkData === 0) {
/******/ 			return new Promise(function(resolve) { resolve(); });
/******/ 		}
/******/
/******/ 		// a Promise means "currently loading".
/******/ 		if(installedChunkData) {
/******/ 			return installedChunkData[2];
/******/ 		}
/******/
/******/ 		// setup Promise in chunk cache
/******/ 		var promise = new Promise(function(resolve, reject) {
/******/ 			installedChunkData = installedChunks[chunkId] = [resolve, reject];
/******/ 		});
/******/ 		installedChunkData[2] = promise;
/******/
/******/ 		// start chunk loading
/******/ 		var head = document.getElementsByTagName('head')[0];
/******/ 		var script = document.createElement('script');
/******/ 		script.type = 'text/javascript';
/******/ 		script.charset = 'utf-8';
/******/ 		script.async = true;
/******/ 		script.timeout = 120000;
/******/
/******/ 		if (__webpack_require__.nc) {
/******/ 			script.setAttribute("nonce", __webpack_require__.nc);
/******/ 		}
/******/ 		script.src = __webpack_require__.p + "" + ({"0":"home-chunk","1":"users-chunk","2":"about-chunk"}[chunkId]||chunkId) + ".js";
/******/ 		var timeout = setTimeout(onScriptComplete, 120000);
/******/ 		script.onerror = script.onload = onScriptComplete;
/******/ 		function onScriptComplete() {
/******/ 			// avoid mem leaks in IE.
/******/ 			script.onerror = script.onload = null;
/******/ 			clearTimeout(timeout);
/******/ 			var chunk = installedChunks[chunkId];
/******/ 			if(chunk !== 0) {
/******/ 				if(chunk) {
/******/ 					chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));
/******/ 				}
/******/ 				installedChunks[chunkId] = undefined;
/******/ 			}
/******/ 		};
/******/ 		head.appendChild(script);
/******/
/******/ 		return promise;
/******/ 	};

从上面代码我们可以看出requireEnsure其实就是通过动态创建script标签来加载js文件的,但是这里不是每次访问这个js文件,都进行创建script请求的,在创建script前,requireEnsure会先通过installedChunks读取下是否已经有缓存了,如果有缓存直接使用便可。

一个Demo

干说原理,都抽象啊,还是从一个demo来分析,你轻松我也轻松

声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。