继React,Vue,这是第三个着重阅读源码的前端项目-Webpack。本文主要以:前端
三个方向展开。node
欢迎Star和订阅 个人博客。
诚然Webpack这是一个前端工程化工具,理解容易, 使用简单,彷佛没有深刻研究的必要。那为何还要费心费力阅读其源码?这,把正在写此篇文章的我也问住了。理提纲时,认为WHY最好写,几句话就可带过,但事实证实真要较真这一块还值得一说。
擅自揣测下会阅读Webpack源码伙伴可能的动机:react
做者最早是缘由是4,而后是1,2。固然,1,2应该是大多数人看项目源码的动机。webpack
要阅读源码,首先拿到源码,而后最后能边调试边阅读。固然,若是智力和推理能力惊人,大能够直接在Github上在线阅读。
有2中方法下载源码。一种是最多见的git clone,将Github上webpack项目clone到本地,pull后与webpack官方最新代码保持一致,一劳永逸。不过做者尝试第一种方法时,老是clone不下来,很大多是因为webpack源文件过大且github服务器clone一直很慢。
因而退而求其次,使用第二种方法:下载Webpack源码release版本。选择一个打算阅读的webpack源码版本,直接下载"Source code(zip)"便可。速度很是快,由于不包含.git。git
IDE做者使用VSCode,调试node很方便。拿到源码后,在目录新建一个文件夹,写一个简单的webpack案例,而后使用VSCode进行调试。
不过,在实际操做中,直接使用下载源码中的webpack.js调试可能会出现报错Cannot find module 'json-parse-better-errors'
或Cannot find module 'webpack/lib/RequestShortener'
,只需运行npm install webpack webpack-cli --save-dev
,便可解决报错,且不影响调试源码。github
此附做者在调试时使用版本参考,下载后使用VSCode打开webpack-4.41.4(modified),安装依赖,安装webpack和webpack-cli,按F5便可启动调试。web
Webpack源码量庞大,把每一行代码都读懂确实没有必要,可是咱们至少要知道它的总体运行流程,知道它反复用到的核心代码,以及各个模块的生命周期如何运转。npm
代码量大,想要在走总体流程时刚好找核心功能的源码,困难重重,至少对于webpack源码是这样,由于其独特的插件和回调结构。
不过,咱们能够根据每个想要了解的核心功能,单独去寻找和阅读相关源码。好比,若是咱们想看webpack如何打包生成bundle.js,可经过webpack必定会调用NodeJS文件系统输出文件方法,全局搜索"writeFile"找到相关代码,或经过bundle.js中的关键字"// Check if module is in cache"进行搜索。json
经过边调试边阅读代码,了解代码总体走向以及webpack如何打包生成bundle.js,做者学到了如下内容:前端工程化
Tapable在源码中应用随处可见,要了解源码,首先得学习tapable机制。其实它并不复杂,而且咱们只须要知道它的基本做用和用法便可。
Tapable 可理解为一套钩子回调函数机制,每个钩子可订阅多个函数,发布钩子时会运行该钩子订阅该的多个函数。
用一个简单案例说明。
const { SyncHook } = require('tapable') class Car { constructor() { this.hooks = { // # 添加一个钩子 start: new SyncHook() } } } const car = new Car() // start钩子订阅一个函数 car.hooks.start.tap( 'run slowly', () => console.log('start running slowly') ) // start钩子订阅另外一个函数 car.hooks.start.tap( 'run mediumly', () => console.log('start running mediumly') ) // 发布钩子 car.hooks.start.call() // 输出: run slowly run mediumly
未压缩的bundle.js文件结构通常以下:
/******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; ....
那么Webpack如何生成这些内容?
其实Webpack对于内容分两步处理,第一步先经过loader(默认为babel-loader)生成组合JS代码。第二步将组合JS代码放入webpack默认函数中,从而避免变量泄露。
如打包前: foo.js
export const foo = () => 'hello foo!'
bar.js
import { foo } from './foo.js' foo() console.log( 'hello bar!' )
打包第一步,经过loader(默认为babel-loader)生成组合JS代码:
... const foo = () => 'hello foo!' ... \r\n__WEBPACK_MODULE_REFERENCE__0_666f6f_call__()\r\nconsole.log( 'hello bar!' ) ...
打包第二步,组合JS代码放入webpack默认函数中。
/******/ (function(modules) { // webpackBootstrap\n ... const foo = () => 'hello foo!' ... foo() console.log( 'hello bar!' ) ...
值得注意的是,核心文件为ConcatenatedModule.js
, 经过遍历modulesWithInfo
从而生成打包代码。
1 . runtime
是什么?
无论在webpack源码,仍是Vue源码和其余地方,runtime常常出现。runtime到底是什么?
通过反复查阅资料和推敲,runtime代码能够理解为编译后生成的代码。好比,对于React,runtime代码就是编译JSX代码后生成的JS代码。对于Vue,runtime代码则是编译template,script,style后生成的JS代码。
2 . 热更新,Code Splitting, Tree-shaking等是如何实现?
Webpack内容较多,核心模块原理也很多,好比loader如何运转,Code Splitting如何实现,Tree-Shaking和热加载又是怎么作到的。但毕竟时间有限,这次阅读源码的目标不是大而全的弄懂全部内容,而是掌握Webpack的主要运转流程以及了解较为感兴趣的几个模块。因此其余模块原理之后有机再加入此文。对相应模块模块感兴趣的伙伴可网上先自行搜索相关内容。
感谢你花时间阅读这篇文章。若是你喜欢这篇文章,欢迎点赞、收藏和分享,让更多的人看到这篇文章,这也是对我最大的鼓励和支持!
欢迎Star和订阅个人原创前端技术博客。