nodejs、webpack都是openjs的项目,它的支持者中也是一大票美国公司,中国的自主研发的产品在哪儿,仅仅在在这一块,核心技术在哪儿?令人不快,只能学习借鉴。
接着之前的内容,在编译后的内容中,webpackBootstrap是在哪儿生成的呢?
这涉及到了chunk的业务。
根据module和chunk.time获得翻译的结果,如下:
再往前倒,看这个chunk是怎么来的。
往前倒,查看它的引用会发现,它是renderMain下的 inlineModules,如下:
那这个inlineModules是从哪儿来的?关键是要搞清楚,这个m是如何从chunk中转换的?再往前倒:
通过chunk获取对应ChunkGraphChunk的keys。这里有一个关键的点是如下内容:
_getChunkGraphChunk(chunk) {
let cgc = this._chunks.get(chunk);
if (cgc === undefined) {
cgc = new ChunkGraphChunk();
this._chunks.set(chunk, cgc);
}
return cgc;
}
这里的 this._chunks 是 new WeakMap() ,它实际上应该是作为了缓存,当再次使用 chunk 作为键的时候从 this._chunks 中通过 get 取值。
到这一步可以看到它对应的inlineModules下的条目对应的 _source 的值还没有被转换,它还是main.js的原生内容:
接着找这个源码编译的具体位置,到这一步还没有被编译,还是原生的内容:
从这个hooks.renderStartup这个名字好像能看出来点意思,渲染启动的钩子方法。
但是这里只是添加到source,并没有调用钩子函数。而是执行完后回到了Compilation,如下:
alreadyWrittenFiles从名字上来看是已经写好的文件,但是它的用处是什么,得看后面的情况:
读取资源:
这个能看到提供解析的文件路径,但是具体解析的流程还是没找到,这就很头大:
这个地方会出现style-loader
会反复进入到这个buildModule模块:
再往回倒,看这个 this._chunks 在赋值过程中发生的事情。在这一步骤会聚焦在 Compliation下的seal方法中:
其中getModule如下:
查找引用模块的依赖项:
connection下的module的_source如下:
从这个到最后的输出到bundle.js中的内容还是有区别的
这一点比较重要。这其实也给看源码提供了一个思路,就是说当我们想要知道某一变量的状态的时候,可以从两个维度去考虑,一个是流程,一个是它本身。如果流程上无法判断它的衍变过程的情况下,就直接定位它本身通过逆推去寻找线索。
通过这种方式可以定位最终生成的bundle.js内容的位置,如下:
这里为了方便调试,在当前webpack-resource/lib/RawSource.js下的RawSource构造函数中增加了一个console.log(value)的输出,这样在中断中能够更容易得到对应的结果,如上图。
从RawSource向上一步推断,可以看到output.code就是最终在bundle.js中输出的内容:
这一步很关键,这个钩子在什么情况下注册的,它给compilation对象的钩子中processAssets添加处理逻辑:
在webpack下调用的位置,也就是说这里除了使用TerserPlugin进行处理之外没有别的逻辑:
最后确定,在terser-webpack-pluginx/dist/index.js下的:
对应于webpack/Compilation/lib/Compilation中的:
当被拦截器拦截后执行 this.optimize。
执行到如下这一步的时候,内容就变成压缩处理后的内容,如下:
到这一步基本上搞清楚了,它的输入和输出的转换。但是为什么从es6就转换成了es5,在这里webpack起到了什么作用,loader在哪个环节有意义了,还是没有看到。要看的是它的webpack的函数有什么意义?
把上图中的options.input的内容拿出来看一看:
"/******/ (() => { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 329:\n/***/ ((module) => {\n\n\nfunction init(content)\n{\n window.document.getElementById('app').innerHTML= content;\n}\n\n\n\nmodule.exports=init;\n\n/***/ }),\n\n/***/ 313:\n/***/ ((module, __webpack_exports__, __webpack_require__) => {\n\n\"use strict\";\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"Z\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(645);\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);\n// Imports\n\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \"#app{color:red;}\", \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n/***/ }),\n\n/***/ 645:\n/***/ ((module) => {\n\n\"use strict\";\n\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = []; // return the list of modules as css string\n\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n\n content += cssWithMappingToString(item);\n\n if (needLayer) {\n content += \"}\";\n }\n\n if (item[2]) {\n content += \"}\";\n }\n\n if (item[4]) {\n content += \"}\";\n }\n\n return content;\n }).join(\"\");\n }; // import a list of modules into the list\n\n\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n\n var alreadyImportedModules = {};\n\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n\n list.push(item);\n }\n };\n\n return list;\n};\n\n/***/ }),\n\n/***/ 81:\n/***/ ((module) => {\n\n\"use strict\";\n\n\nmodule.exports = function (i) {\n return i[1];\n};\n\n/***/ }),\n\n/***/ 181:\n/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {\n\n\"use strict\";\n__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(379);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(795);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(569);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(565);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(216);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(589);\n/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(313);\n\n \n \n \n \n \n \n \n \n \n\nvar options = {};\n\noptions.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());\noptions.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());\n\n options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, \"head\");\n \noptions.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());\noptions.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());\n\nvar update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__/* [\"default\"] */ .Z, options);\n\n\n\n\n /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__/* [\"default\"] */ .Z && _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__/* [\"default\"].locals */ .Z.locals ? _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__/* [\"default\"].locals */ .Z.locals : undefined);\n\n\n/***/ }),\n\n/***/ 379:\n/***/ ((module) => {\n\n\"use strict\";\n\n\nvar stylesInDOM = [];\n\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n\n for (var i = 0; i < stylesInDOM.length; i++) {\n if (stylesInDOM[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n\n return result;\n}\n\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var indexByIdentifier = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3],\n supports: item[4],\n layer: item[5]\n };\n\n if (indexByIdentifier !== -1) {\n stylesInDOM[indexByIdentifier].references++;\n stylesInDOM[indexByIdentifier].updater(obj);\n } else {\n var updater = addElementStyle(obj, options);\n options.byIndex = i;\n stylesInDOM.splice(i, 0, {\n identifier: identifier,\n updater: updater,\n references: 1\n });\n }\n\n identifiers.push(identifier);\n }\n\n return identifiers;\n}\n\nfunction addElementStyle(obj, options) {\n var api = options.domAPI(options);\n api.update(obj);\n\n var updater = function updater(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\n return;\n }\n\n api.update(obj = newObj);\n } else {\n api.remove();\n }\n };\n\n return updater;\n}\n\nmodule.exports = function (list, options) {\n options = options || {};\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDOM[index].references--;\n }\n\n var newLastIdentifiers = modulesToDom(newList, options);\n\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n\n var _index = getIndexByIdentifier(_identifier);\n\n if (stylesInDOM[_index].references === 0) {\n stylesInDOM[_index].updater();\n\n stylesInDOM.splice(_index, 1);\n }\n }\n\n lastIdentifiers = newLastIdentifiers;\n };\n};\n\n/***/ }),\n\n/***/ 569:\n/***/ ((module) => {\n\n\"use strict\";\n\n\nvar memo = {};\n/* istanbul ignore next */\n\nfunction getTarget(target) {\n if (typeof memo[target] === \"undefined\") {\n var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself\n\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n\n memo[target] = styleTarget;\n }\n\n return memo[target];\n}\n/* istanbul ignore next */\n\n\nfunction insertBySelector(insert, style) {\n var target = getTarget(insert);\n\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n\n target.appendChild(style);\n}\n\nmodule.exports = insertBySelector;\n\n/***/ }),\n\n/***/ 216:\n/***/ ((module) => {\n\n\"use strict\";\n\n\n/* istanbul ignore next */\nfunction insertStyleElement(options) {\n var element = document.createElement(\"style\");\n options.setAttributes(element, options.attributes);\n options.insert(element, options.options);\n return element;\n}\n\nmodule.exports = insertStyleElement;\n\n/***/ }),\n\n/***/ 565:\n/***/ ((module, __unused_webpack_exports, __webpack_require__) => {\n\n\"use strict\";\n\n\n/* istanbul ignore next */\nfunction setAttributesWithoutAttributes(styleElement) {\n var nonce = true ? __webpack_require__.nc : 0;\n\n if (nonce) {\n styleElement.setAttribute(\"nonce\", nonce);\n }\n}\n\nmodule.exports = setAttributesWithoutAttributes;\n\n/***/ }),\n\n/***/ 795:\n/***/ ((module) => {\n\n\"use strict\";\n\n\n/* istanbul ignore next */\nfunction apply(styleElement, options, obj) {\n var css = \"\";\n\n if (obj.supports) {\n css += \"@supports (\".concat(obj.supports, \") {\");\n }\n\n if (obj.media) {\n css += \"@media \".concat(obj.media, \" {\");\n }\n\n var needLayer = typeof obj.layer !== \"undefined\";\n\n if (needLayer) {\n css += \"@layer\".concat(obj.layer.length > 0 ? \" \".concat(obj.layer) : \"\", \" {\");\n }\n\n css += obj.css;\n\n if (needLayer) {\n css += \"}\";\n }\n\n if (obj.media) {\n css += \"}\";\n }\n\n if (obj.supports) {\n css += \"}\";\n }\n\n var sourceMap = obj.sourceMap;\n\n if (sourceMap && typeof btoa !== \"undefined\") {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n } // For old IE\n\n /* istanbul ignore if */\n\n\n options.styleTagTransform(css, styleElement, options.options);\n}\n\nfunction removeStyleElement(styleElement) {\n // istanbul ignore if\n if (styleElement.parentNode === null) {\n return false;\n }\n\n styleElement.parentNode.removeChild(styleElement);\n}\n/* istanbul ignore next */\n\n\nfunction domAPI(options) {\n var styleElement = options.insertStyleElement(options);\n return {\n update: function update(obj) {\n apply(styleElement, options, obj);\n },\n remove: function remove() {\n removeStyleElement(styleElement);\n }\n };\n}\n\nmodule.exports = domAPI;\n\n/***/ }),\n\n/***/ 589:\n/***/ ((module) => {\n\n\"use strict\";\n\n\n/* istanbul ignore next */\nfunction styleTagTransform(css, styleElement) {\n if (styleElement.styleSheet) {\n styleElement.styleSheet.cssText = css;\n } else {\n while (styleElement.firstChild) {\n styleElement.removeChild(styleElement.firstChild);\n }\n\n styleElement.appendChild(document.createTextNode(css));\n }\n}\n\nmodule.exports = styleTagTransform;\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tvar cachedModule = __webpack_module_cache__[moduleId];\n/******/ \t\tif (cachedModule !== undefined) {\n/******/ \t\t\treturn cachedModule.exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t(() => {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = (module) => {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\t() => (module['default']) :\n/******/ \t\t\t\t() => (module);\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t})();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t(() => {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = (exports, definition) => {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t})();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t(() => {\n/******/ \t\t__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))\n/******/ \t})();\n/******/ \t\n/******/ \t/* webpack/runtime/make namespace object */\n/******/ \t(() => {\n/******/ \t\t// define __esModule on exports\n/******/ \t\t__webpack_require__.r = (exports) => {\n/******/ \t\t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t\t}\n/******/ \t\t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t\t};\n/******/ \t})();\n/******/ \t\n/******/ \t/* webpack/runtime/nonce */\n/******/ \t(() => {\n/******/ \t\t__webpack_require__.nc = undefined;\n/******/ \t})();\n/******/ \t\n/************************************************************************/\nvar __webpack_exports__ = {};\n// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.\n(() => {\n__webpack_require__(181);\nconst init=__webpack_require__(329)\ninit('问问计算机:webpack是怎么回事?');\n\n})();\n\n/******/ })()\n;"
用正则表达式替换换行和引号的内容后结果如下:
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ 329:
/***/ ((module) => {
function init(content) {
window.document.getElementById('app').innerHTML = content;
}
module.exports = init;
/***/
}),
/***/ 313:
/***/ ((module, __webpack_exports__, __webpack_require__) => {
"use strict";
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Z": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */
});
/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81);
/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(645);
/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__);
// Imports
var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default()));
// Module
___CSS_LOADER_EXPORT___.push([module.id, "#app{color:red;}", ""]);
// Exports
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);
/***/
}),
/***/ 645:
/***/ ((module) => {
"use strict";
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
module.exports = function (cssWithMappingToString) {
var list = []; // return the list of modules as css string
list.toString = function toString() {
return this.map(function (item) {
var content = "";
var needLayer = typeof item[5] !== "undefined";
if (item[4]) {
content += "@supports (".concat(item[4], ") {");
}
if (item[2]) {
content += "@media ".concat(item[2], " {");
}
if (needLayer) {
content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {");
}
content += cssWithMappingToString(item);
if (needLayer) {
content += "}";
}
if (item[2]) {
content += "}";
}
if (item[4]) {
content += "}";
}
return content;
}).join("");
}; // import a list of modules into the list
list.i = function i(modules, media, dedupe, supports, layer) {
if (typeof modules === "string") {
modules = [[null, modules, undefined]];
}
var alreadyImportedModules = {};
if (dedupe) {
for (var k = 0; k < this.length; k++) {
var id = this[k][0];
if (id != null) {
alreadyImportedModules[id] = true;
}
}
}
for (var _k = 0; _k < modules.length; _k++) {
var item = [].concat(modules[_k]);
if (dedupe && alreadyImportedModules[item[0]]) {
continue;
}
if (typeof layer !== "undefined") {
if (typeof item[5] === "undefined") {
item[5] = layer;
} else {
item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}");
item[5] = layer;
}
}
if (media) {
if (!item[2]) {
item[2] = media;
} else {
item[1] = "@media ".concat(item[2], " {").concat(item[1], "}");
item[2] = media;
}
}
if (supports) {
if (!item[4]) {
item[4] = "".concat(supports);
} else {
item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}");
item[4] = supports;
}
}
list.push(item);
}
};
return list;
};
/***/
}),
/***/ 81:
/***/ ((module) => {
"use strict";
module.exports = function (i) {
return i[1];
};
/***/
}),
/***/ 181:
/***/ ((__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 import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(379);
/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(795);
/* harmony import */ var _node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(569);
/* harmony import */ var _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(565);
/* harmony import */ var _node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(216);
/* harmony import */ var _node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(589);
/* harmony import */ var _node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(313);
var options = {};
options.styleTagTransform = (_node_modules_style_loader_dist_runtime_styleTagTransform_js__WEBPACK_IMPORTED_MODULE_5___default());
options.setAttributes = (_node_modules_style_loader_dist_runtime_setAttributesWithoutAttributes_js__WEBPACK_IMPORTED_MODULE_3___default());
options.insert = _node_modules_style_loader_dist_runtime_insertBySelector_js__WEBPACK_IMPORTED_MODULE_2___default().bind(null, "head");
options.domAPI = (_node_modules_style_loader_dist_runtime_styleDomAPI_js__WEBPACK_IMPORTED_MODULE_1___default());
options.insertStyleElement = (_node_modules_style_loader_dist_runtime_insertStyleElement_js__WEBPACK_IMPORTED_MODULE_4___default());
var update = _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */.Z, options);
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__/* ["default"] */.Z && _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__/* ["default"].locals */.Z.locals ? _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__/* ["default"].locals */.Z.locals : undefined);
/***/
}),
/***/ 379:
/***/ ((module) => {
"use strict";
var stylesInDOM = [];
function getIndexByIdentifier(identifier) {
var result = -1;
for (var i = 0; i < stylesInDOM.length; i++) {
if (stylesInDOM[i].identifier === identifier) {
result = i;
break;
}
}
return result;
}
function modulesToDom(list, options) {
var idCountMap = {};
var identifiers = [];
for (var i = 0; i < list.length; i++) {
var item = list[i];
var id = options.base ? item[0] + options.base : item[0];
var count = idCountMap[id] || 0;
var identifier = "".concat(id, " ").concat(count);
idCountMap[id] = count + 1;
var indexByIdentifier = getIndexByIdentifier(identifier);
var obj = {
css: item[1],
media: item[2],
sourceMap: item[3],
supports: item[4],
layer: item[5]
};
if (indexByIdentifier !== -1) {
stylesInDOM[indexByIdentifier].references++;
stylesInDOM[indexByIdentifier].updater(obj);
} else {
var updater = addElementStyle(obj, options);
options.byIndex = i;
stylesInDOM.splice(i, 0, {
identifier: identifier,
updater: updater,
references: 1
});
}
identifiers.push(identifier);
}
return identifiers;
}
function addElementStyle(obj, options) {
var api = options.domAPI(options);
api.update(obj);
var updater = function updater(newObj) {
if (newObj) {
if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {
return;
}
api.update(obj = newObj);
} else {
api.remove();
}
};
return updater;
}
module.exports = function (list, options) {
options = options || {};
list = list || [];
var lastIdentifiers = modulesToDom(list, options);
return function update(newList) {
newList = newList || [];
for (var i = 0; i < lastIdentifiers.length; i++) {
var identifier = lastIdentifiers[i];
var index = getIndexByIdentifier(identifier);
stylesInDOM[index].references--;
}
var newLastIdentifiers = modulesToDom(newList, options);
for (var _i = 0; _i < lastIdentifiers.length; _i++) {
var _identifier = lastIdentifiers[_i];
var _index = getIndexByIdentifier(_identifier);
if (stylesInDOM[_index].references === 0) {
stylesInDOM[_index].updater();
stylesInDOM.splice(_index, 1);
}
}
lastIdentifiers = newLastIdentifiers;
};
};
/***/
}),
/***/ 569:
/***/ ((module) => {
"use strict";
var memo = {};
/* istanbul ignore next */
function getTarget(target) {
if (typeof memo[target] === "undefined") {
var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself
if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {
try {
// This will throw an exception if access to iframe is blocked
// due to cross-origin restrictions
styleTarget = styleTarget.contentDocument.head;
} catch (e) {
// istanbul ignore next
styleTarget = null;
}
}
memo[target] = styleTarget;
}
return memo[target];
}
/* istanbul ignore next */
function insertBySelector(insert, style) {
var target = getTarget(insert);
if (!target) {
throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
}
target.appendChild(style);
}
module.exports = insertBySelector;
/***/
}),
/***/ 216:
/***/ ((module) => {
"use strict";
/* istanbul ignore next */
function insertStyleElement(options) {
var element = document.createElement("style");
options.setAttributes(element, options.attributes);
options.insert(element, options.options);
return element;
}
module.exports = insertStyleElement;
/***/
}),
/***/ 565:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* istanbul ignore next */
function setAttributesWithoutAttributes(styleElement) {
var nonce = true ? __webpack_require__.nc : 0;
if (nonce) {
styleElement.setAttribute("nonce", nonce);
}
}
module.exports = setAttributesWithoutAttributes;
/***/
}),
/***/ 795:
/***/ ((module) => {
"use strict";
/* istanbul ignore next */
function apply(styleElement, options, obj) {
var css = "";
if (obj.supports) {
css += "@supports (".concat(obj.supports, ") {");
}
if (obj.media) {
css += "@media ".concat(obj.media, " {");
}
var needLayer = typeof obj.layer !== "undefined";
if (needLayer) {
css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {");
}
css += obj.css;
if (needLayer) {
css += "}";
}
if (obj.media) {
css += "}";
}
if (obj.supports) {
css += "}";
}
var sourceMap = obj.sourceMap;
if (sourceMap && typeof btoa !== "undefined") {
css += "\
/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");
} // For old IE
/* istanbul ignore if */
options.styleTagTransform(css, styleElement, options.options);
}
function removeStyleElement(styleElement) {
// istanbul ignore if
if (styleElement.parentNode === null) {
return false;
}
styleElement.parentNode.removeChild(styleElement);
}
/* istanbul ignore next */
function domAPI(options) {
var styleElement = options.insertStyleElement(options);
return {
update: function update(obj) {
apply(styleElement, options, obj);
},
remove: function remove() {
removeStyleElement(styleElement);
}
};
}
module.exports = domAPI;
/***/
}),
/***/ 589:
/***/ ((module) => {
"use strict";
/* istanbul ignore next */
function styleTagTransform(css, styleElement) {
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText = css;
} else {
while (styleElement.firstChild) {
styleElement.removeChild(styleElement.firstChild);
}
styleElement.appendChild(document.createTextNode(css));
}
}
module.exports = styleTagTransform;
/***/
})
/******/
});
/************************************************************************/
/******/ // 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] = {
/******/ id: moduleId,
/******/ // 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;
/******/
}
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ var getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/
};
/******/
})();
/******/
/******/ /* 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/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/
})();
/******/
/******/ /* 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/nonce */
/******/ (() => {
/******/ __webpack_require__.nc = undefined;
/******/
})();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
__webpack_require__(181);
const init = __webpack_require__(329)
init('问问计算机:webpack是怎么回事?');
})();
/******/
})()
;
折叠起代码块如下:
把这个文件重命名为 bundle.js 放在dist文件夹下,浏览 index.html 效果如下:
也就是说这个效果和最终输出的编译压缩后的bundle.js的效果是一样的。但是这个对于查看编译结果的内容来说更加直白。
初始化 __webpack_modules__ 对象,各模块对应的属性名称是 数字,如下:329,313,645,81,181,379,569,216,565,795,589
这里在第一次加载的时候实际上它只是给对 __webpack_require__.n进行了赋值而已,并没有调用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D186EO44-1662528249572)(static/image-20220822092020034.png)]
后面几个方法同理,只是对 __webpack_require__.d、 __webpack_require__.o __webpack_require__.r、 __webpack_require__.nc进行赋值:
在最后才开始真正的业务实现,如下:
调用__webpack_require__(181),先经过如下过程,判断缓存对象中是否存在对应于181的模块,如果存在直接获取,如果不存在久再创建一个新的对应moduleId的模块对象。然后使用 __webpack_module__[moduleId]执行对应的方法(注:这里的 __webpack_module_cache 只是当前环境下的一个对象,并不是操作系统的角度去理解的物理意义上的缓存机制):
/*
* __webpack_module_cache 模块缓存对象
* author:askcomputer
* **/
var __webpack_module_cache__ = {};
/*
* __webpack_require 方法
* author:askcomputer
* **/
function __webpack_require__(moduleId) {
// 判断模块是否在cache中
var cachedModule = __webpack_module_cache__[moduleId];
if (cachedModule !== undefined) {
return cachedModule.exports;
}
//如果cache对象中没有,就创建一个新的模块,并把它放在cache中
var module = __webpack_module_cache__[moduleId] = {
id: moduleId,
exports: {}
};
// 根据moduleId调用__webpack_modules__对象中对应的模块方法
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
return module.exports;
}
下面执行181对应的方法如下,其中三个参数对应的实参:
{
...
181:
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
...
这一步骤给 __webpack_exports__ 对象添加属性,并赋值如下:
紧接着调用 d 方法 如下:
调用 o 方法,如下:
if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
}
o 方法:
__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
Object.prototype.hasOwnProperty.call() 用来判断一个属性是定义在对象本身而不是继承自原型链。
这种情况下,__webpack_require__.o(definition, key) 的结果为true,而__webpack_require__.o(exports, key) 的结果为false。很明显,definition 当参数传进来的时候给的 default ,而 exports 在前面定义的只有 __esModule属性和 Symbol(Symbol.toStringTag),所以if后的条件成立,执行if的代码块,如下:
执行完后给 exports 对象绑定了get属性,如下:
接下来回到模块181,并调用模块379如下:
/* harmony import */ var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(379);
这一步到这里实际上什么都没有做,它只是给 module.exports 赋值了一个方法,但是并没有执行。如下:
紧接着:
var _node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);
调用n方法,参数是上一步中初始化的模块379。如下:
(() => {
__webpack_require__.n = (module) => {
var getter = module && module.__esModule ?
() => (module['default']) :
() => (module);
__webpack_require__.d(getter, { a: getter });
return getter;
};
})();
给module设置getter属性,如下:
并赋值给_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default。如下几种同理:
下一步看一看 css_loader 的模块,如下:
var _node_modules_css_loader_dist_cjs_js_index_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(313);
实现过程类似。
直到 __webpack_require__(181) 这个方法执行完进入下一步之前所有的内容都是对于 css 的处理,其前提是以webpack 的模块调用过程为基础。
下面的关键就是 这个 Loader 是在什么情况下, 运行的,它和 webpack.config.js 中的配置是什么时候关联上的。
在这其中的loader-runner是干什么用的?
得到的是一个RawSource对象。
这是解析器解析步骤的一个重要环节:
这一步比较重要,它涉及到acorn,将原有的source对应的脚本转换成AST格式。
需要了解acorn的使用方式 https://blog.csdn.net/u012222078/article/details/70185068。
content的内容全部加载输出parser完成之后,进入到renderMain的阶段,如下:
这里涉及到一个RuntimeTemplate.js的内容,暂且不知道它具体的用处是什么。这里看一看针对上述的输出内容,看它的每一行最终的结果是怎么转换输出的。好像离终点越来越近了。
加载,解析,编译,渲染,输出。
现在这一步到了模板渲染最终结果的阶段了。
但是前面的加载器处理的过程,还需要进一步细化。当前只是知道了,它如何进入加载器。怎么找到加载器,加载器做了哪些操作还需要进一步抽象明确。
这儿就是输出的最终的渲染结果的部分。从这再往回倒应该就相对更清晰。
详细看这个streamChunk方法的五个参数:
在streamChunk方法中得到的结果对应source和code,然后用于resultSource的后续处理。
其中当前上下文中:
- source:
这里的source的类型是ConcatSource的类型,在ConcatSource类下可以看到streamChunk的方法,所以这里第一个if判断结果为真,执行if条件下的代码块。ConcatSource中的Concat直译是“连接”的意思。比如在JavaScript中的数组就有concat方法,用于两个数组的连接组合。这里的ConcatSource是对不同种类型的Source的连接。这里的ConcatSource会根据类型去关联CachedSource和RawSources的streamChunk。
streamChunks(options, onChunk, onSource, onName) {
if (!this._isOptimized) this._optimize(); //把字符串部分变更为RawSources类型,其中子节点的顺序保持原样,CachedSource部分不做修改,直接push到newChildren中
if (this._children.length === 1)
return this._children[0].streamChunks(options, onChunk, onSource, onName);
let currentLineOffset = 0;
let currentColumnOffset = 0;
let sourceMapping = new Map();
let nameMapping = new Map();
const finalSource = !!(options && options.finalSource);
let code = "";
let needToCloseMapping = false;
for (const item of this._children) {
const sourceIndexMapping = [];
const nameIndexMapping = [];
let lastMappingLine = 0;
//这里嵌套了一层streamChunks,可是这里调用的不是文件中的streamChunk,而是引入的 const streamChunks = require("./helpers/streamChunks");
//generatedLine:生成的行
//generatedColumn:生成的列
//source:解析的内容,源代码
const { generatedLine, generatedColumn, source } = streamChunks(
item,
options,
// eslint-disable-next-line no-loop-func
(
chunk,
generatedLine,
generatedColumn,
sourceIndex,
originalLine,
originalColumn,
nameIndex
) => {
const line = generatedLine + currentLineOffset;
const column =
generatedLine === 1
? generatedColumn + currentColumnOffset
: generatedColumn;
if (needToCloseMapping) {
if (generatedLine !== 1 || generatedColumn !== 0) {
onChunk(
undefined,
currentLineOffset + 1,
currentColumnOffset,
-1,
-1,
-1,
-1
);
}
needToCloseMapping = false;
}
const resultSourceIndex =
sourceIndex < 0 || sourceIndex >= sourceIndexMapping.length
? -1
: sourceIndexMapping[sourceIndex];
const resultNameIndex =
nameIndex < 0 || nameIndex >= nameIndexMapping.length
? -1
: nameIndexMapping[nameIndex];
lastMappingLine = resultSourceIndex < 0 ? 0 : generatedLine;
if (finalSource) {
if (chunk !== undefined) code += chunk;
if (resultSourceIndex >= 0) {
onChunk(
undefined,
line,
column,
resultSourceIndex,
originalLine,
originalColumn,
resultNameIndex
);
}
} else {
if (resultSourceIndex < 0) {
onChunk(chunk, line, column, -1, -1, -1, -1);
} else {
onChunk(
chunk,
line,
column,
resultSourceIndex,
originalLine,
originalColumn,
resultNameIndex
);
}
}
},
(i, source, sourceContent) => {
let globalIndex = sourceMapping.get(source);
if (globalIndex === undefined) {
sourceMapping.set(source, (globalIndex = sourceMapping.size));
onSource(globalIndex, source, sourceContent);
}
sourceIndexMapping[i] = globalIndex;
},
(i, name) => {
let globalIndex = nameMapping.get(name);
if (globalIndex === undefined) {
nameMapping.set(name, (globalIndex = nameMapping.size));
onName(globalIndex, name);
}
nameIndexMapping[i] = globalIndex;
}
);
if (source !== undefined) code += source;
if (needToCloseMapping) {
if (generatedLine !== 1 || generatedColumn !== 0) {
onChunk(
undefined,
currentLineOffset + 1,
currentColumnOffset,
-1,
-1,
-1,
-1
);
needToCloseMapping = false;
}
}
if (generatedLine > 1) { //如果生成的行数大于一
currentColumnOffset = generatedColumn; //当前的column偏移等于生成的列的数量【ME:这里还不太明白怎么回事】
} else {
currentColumnOffset += generatedColumn;
}
needToCloseMapping =
needToCloseMapping ||
(finalSource && lastMappingLine === generatedLine);
currentLineOffset += generatedLine - 1;
}
return {
generatedLine: currentLineOffset + 1,
generatedColumn: currentColumnOffset,
source: finalSource ? code : undefined
};
}
- options
- onChunk
- onSource
- onName
需要确认的是这个方法的详细逻辑,它实际上是根据module去获取对应的运行时结果,关键在于codeGenerationResults对应的get方法的理解:
从下图可以看到,module对应的内容:
在渲染模块renderModule的时候会用到 this.map ,如下:
而这个this.map是在什么时候赋值的呢?如下:
调用它的地方位于Compilation,如下:
那么下面一个问题就是这里的Module[1003:…]是什么时候添加到 CodeGenerationResults 的 this.map 中的,使用如下方式:
这个module来自于:
module来自于 _runCodeGenerationJobs
需要明确这个方法的过程。到这一步就离转换的起点更近了。
这里对于 asyncLib.eachLimit的理解比较重要,它是neo-async的内容,其中第一个参数 jobs 是任务数组,第二个参数是 任务并行执行的数量,第三个参数是对应每个任务的回调函数。
所以在这个基础上就能理解,对应于job当中的module,实际上是来自于jobs对应的处理后调用回调函数传回来的参数。那么这种情况下就要明确jobs的内容。
而jobs来自于_runCodeGenerationJobs的形参。如下:
它的调用位置在:
然后进一步查看这个jobs的创建过程。从这个方法中可以看到 jobs 是由 this.modules 遍历后处理得到的。这里的this.modules 是Set对象。JavaScript中Set对象是唯一值的集合,每个值在Set中只能出现一次,一个Set可以容纳任何数据类型的任何值。
所以接着要看这个 this.modules 是什么情况下 add 的元素。
到这已经触及到了工作中经常说的webpack中将一切视为模块进行打包的理念了。下一步要搞清楚的是这里的模块是什么模块,怎么生成的。
一方面需要确认addModule与_addModule之间的关系,另一方面需要进一步确认addModule的调用位置和module的生成位置,如下:
下面详细分析这个this.factorizeModule的实现细节。
this.factoryModule,它对应于 Compilation.prototype.factorizeModule :
//这里的factorize直译为“分解”的意思
Compilation.prototype.factorizeModule = (
function (options, callback) {
this.factorizeQueue.add(options, callback);
}
);
把参数送给了this.factorizeQueue的add方法。factorizeQueue是一个AsyncQueue,AsyncQueue是在webpack中定义的一个异步队列的类型。这一个过程就很关键,理解起来也比较晦涩。
在AsyncQueue的构造函数中定义了4个钩子。如下:
当上面执行 this.factorizeQueue.add(options, callback); 方法的时候,就在钩子上调用了 beforeAdd。在add方法中执行了 this.hooks.beforeAdd.callAsync,如下:
这里需要搞清的是callAsync发生了什么事情。
但是因为没有通过tap订阅消息,所以这里直接执行回调函数。
查看key和newEntry,如下:
最终定位到 module 的生成位置如下:
如下:
从这就能看到对应于Module的唯一身份识别码,起始位1000。
还有一个关键的地方要注意的是loader-runner
下面大概捋一捋思路:从createData到Module,增加了很多属性。
这里用的get,实际上它对应的是add方法,
在这个方法里看一看到,它把三个参数也就是 module、runtime和result 三个合成了一个,实际上最后输出的内容,是存在result里的。
result生成的位置如下:
对应结果中的181找到踪迹了,如下:
实际上文件的内容在一开始的时候就已经读成字节流了,如下:
这里的 this._source 在 codeGenerator的时候被获取:
现在基本流程基本上清晰了,需要进一步定位的是 loader 也就是 style-loader 和 css-loader 这两个 loader 实际应用的点 在哪儿。
解析请求数组:
这样这个过程就关联上了。
知道了什么时候进行的关联,下一步要明确,什么时候进行的转换,如何进行的loader的转换。这个实际上依托于load-runner。
所以接下要看看 load-runner是个什么鬼东西。针对loader-runner源码,要明确测试的流程和使用方法。