谢谢大家看我扯技术,最近在对webpack2
进行的配置进行梳理和学习,webpack
是在去年使用vue
开始接触的,我的感受webpack
融入到编程过程当中,提供了模块化,将各类类型的文件都当作模块,经过不一样的 loader
进行处理和代码组织,是一个比较新颖的编程体验,应该说webpack
的编程适用场景比较普遍,可以比较方便的引入第三方的各类 npm 模块进行使用, 方便快速开发工做。
打算写几篇文章(若是能坚持的话= =)来总结下 webpack
,文章不是教你怎么使用webpack
,而是让你更好的了解你在使用的webpack
是怎么去运行的 ,想来想去,第一篇就先介绍下webpack
生成的文件,是怎么去执行的。html
首先咱们要先经过 webpack 去生成文件(好一句废话),文章全部的代码都会在文章最后面给出连接,下面是本文章使用的代码的目录:vue
咱们如今只要关注js
目录,里面有两个入口 app.js
、bar.js
,而后会引用 es5,es6中的各类测试模块,具体你们能够看代码。而后代码一跑!只见命令行蹭蹭蹭跑出来了好多信息,像下面同样:webpack
首先咱们来看下生成的信息:git
Asset
: 这个一看就明白是生成的文件相对于配置中output.path
的路径,能够看到图中生成的文件都是在 output.path
底下的;而后咱们仔细看下文件名,好比第一个0.fb6d7f4.js
,是由[name/chunkname].[hash/chunkhash].js
组成的,这个能够在output.filename
中配置,关于hash
和chunkhash
的区别,这个后面会专门经过一篇文章进行简介。es6
Size
: 这个就没啥好说的,就是生成文件的大小github
Chunks
: 咱们会看到有些 Chunks
是两个数字,有些是一个,其实还可能出现更多,通过个人一堆实验= =,发现Chunks
中的第一个数字,就是这个文件的 ChunkId
,然后面的是当前这个文件依赖的文件的ChunkId
,从图中咱们能够看到,第一个文件的ChunkId
是0
,它依赖的是ChunkId
为3
的manifest.a890c12.js
web
Chunk Names
: 这个就是这个生成文件的chunkName
,能够用于文件命名,能够看到若是没有在entry
中指定,那么chunkName
会等于chunkId
chrome
了解了生成的信息,接下来咱们把项目跑起来(能够用 anywhere
跑项目),经过chrome developer tool
能够看到请求状况npm
能够看到请求了页面html以后,按顺序分别加载了 manifest
,index
,0
,2
文件,这里咱们先来分析下文件的分割和加载流程。编程
能够看到页面的 js 被分割成为了4个文件,一般来讲,一个项目定义了一个 entry point
,webpack
会以这个entry point
做为入口,进行代码回溯,若是存在System.import
或者是require.ensure
的异步模块调用,webpack
会对使用的模块进行单独打包,好比文件中的0
、2
这两个 js,若是没有异步模块调用,那么会将全部的代码生成在一个文件中,webpack
为了使得打包的代码进行优化,可使用CommonsChunkPlugin
插件对代码进行处理,将库文件单独打包,经过规则生成对应的 chunk
文件,其中的manifest
为 默认的 chunk
,其中包含了打包文件的runtime
信息,还有webpackJsonp
模块加载的封装库,全部的生成模块都是采用webpackJsonp
进行封装的。
从上面的图中能够看到,浏览器按顺序分别加载了 manifest
,index
,0
,2
文件,其中manifest
至关于webpack
的runtime
工具,用于作模块加载,其余文件是逻辑文件; manifest
中封装了webpackJsonpCallback
方法和__webpack_require__
方法,下面咱们来进行分析:
webpackJsonpCallback(chunkIds, moreModules, executeModule)
:webpackJsonpCallback
是chunk封装的包装方法,webpack
在生成每个chunk
的时候都是经过这个方法进行包装的,咱们在上面看到的 chunksId
,会做为第一个参数,被包含进这个chunk
的module
会被以数组的形式传入第二个参数moreModules
中,若是这个chunk
中包含能够执行的modules
,须要将 moduleId
传入第三个参数 executeModule
中,下面是 这个方法的代码片断:这个方法主要作了下面几件事:
咱们能够看到这个方法用第一个循环分别将chunkIds
处理进入installedChunks
对象中,installedChunks
对象用于记录chunk
的加载状况,分别用0
表示当前的chunkId
已经加载完成,用一个长度为3的数组表示当前的chunk
正在加载中,数据中其实存储着加载过程当中的resolve
方法、reject
方法和pormise
对象,这种只在经过require.ensure
或者是System.import
才会出现。所以咱们能够看到,第一个for
循环中判断若是chunkId
在 installedChunks 中存在且不为0,则判断是异步加载的模块已经加载成功,将chunk
的resolve
方法传入resolves
数组,而后后面运行,而后将chunk
对应的状态设置为0
。若是判断以后不存在,这认为这是一个同步加载的chunk
,直接设置为0
,表示chunk
已经加载完毕。
加载 module
的逻辑比较简单,判断纯不存在这个module
以后,将 其写入modules
参数之中
module
若是executeModule
存在,则对其中对应moduleId
的模块进行运行
__webpack_require__
: 这个对象包含了多个方法,主要用于module
和chunk
的加载,处理和运行,下面咱们一个一个分析:
__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
:这个是和webpack
的output.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
里面提,本次的项目在分支上面开发,代码点击这里