深入理解 webpack 文件打包机制(小结)(4)
执行 npm run build:multiple 即可查看打包内容,首先来看下 manifest 如何做初始化工作(精简版)?
// dist/mainifest.xxxx.js (function(modules) { window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules) { var moduleId, chunkId, i = 0, callbacks = []; for(;i < chunkIds.length; i++) { chunkId = chunkIds[i]; if(installedChunks[chunkId]) callbacks.push.apply(callbacks, installedChunks[chunkId]); installedChunks[chunkId] = 0; } for(moduleId in moreModules) { if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { modules[moduleId] = moreModules[moduleId]; } } while(callbacks.length) callbacks.shift().call(null, __webpack_require__); if(moreModules[0]) { installedModules[0] = 0; return __webpack_require__(0); } }; var installedModules = {}; var installedChunks = { 4:0 }; function __webpack_require__(moduleId) { // 和单文件一致 } __webpack_require__.e = function requireEnsure(chunkId, callback) { if(installedChunks[chunkId] === 0) return callback.call(null, __webpack_require__); if(installedChunks[chunkId] !== undefined) { installedChunks[chunkId].push(callback); } else { installedChunks[chunkId] = [callback]; var head = document.getElementsByTagName('head')[0]; var script = document.createElement('script'); script.type = 'text/javascript'; script.charset = 'utf-8'; script.async = true; script.src = __webpack_require__.p + "" + chunkId + "." + ({"0":"pageA","1":"pageB","3":"vendor"}[chunkId]||chunkId) + "." + {"0":"e72ce7d4","1":"69f6bbe3","2":"9adbbaa0","3":"53fa02a7"}[chunkId] + ".js"; head.appendChild(script); } }; })([]);
与单文件内容一致,定义了一个自执行函数,因为它不包含任何模块,所以传入一个空数组。除了定义了 __webpack_require__ ,还另外定义了两个函数用来进行加载模块。
首先讲解代码前需要理解两个概念,分别是 module 和 chunk
- chunk 代表生成后 js 文件,一个 chunkId 对应一个打包好的 js 文件(一共五个),从这段代码可以看出,manifest 的 chunkId 为 4,并且从代码中还可以看到:0-3 分别对应 pageA, pageB, 异步 utilC, vendor 公共模块文件,这也就是我们为什么不能将这段代码放在 vendor 的原因,因为文件的 hash 值会变。内容变了,vendor 生成的 hash 值也就变了。
- module 对应着模块,可以简单理解为打包前每个 js 文件对应一个模块,也就是之前 __webpack_require__ 加载的模块,同样的使用数组下标作为 moduleId 且是唯一不重复的。
那么为什么要区分 chunk 和 module 呢?
首先使用 installedChunks 来保存每个 chunkId 是否被加载过,如果被加载过,则说明该 chunk 中所包含的模块已经被放到了 modules 中,注意是 modules 而不是 installedModules。我们先来简单看一下 vendor chunk 打包出来的内容。