这是继React和Vue之后,第三个专注于阅读源码的前端项目——Webpack。本文主要基于:WHY:为什么要阅读Webpack源码HOW:如何阅读Webpack源码WHAT:阅读源码你学到了什么?欢迎Star和订阅我的博客。WHY确实Webpack是一个前端工程化工具,简单易懂,好用,似乎也没有深入研究的必要。那为什么还要费心阅读它的源代码呢?这个,还问我这篇文章是谁写的。分析大纲的时候,我觉得写WHY最好,几句话就可以覆盖,但事实证明,如果是真的,也值得一提。本人将擅自阅读Webpack源码。合作伙伴可能的动机:丰富的工作经验和技术爱好者。了解正在发生的事情对于了解原因也是必要的。同时,学习方法与工作或个人项目有关。参考学习看到有人写相关的文章,也看看。笔者先从原因4说起,然后是1、2。当然,1、2应该是大多数人看项目源码的动机。如何搭建源码调试环境阅读源码,首先是获取源码,最后是边读边调试。当然,如果你的智力和推理能力惊人,可以直接在Github上在线阅读。下载源代码有2种方式。一种是最常见的gitclone,将Github上的webpack项目clone到本地,拉取后与webpack官方最新代码一致,一劳永逸。但是笔者在尝试第一种方法时,总是克隆失败,很有可能是因为webpack源文件太大,github服务器克隆一直很慢。所以最好的办法是使用第二种方法:下载Webpack源代码的发布版本。选择你想阅读的webpack源码版本,直接下载“源码(zip)”。非常快,因为没有包含.git。IDE作者使用VSCode,调试node非常方便。拿到源码后,在目录下新建一个文件夹,写一个简单的webpack案例,然后用VSCode调试。但是在实际运行中,直接在下载的源码中使用webpack.js调试可能会报错Cannotfindmodule'json-parse-better-errors'或者Cannotfindmodule'webpack/lib/RequestShortener',npminstallwebpack即可webpack-cli--save-dev可以在不影响调试源码的情况下解决错误。本附件作者在调试时使用版本参考。下载后用VSCode打开webpack-4.41.4(修改),安装依赖,安装webpack和webpack-cli,按F5开始调试。调试,整理Webpack源码的大致路径是巨大的,确实没有必要去了解每一行代码,但我们至少要知道它的整体运行流程,知道它反复使用的核心代码,以及它的生命周期每个模块如何工作。找到核心功能的源码是一大堆代码,走遍整个过程很难找到核心功能的源码,至少webpack的源码是这样,因为它独特的插件-in和回调结构。不过,我们可以针对每一个我们想了解的核心功能,分别查找并阅读相关的源码。比如我们想看webpack是如何打包生成bundle.js的,肯定可以通过webpack调用NodeJS文件系统输出文件的方法,全局搜索“writeFile”找到相关代码,或者使用关键字“//检查bundle.js模块是否在缓存中”进行搜索。What通过边调试边阅读代码,了解代码的整体走向以及webpack是如何打包生成bundle.js的,笔者了解到:tapable插件简化版中bundle.js内容是如何生成的Tapable机制在源代码中随处可见。要想看懂源码,首先要了解tapable机制。其实它并不复杂,我们只需要知道它的基本功能和用法就可以了。Tapable可以理解为一个hook回调函数机制。每个钩子可以订阅多个函数。当一个钩子被发布时,它会运行这个钩子来订阅多个函数。用一个简单的例子来说明。const{SyncHook}=require('tapable')classCar{constructor(){this.hooks={//#添加一个钩子start:newSyncHook()}}}constcar=newCar()//开始钩子订阅一个函数car.hooks.start.tap('runslowly',()=>console.log('startrunningslowly'))//starthook订阅另一个函数car.hooks.start.tap('runmediumly',()=>console.log('startrunningmediumly'))//释放钩子car.hooks.start.call()//输出:runslowlyrunmedium简化版Webpack运行过程bundle.js内容生成未压缩的bundle.js文件结构一般如下:/******/(function(modules){//webpackBootstrap/******///模块缓存/******/varinstalledModules={};/******//******///require函数/******/function__webpack_require__(moduleId){/******//******///检查模块是否在缓存中/******/if(installedModules[moduleId]){/******/returninstalledModules[moduleId].exports;/******/}/******///创建一个新模块(并将其放入cache)/******/varmodule=installedModules[moduleId]={/******/i:moduleId,/******/l:false,/******/exports:{}/******/};....那么Webpack是如何生成这些的呢?事实上,Webpack分两步处理内容。第一步是通过loader(默认是babel-loader)生成合并后的JS代码。第二步,将合并后的JS代码放入webpack默认函数中,避免变量泄露。比如打包前:foo.jsexportconstfoo=()=>'hellofoo!'bar.jsimport{foo}from'./foo.js'foo()console.log('hellobar!')第一个一步打包,通过loader(默认babel-loader)生成组合JS代码:...constfoo=()=>'hellofoo!'...\r\n__WEBPACK_MODULE_REFERENCE__0_666f6f_call__()\r\nconsole.log('你好吧!')...打包的第二步是将JS代码组合到webpack默认的函数中。/******/(function(modules){//webpackBootstrap\n...constfoo=()=>'hellofoo!'...foo()console.log('hellobar!')...值得注意的是,核心文件是ConcatenatedModule.js,通过遍历modulesWithInfo生成打包代码常见问题1.什么是runtime?不管是在webpack源码,Vue源码还是其他地方,runtime经常出现,什么是运行时?什么?经过反复参考和推敲,运行时代码可以理解为编译后生成的代码。比如对于React,运行时代码就是JSX代码编译后生成的JS代码。对于Vue来说,运行时代码就是模板、脚本、样式编译后生成的JS代码。2、如何实现热更新、CodeSplitting、Tree-shaking等?Webpack有很多内容和核心模块原理,比如loader如何工作,如何实现CodeSplitting,如何实现Tree-Shaking和hotloading。但毕竟时间有限。这次阅读源码的目的不是为了大篇幅了解所有内容,而是掌握Webpack的主要运行流程,了解几个比较有趣的模块。因此,以后会把其他模块的原理有机的加入到本文中。对相应模块感兴趣的小伙伴可以先上网搜索相关内容。阅读源码资源推荐how-react-works.pdfExplainwebpack-吴浩林帮助开发者更好的理解webpack的工作原理:artsy-webpack-tourbuildyourownwebpack感谢您抽空阅读本文。如果喜欢这篇文章,请点赞收藏分享,让更多人看到这篇文章,这也是对我最大的鼓励和支持!欢迎Star订阅我的前端技术原创博客。
