You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/******/__webpack_require__.e=functionrequireEnsure(chunkId){/******/varpromises=[];/******//******//******/// JSONP chunk loading for javascript/******//******/varinstalledChunkData=installedChunks[chunkId];/******/if(installedChunkData!==0){// 0 means "already installed"./******//******/// a Promise means "currently loading"./******/if(installedChunkData){/******/promises.push(installedChunkData[2]);/******/}else{/******/// setup Promise in chunk cache/******/varpromise=newPromise(function(resolve,reject){/******/installedChunkData=installedChunks[chunkId]=[resolve,reject];/******/});/******/promises.push(installedChunkData[2]=promise);/******//******/// start chunk loading/******/varscript=document.createElement('script');/******/varonScriptComplete;/******//******/script.charset='utf-8';/******/script.timeout=120;/******/if(__webpack_require__.nc){/******/script.setAttribute("nonce",__webpack_require__.nc);/******/}/******/script.src=jsonpScriptSrc(chunkId);/******/if(script.src.indexOf(window.location.origin+'/')!==0){/******/script.crossOrigin="anonymous";/******/}/******/// create error before stack unwound to get useful stacktrace later/******/varerror=newError();/******/onScriptComplete=function(event){/******/// .../******/};/******/vartimeout=setTimeout(function(){/******/onScriptComplete({type: 'timeout',target: script});/******/},120000);/******/script.onerror=script.onload=onScriptComplete;/******/document.head.appendChild(script);/******/}/******/}/******/returnPromise.all(promises);/******/};
// webpack/lib/MainTemplate.jsthis.hooks.requireExtensions.tap("MainTemplate",(source,chunk,hash)=>{constbuf=[];constchunkMaps=chunk.getChunkMaps();// Check if there are non initial chunks which need to be imported using require-ensureif(Object.keys(chunkMaps.hash).length){buf.push("// This file contains only the entry chunk.");buf.push("// The chunk loading function for additional chunks");buf.push(`${this.requireFn}.e = function requireEnsure(chunkId) {`);buf.push(Template.indent("var promises = [];"));buf.push(Template.indent(this.hooks.requireEnsure.call("",chunk,hash,"chunkId")));buf.push(Template.indent("return Promise.all(promises);"));buf.push("};");}// ...}
The text was updated successfully, but these errors were encountered:
xiaoxiaojx
added
webpack
A bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting a
DEBUG
debug
labels
Sep 28, 2022
问题简述
a 同学说我写的 npm 包 @xxfe/pkg 在 x 项目使用时发布到测试环境报了如上的错误, 但是开发环境没有报错。接着我看了一下 node_modules 中这个包的代码, 这个 Promise 都没 await 咋会被 catch 且还真的被捕获打印了错误日志 🤯, 这是什么瞎猫碰见死耗子的操作 ...
仅看 node_modules 中的代码并未发现明显的错误, 其实我们应该看的是 @xxfe/pkg 打包后的代码
打包后的代码就发现了错误的源头 n.e
熟悉 webpack 的同学就知道动态 import 函数打包后会被 webpack_require.e 函数给替换, 其原理就是通过动态创建一个 script 标签来加载一个 js, 如下即函数的代码
问题排查
那么为什么代码中用到了 import 函数, webpack 却没有注入 webpack_require.e 函数的实现了 ?
此时我们只能看 webpack 的代码实现, 可以发现当 Object.keys(chunkMaps.hash).length 条件为 true 时, 才会注入 ${this.requireFn}.e 函数
顺着函数调用顺序发现关键是 getAllAsyncChunks 函数返回值 chunks 集合不为空即可
chunks 集合只有一处往集合增加数据的逻辑。initialChunks 可以理解为首屏 html 中 script 标签的 js, 通常是 main.js 及其运行前依赖的 js, 比如 main.js 需要依赖 react, react-dom 等 js 的前置运行。
因为业务项目 webpackConfig.optimizationa.splitChunks 的配置把 a 同学写的 @xxfe/pkg 包都打入到了 xxfe_vendor 文件中, 而 @xxfe/ scope 下的依赖被业务项目大量使用, 所以无疑是业务项目 main.js 前置依赖的一个 js, 故 xxfe_vendor 在首屏 html 中 script 标签的 js 中
所以 xxfe_vendor 是 initialChunks 中的其中一个, 故此处 if 为 false
至此我们理清了导致问题的原因, @xxfe/pkg 中的 import 函数引用的 js 及其自身代码由于分包的 splitChunks 设置都被打入到了 xxfe_vendor 中, 而 xxfe_vendor 又是业务项目 main.js 前置运行依赖的 js, 故 webpack 错误的认为你不需要 webpack_require.e 函数
问题解决
将如下的 chunks 字段由 all 改为了 initial, 表示该分包设置将不要影响到动态 import 函数异步加载的 js (该类型为 async chunks), 使得 @xxfe/pkg 将不会被合入 xxfe_vendor 文件中, 那么如上的 initialChunks 也将不包含 @xxfe/pkg, 从而 webpack 也会如约注入 webpack_require.e 函数的实现
The text was updated successfully, but these errors were encountered: