当前位置: 首页 > 后端技术 > Node.js

webpack2的那些事儿------生成文件的工作原理

时间:2023-04-03 20:43:29 Node.js

感谢大家看我的技术。最近在整理和研究webpack2的配置。webpack是从去年开始使用vue的。个人感觉webpack融入了编程流程,提供了模块化。它通过不同的加载器将各种类型的文件视为模块和进程和代码。这是一种相对较新的编程体验。应该说webpack适用的编程场景比较广泛,可以方便的引入各种第三方npm模块使用,方便快速开发工作。我打算写几篇文章(如果你能坚持==)来总结一下webpack。这篇文章不是教你如何使用webpack,而是让你更好地理解你正在使用的webpack是如何工作的。想来想去,第一篇这篇先介绍如何执行webpack生成的文件。webpack的生成信息首先,我们需要先通过webpack生成文件(废话少说),文中所有代码都会在文末链接,下面是本文所用代码的目录:我们现在只需要关注js目录,里面有两个入口app.js和bar.js,然后会引用es5和es6中的各种测试模块。您可以查看代码了解详细信息。然后代码运行!看到命令行出来了很多信息,像下面这样:首先我们看一下生成的信息:Asset:这个一目了然。它是生成的文件相对于配置中的output.path的路径。可以看到图中生成的文件都在output.path下;然后我们再仔细看一下文件名,比如第一个0.fb6d7f4.js,由[name/chunkname].[hash/chunkhash].js组成,这个可以在output.filename中配置。关于hash和chunkhash的区别,这个会在后面的文章中介绍。size:这个没什么好说的,就是生成文件的大小Chunks:我们会看到有的Chunks是两个数,有的是一个数,其实可能还有更多,经过一堆实验==,我发现在Chunks中第一个数字是这个文件的ChunkId,后面的是当前文件所依赖的文件的ChunkId。从图中可以看出,第一个文件的ChunkId为0,它依赖于3manifest.a890c12.jsChunkId的ChunkId:这是生成文件的chunkName,可以用来进行文件命名。可以看到如果没有在entry中指定,chunkName就会等于chunkId。程序加载过程理解生成的信息,然后我们把项目运行起来(可以使用任何地方来运行项目),通过chrome开发者工具可以看到请求状态。可以看到请求页面html后,依次加载了manifest、index、0、2文件。这里我们先分析文件。拆分和加载过程。切分可以看到页面的js被分成了4个文件。一般来说,一个项目定义一个入口点,webpack会以这个入口点作为入口点进行代码回溯。如果有System.import或require.ensure异步模块调用,webpack会打包单独使用的模块,比如文件中的两个js0和2,如果没有异步模块调用,那么所有的代码都会生成在一个文件中,webpack为了使打包后的代码得到优化,可以使用CommonsChunkPlugin插件对代码进行处理,将库文件单独打包,通过规则生成相应的chunk文件。manifest是默认的chunk,包含了打包文件的运行时信息,以及webpackJsonp模块加载的封装库,所有生成的模块都被webpackJsonp封装。manifest从上图可以看出,浏览器依次加载了manifest、index、0、2文件。manifest相当于模块加载的webpack运行时工具,其他文件为逻辑文件;在manifest中封装了webpackJsonpCallback方法和__webpack_require__方法之后,下面分析一下:webpack在生成每个chunk的时候使用这个方法来打包每个chunk。我们会把上面看到的chunksId作为第一个参数,这个chunk包含的modules会以数组的形式传递给第二个参数moreModules。如果chunk中包含可执行模块,则需要通过moduleId输入第三个参数executeModule,下面是该方法的代码片段:该方法主要做了以下几件事:loadchunk我们可以看到,该方法使用了第一个循环来将chunkIds分别处理成installedChunks对象,installedChunks对象用于记录chunk的加载状态。用0表示当前chunkId已经加载,用长度为3的数组表示当前chunk正在加载。数据实际上存储了加载过程中的resolve方法、reject方法和promise。对象,仅通过require.ensure或System.import出现。因此,我们可以看到,在第一个for循环中,判断如果chunkId在installedChunks中存在且不为0,则判断异步加载模块加载成功,将chunk的resolve方法传入resolves数组,后面运行,然后将chunk对应的state设置为0,如果判断后不存在,则认为这是一个同步加载的chunk,直接设置为0,说明该块已被加载。加载模块加载模块的逻辑相对简单。判断模块不存在后,写入modules参数,运行需要执行的模块。如果executeModule存在,则运行moduleId对应的模块__webpack_require__:该对象包含多个方法,主要用于模块和块的加载、处理和运行。下面一一分析:__webpack_require__(moduleId):代码如下。此方法接收一个moduleId,构建一个模块对象并将其存储在installedModules中,并对模块进行初始化。最后返回module.export__webpack_require__.e(chunkId):该方法用于异步加载chunk文件。代码如下:该方法一般加载一个脚本文件,生成一个promise对象,当脚本加载完成后运行,会执行前面的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增加了对ES6MODULE的支持。下面的__webpack_require__用于ES6:__webpack_require__.d:代码如下:这个是针对ES6中命名的export,比如webpack遇到这种export,会用__webpack_require__.d打包成:__webpack_require__。i:用于返回正确上下文的函数,用于当export直接为runnable方法时,以上是webpackmanifest中大部分重要的函数,主要是通过webpackJsonpCallback注册加载相应的chunk文件,处理通过__webpack_require__建立模块关系。综上所述,整个webpack在运行时都是通过manifest来控制和处理的。webpackJsonpCallback对应的是加载chunk文件的处理,__webpack_require__是加载模块的处理。了解这些可以让我们更好的优化我们的代码,帮助我们调试代码,帮助我们解决复杂情况下的问题,提供一些其他的思路。最后附上代码:先介绍一下,webpack-base是我在使用webpack过程中总结的一套脚手架。文档不完整。如果您需要文档,可以在问题中提及。这个项目是在分支上开发的。代码点这里