前端如何开始看框架源码?

发布于:2023-07-22 15:16:03

本文主要分享阅读大型前端开源比如:React、Vue、Webpack、Babel源码的一些技巧。目的是让大家在遇到需要阅读源码才能解决的问题时,可以快速定位到自己想看的代码。

一、为什么看源码?

*先,我们要明确的是,看源码的目前第是什么。

黑马意见,看源码是为了解决问题。开源项目的源码好是好,但是代码的数量级巨大,想要从源码中学习东西,直接浏览整个Codbase,简直是大海捞针。

但是如果带着问题看源码,比如了解一下React的合成事件系统的原理,想了解React的setState前后发生了什么,或者想了解webpack插件系统的原理。也可能是遇到了一个bug,怀疑是框架/工具的问题。在这样的情况下,带着一个具体的目标去看源码,就会轻松很多。

二、看最新版的源码

网上好多人说,看源码要从项目的第一个commit开始看,如果是为了解决前文中对框架/工具产生的困惑,那自然是要看当前项目中用到的框架/工具版本。

如果是为了学习源码,这里也建议大家看最新的。因为一个项目是在不断迭代和重构的。不同版本之间可能是一次完全的重写。

三、如何开始看源码

看源码之前要对项目的原理有一个基本的了解,所谓的原理就是,这个项目有哪些部分组成,为了达到最终的产出,要经过那几步流程。这些流程里,业界主流的方案有哪几种。

比如前端 View 层框架,要渲染出 UI,组件要经过 mount、 render 等等步骤。数据驱动的前端框架,在 mounted 之后,就会进入一个循环,当用户交互触发组件数据变化时,会更新 UI。其中数据的检测方式又有分 Push 和 Pull 两种方案。渲染 UI 可以是全量的字符串模板替换,也可以是基于 Virtual DOM 的差量 DOM 更新。

又比如前端的一些工具,Webpack 和 Babel 这些工具都是基于插件的。基本的工作流程就是读取文件,解析代码成 AST,调用插件去转换 AST,最后生成代码。要了解 Webpack 的原理,就要知道 Webpack 基于一个叫 tapable 的模块系统。

那我们要如何了解这些呢?要了解这些,可以去各大网站和博客上的《XXX源码解析》系列。通过这些文章,我们可以对我们要看的框架/工具的原理有一个大致的了解。

本地build不过最终我们还是要直接看源码。笔者真正看源码的第一步就是把项目的代码仓库 clone 到本地。然后按项目 README 上的构建指南,在本地 build 一下。

如果是前端框架,我们可以在 HTML 中里直接引入本地 build 出的 umd bundle(记得用 development build,不然会把代码压缩,可读性差),然后写一个简单的 demo,demo 里引入本地的 build。如果是基于 Nodejs 的工具,我们可以用 npm link 把这个工具的命令 link 到本地。也可以直接看项目的 package.json 的入口文件,直接用 node 运行那个文件。

这里要强调一下,大型的开源项目一般都会有一个 Contribution Guide,目的是让想贡献代码的开发者更快上手。里面就有讲怎么在本地构建代码。

以 React 为例,React 的 Contributing Guide 里就 Development Workflow 这一节。里面有这么一段话:

The easiest way to try your changes is to run yarn build core,dom type=UMD and then open fixtures/packaging/babel-standalone/dev.html. This file already uses react.development.js from the build folder so it will pick up your changes.

所以 React 仓库中的 fixtures/packaging/babel-standalone/dev.html 就是一个方便的 demo 页。我们可以在这个页面快速查看我们在本地对代码的改动。

你可以尝试着在项目的入口文件中加入一句 log,看看是不是可以在控制台/终端看到这句 log。如果可以的话,恭喜你,你现在可以随便把玩这个项目了!

四、清理目录结构

在看具体的代码之前,我们需要理清项目的目录结构,这样我们才能更快的知道在哪里地方找相关功能的代码。

我们看看 React 的目录结构。React 是一个 monorepo。也就是一个仓库里包含了多个子仓库。我们在 packages 目录下可以看到很多单独的 package:

在 React 16之后,React 的代码分为 React Core,Renderer 和 Reconciler 三部分。这是因为 React 的设计让我们可以把负责映射数据到 UI 的 Reconciler 以及负责渲染 Vritual DOM 到各个终端的 Renderer 和 React Core 分开。React Core 包含了 React 的类定义和一些顶级 API。大部分的渲染和 View 层 diff 的逻辑都在 Reconciler 和 Renderer 中。

Babel 也是一个 monorepo。Babel 的核心代码是 babel-core 这个 package,Babel 开放了接口,让我们可以自定义 Visitor,在AST转换时被调用。所以 Babel 的仓库中还包括了很多插件,真正实现语法转换的其实是这些插件,而不是 babel-core 本身。

Vuejs 的代码比较典型,核心代码在 src 目录下,按功能模块划分。因为 Vue 也支持多平台渲染,所以把平台相关的代码都放到了 platform 文件夹下,core 文件夹中是 Vue 的核心代码,compiler 是 Vue 的模板编译器,把 HTML 风格的模板编译为 render function。

Webpack 和 Babel 一样,可以说都是基于插件的系统。Webpack 的主要源码在 lib 目录下,里面的 webpack.js 就是入口文件。

上面说了四个项目的目录结构,那我们遇到一个新的开源项目,应该怎么了解它的目录结构呢?

如果这个项目是一个 monorepo,*先我们要找到核心的那个 package,然后看里面的代码。

不是 monorepo 的话,一般来说,如果这个项目是一个 CLI 的工具,那 bin 目录下放的就是命令行界面相关的入口文件,lib 或者 src 下面就是工具的核心代码。如果这个项目是一个前端 View 层框架,那目录结构就和 Vue 类似。

作为验证,大家可以看一下打包工具 parcel 和前端 View 层库 moon 的目录结构。目录结构这个东西往往是大同小异,多看几个项目就熟悉了。

debugger &&全局搜索大法运行了本地的 build,了解了目录结构,接下来我们就可以开始看源码了!之前说了,我们要以问题驱动,下面我就以 React 调用 setState 前后发生了什么这个问题作为例子。

我们可以在 setState 的地方打一个断点。*先我们要找到 setState 在什么地方。这个时候之前的准备工作就派上用处了。我们知道 React 的共有 API 在 react 这个 package 下面。我们就在那个 package 里面全局搜索。我们发现这个 API 定义在 src/ReactBaseClasses.js 这个文件里。

于是我们就在这里打一个断点:

Component.prototype.setState = function(partialState, callback){ invariant( typeof partialState ===object typeof partialState ===function partialState == null,setState(...): takes an object of state variables to update or a + function which returns an object of state variables.,); debugger; this.updater.enqueueSetState(this, partialState, callback,setState);};

然后运行本地 React build 的 demo 页面,让组件触发 setState,我们就可以在 Devtool 里看到断点了。

我们走进 this.updater.enqueueSetState 这个调用,就来到了 ReactFiberClassComponent 这个函数中的 enqueueSetState,这里调用了 enqueueUpdate 和 scheduleWork 两个函数,如果要深入 setState 之后的流程,我们只需要再点击走进这两个函数里看具体的代码就可以了。

如果想看 setState 之前发生了什么,我们只需要看 Devtool 右边的调用栈:

点击每一个 frame 就可以跳到对应的函数中,并且恢复当时的上下文。

结合一步一步的代码调试,我们可以看到框架的函数调用栈。对于每个重要的函数,我们可以在仓库里搜索到源码,进一步研究。

Node 工具的调试方法也是相似的,我们可以在运行 node 命令时加上 inspect 参数。

其实大家都知道单步调试这种办法,但在哪里打断点才是最关键的。我们在熟悉框架的原理之后,就可以在框架的关键链路上打断点,比如前端 View 层框架的声明周期钩子和 render 方法,Node 工具的插件函数,这些代码都是框架运行的必经之地,是不错的切入点。

如果是为了了解一个特定的问题,大家可以直接在自己觉得有问题的地方打断点。然后把源码运行起来,想办法让代码运行到那个地方。我们在断点可以看到局部变量等等信息,有助于定位问题。

五、善用工具

Octotree,浏览器扩展,在github上面显示代码树,对你了解整个项目结构有着非常大的帮助webstorm,这个看个人喜好吧,笔者比较喜欢WS,主要是里面的工具比较全面,比如支持typescript、babel等等一些前端经常用到的工具SourceTree,git可视化客户端工具,如果你喜欢从第一个commit开始看,那么这个工具对你比较有帮助,看看快速了解到每个版本提交的内容以及源码变更记录,笔者以前比较喜欢用这个,但是后面WS有自带的可视化工具之后就没用过了。


免责声明:本站所有内容及图片均采集来源于网络,并无商业使用,如若侵权请联系删除。

上一篇:WordPress 插件被曝重大 bug,超 20 万个网站受影响

下一篇:如何设计不同类型网站?

资讯 观察行业视觉,用专业的角度,讲出你们的心声。
MORE

I NEED TO BUILD WEBSITE

我需要建站

*请认真填写需求信息,我们会在24小时内与您取得联系。