资讯专栏INFORMATION COLUMN

webpack2的那些事儿 ------ 生成的文件是怎么运行的

anonymoussf / 1389人阅读

摘要:打算写几篇文章如果能坚持的话来总结下,文章不是教你怎么使用,而是让你更好的了解你在使用的是怎么去运行的,想来想去,第一篇就先介绍下生成的文件,是怎么去执行的。

谢谢你们看我扯技术,最近在对webpack2进行的配置进行梳理和学习,webpack是在去年使用vue开始接触的,个人感觉webpack 融入到编程过程中,提供了模块化,将各种类型的文件都看成模块,通过不同的 loader 进行处理和代码组织,是一个比较新颖的编程体验,应该说webpack的编程适用场景比较广泛,能够比较方便的引入第三方的各种 npm 模块进行使用, 方便快速开发工作。
打算写几篇文章(如果能坚持的话= =)来总结下 webpack,文章不是教你怎么使用webpack,而是让你更好的了解你在使用的webpack是怎么去运行的 ,想来想去,第一篇就先介绍下webpack生成的文件,是怎么去执行的。

webpack 的生成信息

首先我们要先通过 webpack 去生成文件(好一句废话),文章所有的代码都会在文章最后面给出链接,下面是本文章使用的代码的目录:

我们现在只要关注js目录,里面有两个入口 app.jsbar.js,然后会引用 es5,es6中的各种测试模块,具体大家可以看代码。然后代码一跑!只见命令行蹭蹭蹭跑出来了好多信息,像下面一样:

首先我们来看下生成的信息:

Asset : 这个一看就明白是生成的文件相对于配置中output.path的路径,可以看到图中生成的文件都是在 output.path底下的;然后我们仔细看下文件名,比如第一个0.fb6d7f4.js,是由[name/chunkname].[hash/chunkhash].js组成的,这个可以在output.filename 中配置,关于hashchunkhash的区别,这个后面会专门通过一篇文章进行简介。

Size : 这个就没啥好说的,就是生成文件的大小

Chunks : 我们会看到有些 Chunks是两个数字,有些是一个,其实还可能出现更多,经过我的一堆实验= =,发现Chunks中的第一个数字,就是这个文件的 ChunkId,而后面的是当前这个文件依赖的文件的ChunkId,从图中我们可以看到,第一个文件的ChunkId0,它依赖的是ChunkId3manifest.a890c12.js

Chunk Names : 这个就是这个生成文件的chunkName,可以用于文件命名,可以看到如果没有在entry中指定,那么chunkName会等于chunkId

程序加载流程

了解了生成的信息,接下来我们把项目跑起来(可以用 anywhere 跑项目),通过chrome developer tool可以看到请求情况

可以看到请求了页面html之后,按顺序分别加载了 manifest,index,0,2文件,这里我们先来分析下文件的分割和加载流程。

分割

可以看到页面的 js 被分割成为了4个文件,通常来说,一个项目定义了一个 entry point,
webpack会以这个entry point作为入口,进行代码回溯,如果存在System.import或者是require.ensure的异步模块调用,webpack会对使用的模块进行多带带打包,比如文件中的02这两个 js,如果没有异步模块调用,那么会将所有的代码生成在一个文件中,webpack 为了使得打包的代码进行优化,可以使用CommonsChunkPlugin插件对代码进行处理,将库文件多带带打包,通过规则生成对应的 chunk 文件,其中的manifest为 默认的 chunk,其中包含了打包文件的runtime信息,还有webpackJsonp模块加载的封装库,所有的生成模块都是采用webpackJsonp进行封装的。

manifest

从上面的图中可以看到,浏览器按顺序分别加载了 manifest,index,0,2文件,其中manifest相当于webpackruntime工具,用于做模块加载,其他文件是逻辑文件; manifest中封装了webpackJsonpCallback方法和__webpack_require__方法,下面我们来进行分析:

webpackJsonpCallback(chunkIds, moreModules, executeModule):webpackJsonpCallback是chunk封装的包装方法,webpack在生成每一个chunk的时候都是通过这个方法进行包装的,我们在上面看到的 chunksId,会作为第一个参数,被包含进这个chunkmodule会被以数组的形式传入第二个参数moreModules中,如果这个chunk中包含可以执行的modules,需要将 moduleId传入第三个参数 executeModule中,下面是 这个方法的代码片段:
这个方法主要做了下面几件事:

加载chunk

我们可以看到这个方法用第一个循环分别将chunkIds处理进入installedChunks对象中,installedChunks对象用于记录chunk的加载情况,分别用0表示当前的chunkId已经加载完成,用一个长度为3的数组表示当前的chunk正在加载中,数据中其实存储着加载过程中的resolve方法、reject方法和pormise对象,这种只在通过require.ensure或者是System.import才会出现。因此我们可以看到,第一个for循环中判断如果chunkId在 installedChunks 中存在且不为0,则判断是异步加载的模块已经加载成功,将chunkresolve方法传入resolves数组,然后后面运行,然后将chunk对应的状态设置为0。如果判断之后不存在,这认为这是一个同步加载的chunk,直接设置为0,表示chunk已经加载完毕。

加载 module

加载 module 的逻辑比较简单,判断纯不存在这个module之后,将 其写入modules参数之中

运行需要执行的module

如果executeModule存在,则对其中对应moduleId的模块进行运行

__webpack_require__: 这个对象包含了多个方法,主要用于modulechunk的加载,处理和运行,下面我们一个一个分析:

__webpack_require__(moduleId) :代码如下
这个方法接收一个moduleId,构建一个 module 对象存入installedModules中,并且初始化这个 module, 最后返回module.export

__webpack_require__.e(chunkId) : 这个方法用于通过异步的方式加载 chunk 文件,代码如下:
这个方法总体来说就是加载一个 script 文件,生成一个 promise对象,当 script 加载完成后运行,又会执行前面的webpackJsonpCallback注册chunk,然后promise.resolve。这里面需要注意的是红框里面的东西,这个涉及到一个优化点,如果没有在使用CommonsChunkPlugin多带带打包manifest,那么一般来说他会和你指定的其他库通过CommonsChunkPlugin打包在一起,那么你会发现即使你只是修改了库之外的逻辑,库文件生成的文件的hash或者是chunkhash也是会变的,原因就在于manifest中红框部分是动态生成的,导致文件的 hash 产生变化,不利于缓存,因此建议多带带打包manifest

__webpack_require__.oe:定义一个统一的错误处理函数

__webpack_require__.p:这个是和webpackoutput.publicPath对应的值

__webpack_require__.o: Object.prototype.hasOwnProperty的封装
前面几个方法在 ES5的情景下面已经足够运行这个模块系统,我们都知道webpack2加入了对ES6 MODULE的支持,下面几个__webpack_require__是为ES6使用的:

__webpack_require__.d:代码如下:
这个是用于ES6中命名的export比如 webpack 遇到这种export,会对其用__webpack_require__.d进行包装,变成:

__webpack_require__.i:用于返回一个正确的上下文的函数回去,针对的是export直接为一个可运行方法的时候

以上就是webpack manifest中的大部分重要的函数,其实主要就是通过webpackJsonpCallback来注册载入对应的chunk文件,通过__webpack_require__来处理模块的关系。

总结

整个webpack 的在运行时都是通过 manifest去做控制处理的, webpackJsonpCallback对应的是对加载的chunk文件的处理,__webpack_require__是对加载模块的处理,了解这些可以使我们更好的去优化我们的代码,帮助我们去调试代码,帮助我们在复杂情况下去解决问题提供一些其他的思路。

最后附上代码:先介绍下,webpack-base是我在使用webpack的过程中自己总结的一套脚手架,文档还没有完善,如果需要文档可以在issue里面提,本次的项目在分支上面开发,代码点击这里

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81789.html

相关文章

  • 无痛学会各种 2 Vue2+Vuex2+Webpack2 前后端同构渲染

    摘要:它会检测出最大静态子树就是不需要动态性的子树并且从渲染函数中萃取出来。这样在每次重渲染的时候,它就会直接重用完全相同的同时跳过比对。需要注意的是,中的操作必须是同步的,不可以存在异步操作的情况。 新增:哈哈,最近又推出了 vue 的文章,在这里放个链接~手把手教你从零写一个简单的 VUE 感谢有人看我扯技术,这篇文章主要介绍最近非常火的vue2前端框架的特点和vue2+vuex2+we...

    fish 评论0 收藏0
  • 无痛学会各种 2 Vue2+Vuex2+Webpack2 前后端同构渲染

    摘要:它会检测出最大静态子树就是不需要动态性的子树并且从渲染函数中萃取出来。这样在每次重渲染的时候,它就会直接重用完全相同的同时跳过比对。需要注意的是,中的操作必须是同步的,不可以存在异步操作的情况。 新增:哈哈,最近又推出了 vue 的文章,在这里放个链接~手把手教你从零写一个简单的 VUE 感谢有人看我扯技术,这篇文章主要介绍最近非常火的vue2前端框架的特点和vue2+vuex2+we...

    30e8336b8229 评论0 收藏0
  • 无痛学会各种 2 Vue2+Vuex2+Webpack2 前后端同构渲染

    摘要:它会检测出最大静态子树就是不需要动态性的子树并且从渲染函数中萃取出来。这样在每次重渲染的时候,它就会直接重用完全相同的同时跳过比对。需要注意的是,中的操作必须是同步的,不可以存在异步操作的情况。 新增:哈哈,最近又推出了 vue 的文章,在这里放个链接~手把手教你从零写一个简单的 VUE 感谢有人看我扯技术,这篇文章主要介绍最近非常火的vue2前端框架的特点和vue2+vuex2+we...

    Pluser 评论0 收藏0
  • [聊一聊系列]聊一聊iconfont那些事儿

    摘要:欢迎大家收看聊一聊系列,这一套系列文章,可以帮助前端工程师们了解前端的方方面面不仅仅是代码从说起要想了解,得从一个新的规则说起。因为用户没有安装的话,我们强制要求显示也没有办法。国内有阿里巴巴的平台,可以选自己喜欢的图标导出。 欢迎大家收看聊一聊系列,这一套系列文章,可以帮助前端工程师们了解前端的方方面面(不仅仅是代码):https://segmentfault.com/blog/fr...

    Markxu 评论0 收藏0
  • [聊一聊系列]聊一聊iconfont那些事儿

    摘要:欢迎大家收看聊一聊系列,这一套系列文章,可以帮助前端工程师们了解前端的方方面面不仅仅是代码从说起要想了解,得从一个新的规则说起。因为用户没有安装的话,我们强制要求显示也没有办法。国内有阿里巴巴的平台,可以选自己喜欢的图标导出。 欢迎大家收看聊一聊系列,这一套系列文章,可以帮助前端工程师们了解前端的方方面面(不仅仅是代码):https://segmentfault.com/blog/fr...

    2501207950 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<