webpack加载bootstrap-Webpack异步加载配置文件_Webpack是如何工作的?

2023-08-29 0 2,526 百度已收录

在平时的开发中,我们经常会用到Webpack这个时下最流行的后端打包工具。 它将开发代码打包并输出可以在各种浏览器上运行的代码,提高开发到发布过程的效率。

我们知道一个Webpack配置文件主要包括入口、输出、模式、加载器、插件等几个部分。 但如果你只需要整理JS文件,那么通过指定入口和输出文件路径就可以完成一个迷你项目的打包。 让我们通过一个简单的项目来看看 Webpack 是如何工作的。

同步加载

本文以webpack^4.30.0为例。 为了更好地观察输出文件,我们将模式设置为development并关闭代码压缩,然后打开source-map以支持原始源代码调试。 除了。 我们还简单写了一个插件MyPlugin来消除源代码中的注释。

新的 src/index.js

创建新的 webpack 配置文件 webpack.config.js

创建新的 src/MyPlugin.js。了解有关 webpack 插件的更多信息

现在我们运行命令webpack—configwebpack.config.js,打包完成后会多出一个输出目录dist:dist/main.js。 main 是 webpack 默认的输出文件名,我们快速看一下这个文件:

整个文件只包含一个立即执行函数(IIFE),我们称之为webpackBootstrap,它只接收一个对象——卸载的模块集合(modules),这个模块对象的键是一个路径,值是一个函数。 你可能会问,这里有哪些模块? 它们是如何加载的?

webpack加载bootstrap-Webpack异步加载配置文件_Webpack是如何工作的?

在仔细查看输出代码之前,我们先丰富一下源代码:

新文件 src/utils/math.js:

更改 src/index.js:

我们按照ES规范的模块化句型编写了一个简单的模块src/utils/math.js,并引用到了src/index.js。 Webpack 以自己的方式支持 ES6Module 规范。 上面提到的module就是对应ES6module的概念。

我们来看看这个模块是如何通过ES5代码实现的。 再次运行命令 webpack—configwebpack.config.js 查看输出文件:

IIFE 传入的 module 对象中多了一个键名对,对应新模块 src/utils/math.js,与我们在源码中拆分的模块相呼应。 不过,拥有模块只是第一步,本文档的最终效果应该是让各个模块按照开发者编程的顺序运行。

探索 webpack Bootstrap

拿出来看看webpackBootstrap有哪些功能:

webpack加载bootstrap-Webpack异步加载配置文件_Webpack是如何工作的?

可见虽然主要做了两件事:

整个webpackBootstrap中只出现了入口模块的影子,那么其他模块是如何加载的呢? 我们沿着 __webpack_require__("./src/index.js") 仔细看看加载函数的内部逻辑:

首先,加载函数使用闭包变量installedModules将加载的模块保存在视频内存中。 接下来是初始化模块对象并将其挂载到缓存中。 之后就是模块的执行流程了。 加载入口文件时,modules[moduleId]即为./src/index.js对应的模块函数。 在执行模块函数之前,会传入几个与模块相关的左值,以便模块可以导入内容并加载其他模块的导入。 最后标记模块已加载,并返回模块导入的内容。

根据__webpack_require__的缓存和导入逻辑,我们知道在整个IIFE操作过程中,缓存的模块在加载时会直接返回installedModules[moduleId].exports,换句话说webpack加载bootstrap,同一个模块只能被引用第一次 只有这样模块本身才能被执行。

模块执行函数

__webpack_require__通过modules[moduleId].call()运行模块执行函数,然后我们进入we​​bpackBootstrap的参数部分查看模块执行函数。

执行顺序为:入口模块->工具模块->入口模块。 在入口模块中,首先通过__webpack_require__("./src/utils/math.js")获取工具模块的exports对象。 再看工具模块,ES import 句型转化为 __webpack_require__.d(__webpack_exports__,[key],[getter]),而 __webpack_require__.d 函数的定义在 webpackBootstrap 中:

webpack加载bootstrap-Webpack异步加载配置文件_Webpack是如何工作的?

可以看出__webpack_require__.d是对Object.defineProperty的简单封装。

引用实用程序模块导入的变量后,入口模块将执行其余部分。 至此,Webpack的基本模块执行流程就结束了。

好了,我们用流程图来总结一下Webpack模块的加载思路:

异步加载

通过前面的打包,我们发现不同的包被打包到了一个main.js文件中。 main.js会集中消耗过多的网络资源,导致用户等待很长时间才能开始与网页交互。

通常的解决方案是:根据需求增加最先加载的文件的体积,必要时异步加载其他文件并使用其中的模块(例如切换后端路由器、交互式风暴反弹)。

Webpack 建议使用 ESimport() 规范来异步加载模块。 我们按照ES规范改变入口模块的导入形式,使其能够异步加载模块:

src/index.js

工具模块(src/utils/math.js)保持不变。 在webpack配置中,我们指定了资源文件的公共资源路径(publicPath),这个路径在前面的搜索过程中会遇到。

然后执行打包,可以看到不仅有dist/main.js,还多了一个dist/0.js./src/utils/math.js。 模块从 mainchunk 迁移到 0chunk。 与demo1不同的是,mainchunk中添加了一些异步加载的代码。 我们来看一下:

可以看到webpackBootstrap的函数体减少了一些内容,参数部分不仅仅移到了“./src/utils/math.js”模块中。 按照包装函数的执行顺序,我们首先关注“JSONP初始化”部分:

看起来有点长,我们一步一步来分析,首先从第一行和最后一行开始,整个函数将异步加载过程封装成一个promise,最后导入。

然后,从第二行开始,installedChunkData从缓存中获取值,即使第一次加载该块时这里未定义该值。 然后,installedChunkData的未定义值触发第一级if语句的判断条件。 立即进行第二级if语句。 此时根据判断条件进入else块。 在这里,我们将策略性地跳过 if 块中的内容。 else中主要有两块内容。 一是块脚本加载过程。 这个过程会创建一个 script 标签,使其请求 chunk 的地址并执行 chunk 内容; 第二个是初始化promise并使用promise来控制chunk文件加载过程。

不过我们只在这个else代码块中发现了reject的使用,也就是chunk加载异常时使用chunk1的地方,却没有发现resolve更重要的使用。 我们只是将解析挂在缓存上(installedChunks[chunkId]=[resolve,reject])。

这里的chunk文件加载后会发生什么? 我们打开 dist/0.js 来看看:

我们发现:

这段代码开始执行webpack加载bootstrap,将与异步加载相关的chunkid和模块传递给push函数。 上面提到了window[“webpackJsonp”]链表的push函数被重绘为webpackJsonpCallback函数,其定义位置在webpackBootstrap中:

进入该函数意味着异步加载的chunk内容已经被接收。 这时候我们需要完成两件事。 一是让依赖异步加载结果的模块继续执行,二是缓存加载结果。

关于第一点,我们回忆一下之前__webpack_require__.e的内容。 此时该chunk还处于“正在加载”状态,也就是说对应的installedChunks[chunkId]为[resolve,reject,promise]。 而这里,chunk已经被加载了,但是promise还没有被解析,所以webpackJsonpCallback内部定义了一个resolves变量来收集installedChunks上的resolve并执行它。

那么,说到第二点,就涉及到几级缓存了。

第一个是块级别。 这里有两个相关的操作。 操作1.将installedChunks[chunkId]设置为0允许__webpack_require__.e在第二次加载同一个块时返回立即解析的promise(Promise.all([])); 操作二:将chunkdata添加到window["webpackJsonp"]链表中,可以通过多入口的方式方便的获取加载的chunk缓存。 通过如下代码实现:

在模块层面,chunk中的moreModules被合并到入口文件的模块中,可以供下一个微任务中的__webpack_require__同步加载模块。

经过 __webpack_require__.e(0) 返回的 Promise 解析后,可以将 __webpack_require__.bind(null,"./src/utils/math.js") 加载到 chunk 携带的模块中,并将该模块作为以下的输入参数返回接下来是微任务函数,后面是WebpackLoader翻译的其他业务代码。

现在我们来梳理一下异步流程:

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 webpack webpack加载bootstrap-Webpack异步加载配置文件_Webpack是如何工作的? https://www.wkzy.net/game/175523.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务