webpack联邦模块之consumes方法
對于使用聯邦模塊的項目會有兩個依賴,一個是遠程模塊,一個是共享模塊。上一篇文章解釋了遠程模塊的加載和安裝并初始化共享作用域。consumes則是共享模塊的解決方案,用于在運行時加載并安裝依賴的共享模塊。
為什么叫consumes?我理解是因為共享模塊的獲取是在__webpack_require__.I中完成的,而consumes只是使用__webpack_require__.S中的數據來安裝對應模塊。所以consumes是在消費__webpack_require__.S中的數據。
__webpack_require__S.default = {react: {version: {get() {}, ...}}}以上信息并沒有在__webpack_require__.m上,所以當前環境并不能使用共享作用域中的內容
var versionLt = (a, b) => {// see webpack/lib/util/semver.js for original codea=parseVersion(a),b=parseVersion(b);for(var r=0;;){if(r>=a.length)return r<b.length&&"u"!=(typeof b[r])[0];var e=a[r],n=(typeof e)[0];if(r>=b.length)return"u"==n;var t=b[r],f=(typeof t)[0];if(n!=f)return"o"==n&&"n"==f||("s"==f||"u"==n);if("o"!=n&&"u"!=n&&e!=t)return e<t;r++} }var findSingletonVersionKey = (scope, key) => {var versions = scope[key];return Object.keys(versions).reduce((a, b) => {return !a || (!versions[a].loaded && versionLt(a, b)) ? b : a;}, 0); };var satisfy = (range, version) => {// see webpack/lib/util/semver.js for original codeif(0 in range){version=parseVersion(version);var e=range[0],r=e<0;r&&(e=-e-1);for(var n=0,i=1,a=!0;;i++,n++){var f,s,g=i<range.length?(typeof range[i])[0]:"";if(n>=version.length||"o"==(s=(typeof(f=version[n]))[0]))return!a||("u"==g?i>e&&!r:""==g!=r);if("u"==s){if(!a||"u"!=g)return!1}else if(a)if(g==s)if(i<=e){if(f!=range[i])return!1}else{if(r?f>range[i]:f<range[i])return!1;f!=range[i]&&(a=!1)}else if("s"!=g&&"n"!=g){if(r||i<=e)return!1;a=!1,i--}else{if(i<=e||s<g!=r)return!1;a=!1}else"s"!=g&&"n"!=g&&(a=!1,i--)}}var t=[],o=t.pop.bind(t);for(n=1;n<range.length;n++){var u=range[n];t.push(1==u?o()|o():2==u?o()&o():u?satisfy(u,version):!o())}return!!o(); }var getSingletonVersion = (scope, scopeName, key, requiredVersion) => {var version = findSingletonVersionKey(scope, key);if (!satisfy(requiredVersion, version)) typeof console !== "undefined" && console.warn && console.warn(getInvalidSingletonVersionMessage(scope, key, version, requiredVersion));return get(scope[key][version]); };var get = (entry) => {entry.loaded = 1;return entry.get() };// 給入參函數注入依賴項共享作用域scope,封裝的是scope的獲取, // 因為scope可能在初始化中,也可能初始化完成 var init = (fn) => (function(scopeName, a, b, c) {var promise = __webpack_require__.I(scopeName);// 等待共享作用域初始化完成if (promise && promise.then) return promise.then(fn.bind(fn, scopeName, __webpack_require__.S[scopeName], a, b, c));return fn(scopeName, __webpack_require__.S[scopeName], a, b, c); });var loadSingletonVersionCheckFallback = /*#__PURE__*/ init((scopeName, scope, key, version, fallback) => {if(!scope || !__webpack_require__.o(scope, key)) return fallback();return getSingletonVersion(scope, scopeName, key, version); });var installedModules = {}; var moduleToHandlerMapping = {"webpack/sharing/consume/default/react/react?5e40": () => (loadSingletonVersionCheckFallback("default", "react", [1,17,0,2], () => (Promise.all([__webpack_require__.e("vendors-node_modules_react_index_js"), __webpack_require__.e("node_modules_object-assign_index_js")]).then(() => (() => (__webpack_require__(/*! react */ "../node_modules/react/index.js"))))))),"webpack/sharing/consume/default/react-dom/react-dom": () => (loadSingletonVersionCheckFallback("default", "react-dom", [1,17,0,2], () => (Promise.all([__webpack_require__.e("vendors-node_modules_react-dom_index_js"), __webpack_require__.e("webpack_sharing_consume_default_react_react")]).then(() => (() => (__webpack_require__(/*! react-dom */ "../node_modules/react-dom/index.js"))))))),"webpack/sharing/consume/default/react/react?7071": () => (loadSingletonVersionCheckFallback("default", "react", [4,17,0,2], () => (__webpack_require__.e("vendors-node_modules_react_index_js").then(() => (() => (__webpack_require__(/*! react */ "../node_modules/react/index.js"))))))) }; // no consumes in initial chunks var chunkMapping = {"src_bootstrap_js": ["webpack/sharing/consume/default/react/react?5e40","webpack/sharing/consume/default/react-dom/react-dom"],"webpack_sharing_consume_default_react_react": ["webpack/sharing/consume/default/react/react?7071"] }; __webpack_require__.f.consumes = (chunkId, promises) => {if(__webpack_require__.o(chunkMapping, chunkId)) {chunkMapping[chunkId].forEach((id) => {if(__webpack_require__.o(installedModules, id)) return promises.push(installedModules[id]);var onFactory = (factory) => {installedModules[id] = 0;__webpack_require__.m[id] = (module) => {delete __webpack_require__.c[id];module.exports = factory();}};var onError = (error) => {delete installedModules[id];__webpack_require__.m[id] = (module) => {delete __webpack_require__.c[id];throw error;}};try {var promise = moduleToHandlerMapping[id]();if(promise.then) {promises.push(installedModules[id] = promise.then(onFactory)['catch'](onError));} else onFactory(promise);} catch(e) { onError(e); }});} }chunkMapping中存著chunk對應共享模塊的依賴,而moduleToHandlerMapping中存著共享模塊的獲取方式,通過方法__webpack_require__.f.consumes入參這兩個數據就能解析chunk依賴的模塊,并對模塊進行安裝。
(loadSingletonVersionCheckFallback("default", "react", [1,17,0,2], fallback))
這一行表達的是在共享作用域default上尋找版本為1.17.0.2的react,如果找不到使用自帶的模塊fallback。
var init = (fn) => (function(scopeName, a, b, c) {var promise = __webpack_require__.I(scopeName);// 等待共享作用域初始化完成if (promise && promise.then) return promise.then(fn.bind(fn, scopeName, __webpack_require__.S[scopeName], a, b, c));return fn(scopeName, __webpack_require__.S[scopeName], a, b, c); });var loadSingletonVersionCheckFallback = /*#__PURE__*/ init((scopeName, scope, key, version, fallback) => {if(!scope || !__webpack_require__.o(scope, key)) return fallback();return getSingletonVersion(scope, scopeName, key, version); });init方法用于初始化對應共享作用域,共享作用域加載完成后將相關作用域信息作為入參調用init的入參函數。
拿到作用域信息后調用方法getSingletonVersion(scope, scopeName, key, version)
getSingletonVersion
function getSingletonVersion(scope, scopeName, key, requiredVersion) {...return get(scope[key][version]); }var get = (entry) => {entry.loaded = 1;return entry.get(); };get方法的返回值會作為方法onFactory的入參
var onFactory = (factory) => {installedModules[id] = 0;__webpack_require__.m[id] = (module) => {delete __webpack_require__.c[id];module.exports = factory();} };onFactory執行完成后__webpack_require__.m上就會出現對應的模塊信息。到這里共享模塊也安裝完成了。
等待chunk src_bootstrap_js文件加載完成,外部依賴準備完成,共享模塊準備完成后chunk src_bootstrap_js 則表示加載完成可以開始執行業務代碼了。
名字的翻譯
在源碼中使用的名字是 import React from ‘react’,而通過webpack編譯后變成了”webpack/sharing/consume/default/react/react?5e40”,并且在__webpack_require__.S上的名字也是react,這些是怎么關聯起來的呢?
該問題同樣存在于遠程模塊加載場景中。
”webpack/sharing/consume/default/react/react?5e40”是怎么和共享作用域中的”react”關聯起來的?
在上面源碼中
var moduleToHandlerMapping = {"webpack/sharing/consume/default/react/react?5e40": () => (loadSingletonVersionCheckFallback("default", "react", [1,17,0,2], () => (Promise.all([__webpack_require__.e("vendors-node_modules_react_index_js"), __webpack_require__.e("node_modules_object-assign_index_js")]).then(() => (() => (__webpack_require__(/*! react */ "../node_modules/react/index.js"))))))), }表示模塊"webpack/sharing/consume/default/react/react?5e40"需要在共享作用域default中的1.17.0.2版本的react,這里這兩個名字就關聯起來了。
源碼中的 import React from ‘react’ 是怎么和 "webpack/sharing/consume/default/react/react?5e40" 關聯起來的?
源碼中的
import React from 'react'經過編譯變成
var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "webpack/sharing/consume/default/react/react?5e40"); var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);這樣源碼中的名字 ”react”就和"webpack/sharing/consume/default/react/react?5e40"關聯起來了。
總結
以上是生活随笔為你收集整理的webpack联邦模块之consumes方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: webpack联邦模块之remotes方
- 下一篇: TCP握手为什么需要三次通信