本期视频发布于 2022 年。文中的技术状态、个人经历与观点均为当时情况。
准备一本 Webpack 技术小册,让范文杰花了很长时间阅读源码,也积累了一套与复杂代码打交道的方法。在 T Chat 第 11 期,他以一次最简单的构建为线索,演示怎样把源码运行起来、找到关键步骤,再处理插件架构带来的间接调用。当期自我介绍中,他在字节跳动飞书前端团队工作。
后半场没有停留在工具使用。主持人进一步追问,前端开发者怎样从完成需求走向技术深度,如何选择框架、练习写作,以及在繁忙工作中安排学习和培养团队。这些回答与前面的源码阅读形成了联系:技术深度需要持续投入,投入什么、怎样验证进展,同样需要判断。
技术分享:沿着一次构建读懂 Webpack
为什么还要研究这套复杂代码
范文杰先解释了选题背景。2022 年前端构建领域已有许多新工具,工程化仍在快速发展;与此同时,不少公司的基础设施、插件体系以及小程序等场景,已经建立在 Webpack 之上。他因此认为,对需要处理这些项目的人来说,理解 Webpack 仍有价值。这是他当时对具体需求的判断,不是关于未来市场份额的保证。
困难也很直接:大量代码、相互关联的类型、复杂的构建阶段,让读者很容易迷失。他把本次分享限定在几个问题上:重要源码放在哪里,怎样调试,主流程如何串联,以及哪些阅读方法可以迁移到别的项目。一次分享不会逐行解释整个仓库。
先找到入口,并搭起最小调试环境
面对一个陌生仓库,他先看目录和 package.json,了解入口、依赖与使用的工具,再辨认需要优先关注的文件。在这次演示中,注意力集中在 lib 目录以及 webpack.js、Compiler.js、Compilation.js 这些与构建主线相关的文件。其他目录并非没有价值,只是暂时不必同时展开。
调试需要一个足够简单的使用项目。范文杰准备了配置文件和一个源码入口,把本地克隆的 Webpack 通过 npm link 关联进去,再在感兴趣的位置插入 debugger,让示例触发自己正在阅读的那份源码。他当时使用 ndb 调试 Node.js 程序,现场也遇到了调试工具崩溃。这里值得保留的步骤,是确认本地源码确实被加载,并能在断点处观察执行状态;具体调试工具应结合自己的环境选择。
他认为,能让程序停在任意关键位置,是阅读复杂项目的重要准备。仅靠静态地浏览文件,很难判断实际走了哪个分支、某个对象是什么类型,以及状态在调用前后发生了什么变化。
现场操作的顺序很具体:先准备只有一个入口文件的项目,让配置尽量简单;在克隆的 Webpack 源码目录执行 npm link,再在示例项目里关联这个本地包;最后在入口函数放 debugger,用 Node.js 调试器启动一次构建。范文杰原本使用 ndb,演示时它接连崩溃,但重新进入调试后,断点确实落在本地源码。这一步验证很关键:如果示例实际跑的是依赖目录里另一份 Webpack,后面观察得再仔细也会走错对象。
沿最简单的场景梳理 Compiler
接下来的演示刻意收窄范围:先看单个配置对象、普通构建的路径,暂时把多配置和 watch 等分支放到一边。他沿入口找到创建编译器的逻辑,观察初始化选项、应用插件、得到 Compiler 实例,再继续追踪 run 与后续编译过程。每走到一层,先问这一层负责什么、下一个重要调用在哪里,再把这些步骤记成流程图。
这里有一个需要分清的细节:创建编译器实例与开始构建是两件事。官方同期 webpack.js 源码中,传入 callback 的调用会根据配置执行 run 或 watch;没有 callback 的调用则返回编译器,后续由调用者驱动。因此不能把演示中暂时忽略某个分支的阅读策略,理解成这些分支在 API 使用上没有意义。Webpack 5.74.0 源码
随着主线深入,流程会创建 Compilation,并进入 make 等钩子触发的阶段。此时,普通函数之间的直接跳转已经不足以解释全部执行过程,阅读方式也要跟着插件架构调整。
他边调试边在图上记下 create、创建 Compiler、run、compile 等节点。看到大段变量初始化和条件判断时,先确认示例究竟走哪一支,不立即追每个工具函数;看到 watch 分支时,先标记下来,继续普通构建。这是为第一轮阅读设边界,而不是认定那些代码不重要。等主线能跑通,再回头查改变结果的分支。
遇到钩子时,查触发点,也查注册点
范文杰用 Webpack 基于 Tapable 的插件机制说明这一难点。不同钩子在不同阶段触发,注册的回调会拿到对应参数,插件由此参与构建。理解一个钩子,至少需要知道它何时触发、哪些代码注册了回调,以及回调接收到什么对象。只停在触发钩子的那一行,调用链就会看起来突然断掉。
演示中,他搜索 make 的注册位置,排除当前示例没有使用的 DLL 和动态入口等路径,找到静态入口对应的 EntryPlugin,然后加断点验证。其回调调用 compilation.addEntry,把入口加入这次编译。官方同期实现使用的是 compiler.hooks.make.tapAsync;搜索时也应留意不同注册方式,不能只匹配完全相同的 tap(...) 字样。参见 EntryPlugin 源码
沿 addEntry 向下,还会经过入口依赖、模块创建与工厂等多层处理。名字和静态跳转可以帮助提出猜测,实际运行则用来验证:这个对象到底是哪一种具体类型,抽象接口由谁实现,调用产生了什么结果。他反复强调,遇到深层封装并没有一个自动绕过全部复杂度的技巧,仍需要沿主线逐步追踪、记录、再回到调试器确认。
这段现场演示说明了为什么断点比只看文件名可靠:addEntry 继续委托给后续函数,模块工厂再创建模块,静态阅读到抽象方法时会像走进死路。范文杰让程序在那个位置停下,看运行时拿到的工厂具体是哪一种,再顺着实际实现进入下一层。他描述的方法不是背熟一张调用图,而是“先猜这层做什么,再看对象和状态是否支持猜测”,每过一层就修正一次图。
官方钩子文档也提供了从源码查找触发位置的方法。读者复现时,可以同时查阅文档里的参数说明,与自己检出的版本相互核对。Webpack Compiler Hooks
用三个阶段组织已经看过的代码
在逐步追踪之后,范文杰把主流程整理为初始化、构建,以及封装与生成三个部分。这是一种帮助阅读的归纳:初始化准备配置与编译器;构建阶段从入口出发处理依赖,形成模块之间的关系;后续阶段再按规则组织模块、生成代码与输出资源。
从模块到输出资源,中间还有 chunk 等结构。演示用多个源码文件合并输出的例子帮助理解,但具体项目怎样拆分、生成哪些资源,仍由配置、依赖和相关优化过程共同决定,不能简化为所有模块必然合成一个文件。
他把构建阶段解释为“处理输入”:从配置的 entry 开始,递归找到依赖及依赖的依赖,解析内容,形成模块关系图。封装和生成阶段才从这些模块出发组织 chunk,生成运行所需代码并形成输出文件。这样分阶段之后,听众再遇到一个 bug,至少能先问:入口根本没被读到、模块解析错了,还是模块已经存在却在输出阶段被组织错了?
他特别展示了 Compilation.seal 附近的复杂逻辑:组织 chunk、优化、代码生成等步骤穿插着许多钩子。分享没有把每个细节展开,而是建议读者沿流程图中的关键函数实际设断点,逐个补上自己不理解的部分。图能提供阅读顺序,理解仍要来自代码与运行结果。
演示时他点开 seal,特意让听众看到一个很长的函数和密集的钩子,说明这里不适合靠一次顺读记下每行。实际练习可以先沿图找到阶段起点,再挑一个节点,例如解析 JavaScript 的调用或代码生成的位置,设断点验证输入、输出。等模块怎样进入 chunk 这条线清楚了,再研究优化钩子怎样改变结果。
有了这条主线,再回头研究 HMR、tree shaking、watch 或缓存等专题,会更容易判断它们处在什么阶段、改变了哪些行为。暂时跳过分支,是控制第一轮阅读范围;主线建立后,仍需返回细节,而不是永远忽略它们。
把一次阅读变成可复用的方法
源码阅读的用途,在范文杰看来包括更有把握地写插件和 loader、定位构建问题、优化性能,以及争取参与工程化基础设施的机会。他把这些作为可能获得的能力与工作空间,没有给出读完源码就必然获得岗位变化的承诺。
他最后把阅读步骤整理为一个可以重复使用的过程:先观察目录、入口与依赖;选定一个具体问题;参考已有资料;梳理关键流程;进入分支与细节;留下总结。切入点可以是程序启动,也可以是如何递归处理模块,大小应与自己的阶段匹配。
范文杰补充了两个常被跳过的动作。第一是读资料后自己验证,别把别人的流程图直接当答案;他在分享里展示自己的文章和图,也请听众按关键函数去调试,确认图是否适用于手里的版本。第二是随手记录:哪一层暂时不懂,可以留作下一轮的切入点;已确认的对象类型和状态变化,则写进笔记,避免下一次又从目录重看。他说曾读过 React 等项目,没及时总结,后来忘掉了不少细节。
资料和图示能节省摸索时间,但看过文章不等于理解。需要自己跑程序,检查调用和状态是否符合解释,再写出自己的流程图或笔记。哪怕总结只供自己使用,也能减少以后重新从零查找的成本;范文杰就提到,早期读过一些框架却没有留下记录,后来忘掉了不少细节。
成长对谈:选择值得深入的问题
为什么选择前端,后续还能深入哪里
主持人问“前端的天花板在哪里”时,范文杰没有只报几个热门名词,而是解释自己挑问题的标准:这件事是否真的难,是否又有业务价值。以低代码为例,拖拽生成一个页面只是开头;生成的页面能否满足多种需求、加载够快、让使用者顺手,才会决定工具是否能进入业务。可视化与复杂交互也一样,漂亮演示和稳定交付之间还有大量工程工作。
范文杰回忆,大学时接触过 C#,毕业前结合自己的兴趣和对就业的个人判断,选择了更喜欢的页面效果与交互方向。2013 年毕业后,他开始全职做前端。关于语言就业范围的评价,他在现场已经说明只是自己的感受,不能当成整个市场的统计。
谈到前端的发展空间,他举了低代码、可视化与工程化几个例子。能拖拽出一个页面,与让生成结果在性能、可用性和多种业务需求下都表现良好,难度相差很大;复杂可视化和交互也需要专门知识;工程化则要面对团队效率和基础设施问题。他当时正在投入低代码方向,认为同时具有难度与实际业务价值的问题,值得持续研究。
从胜任工作,到带团队解决更大的问题
他用刚入行的状态让这些阶段更具体:2013 年找第一份工作时,主要会用 jQuery 拼页面,到了小公司面对真实需求,先要补足“能交付”的能力;胜任后又发现重复写 CSS、重复处理相近问题,于是尝试 Less、Sass 等工具改善效率。再往下追性能和工具为什么这样运作,才会进入源码和单个技术方向的深水区。他的阶段划分来自这些变化,不是简单按年数或头衔排序。
回答成长阶段的问题时,他从自己进入小公司开始讲起。最初掌握的技能有限,真实项目会暴露能力缺口,这时首要任务是补齐基础,达到岗位要求。完成这一步之后,还可以继续观察当前方案的问题:哪些代码重复,哪里开发效率低,哪些性能或工具可以改善。
再向前,就是在某个方向建立深度。为了解决更复杂的优化与工具问题,需要理解底层实现,而不仅是知道如何调用。之后,视野逐渐扩展到业务形态、团队状态以及前后端等不同环节,能够选择更合适的工程体系和技术方案,再带着其他人一起完成任务。更大的责任还会越过单一职能边界,与不同角色共同创造结果。
这是一种对能力变化的归纳,不是所有人必须按顺序通过的职级表。它强调的变化,是从自己完成一项工作,逐步走向理解系统、组织合作,并影响更大的问题。
Vue、React 与团队选择
主持人把两种框架摆在一起请他选,范文杰先回到自己带新人时的具体工作:新同学进来后,要判断还需补哪些知识才能参与项目。如果一套框架更容易讲清楚、让团队尽快上手,这项培训成本就进入选型。谈到 React 可能有不同的性能和开发体验时,他也说明这是个人感受,现场没有给出可复核的基准数据。
在 Vue 和 React 的讨论里,范文杰先说明自己的偏好。他认为 Vue 的上手和团队培训成本更符合自己的经验,因此重新组建团队时会优先考虑它;React 则有另一套使用体验,也可能给新同事带来不同的理解和犯错成本。他承认这些判断带有个人使用习惯,并提到自己也愿意尝试其他框架。
真正要作项目选型时,仍需要结合人员、需求和现有工程,而不是只记住嘉宾更喜欢哪一个名字。范文杰关于性能上下限的口头比较是个人体验,不能替代针对具体项目的测量。
Vite 会替代 Webpack 吗
这是直播间提的问题,主持人转给范文杰时,他先说自己没有资格断言整个行业会走向哪里,再用两个层次回答。“完全替代”在既有项目中很难成立:旧项目、内部插件和特定场景不会随新工具出现就一起消失;同时 Webpack 自身也在改进缓存和按需处理能力。他当时只做过简单体验,没有系统比较,所以把这部分留在工程判断,而非性能结论。
直播间接着问到 Vite 与 Webpack。范文杰没有给出确定预测。他认为既有系统存在长期使用的需求,Webpack 本身也在改善缓存、延迟编译等能力,一些复杂场景已经有成熟的积累。Vite 值得学习,但不同工具并存、分别服务不同项目,在他看来比完全替代更容易想象。
他在当时没有做完整的性能测试,因此这番回答更适合用来理解项目选型时怎样考虑存量工程,不能直接作为今天工具速度或适用范围的比较结果。
另一个问题是面试更常问 React,是否意味着必须围绕它准备。范文杰介绍自己的面试方式:看候选人的简历和主要经历,擅长 Vue 就重点讨论 Vue,使用 React 较多就讨论 React,两者都有则都可以展开。这个回答是在说明他怎样了解候选人,并没有承诺所有面试官都会采用同样的方法。
写作与分享怎样练习
主持人问他怎样提高写作,范文杰先说起自己的焦虑,而不是给出写作公式。他回看早期文章,觉得结构散、没有重点;写小册时主动找编辑,希望对方指出章节组织和表达的问题。后来他把做法归纳成明确目标、把目标拆成可执行的阶段、在每个阶段寻找反馈,然后持续动笔。编辑的建议有用,真正让建议落地的仍是反复写和修改。
说到持续输出,范文杰先坦诚谈到自己的焦虑。他担心职业风险,会在工作之外寻找更多能力,也承认这种难以放松的状态并不值得照搬。可以分开借鉴的,是他如何把一个目标变成可执行的路径:不要一开始就设得过大,而是倒推阶段结果,逐步推进,并寻找让自己愿意继续的正向反馈。
具体到写作,他认为离不开多写、多练和反馈。最初的文章结构松散、重点不清,并不意外;反复整理之后,会逐渐知道怎样组织。写技术小册的一部分动机,也是获得编辑在表达和结构上的指导。技巧可以补充,但仍要进入真实写作过程,才能发现和改进自己的问题。
面对竞争,先确认自己的目标和深度
主持人把范文杰的投入称为“卷”,问怎样跳出困境。范文杰的第一句回答却是自己也没有跳出;他认为若只是被公司任务和他人的建议推着走,增加学习时长未必解决问题。因此先问自己是否真的喜欢这个方向;确认愿意做,再决定深入哪个问题。这里不是让所有人都复制他的焦虑和节奏,而是先让行动有一个属于自己的理由。
主持人用内卷继续提问。范文杰并未宣称已经解决这个困境,而是建议先和自己确认:是否真的愿意沿这条路走,还是只是被工作要求和别人的建议推着前进。技术之外还有其他事情可做,个人选择值得尽早思考。
如果决定继续,他建议建立一块足够深入的能力。广泛接触新技术可以扩展视野,但在缺乏积累时不断切换方向,也可能让每个东西都只停留在表面。完成一件有复杂度的事情,形成理解、判断和学习经验后,再向外扩展,会更有支点。他用自己阅读 Webpack 的过程作例子,而没有把它当成每个人都必须完成的唯一任务。
高强度工作下,怎样安排学习与输出
主持人接着追问,在接近“996”的强度下怎样还有时间输出。范文杰把“这件事必须解决吗”和“必须由我解决吗”分开:一个同事的问题也许能转给更熟悉的人,一件琐事也许可以由合适的角色处理;把每件事都揽在自己身上,会挤掉判断真正重要问题的时间。保留下的思考时间,他会找团队痛点中既有收益又需要技术投入的部分,把解决业务问题与个人积累连接起来。
关于繁忙工作下的技术输出,他首先介绍任务取舍。遇到事情时,判断它是否必须解决、是否必须由自己解决;可以转给更合适的人,就通过协作分担。减少不必要的占用之后,才可能保留一些思考时间。
这些时间可以用于观察团队真正受阻的地方:问题是否足够重要,有没有技术深度,解决后能带来什么收益。若值得投入,就主动把它做成工作中的改进;解决业务问题的过程也能形成个人积累,之后再视情况整理为工具或文章。
工作之外,他还讲到回家后继续学习、写小册时在通勤途中赶稿等个人安排,并多次承认自己的紧绷状态不健康、不建议照搬。明确目标、减少无效消耗、选择未来仍可能有价值的投入,可以根据个人时间和精力调整。主持人也补充,分工不是放弃责任,而是让事情由合适的人处理。
写小册赶稿时,他甚至在地铁上继续写;回家较晚还会遛狗后学习。这些都是他描述自己如何度过一段时期的事实,紧接着也坦言这种心理状态并不健康。若把这段只整理成“下班后努力就能产出”,就会抹掉他自己给出的限制。更能迁移的做法,是看清当前团队有什么值得投入的问题,并把工作中的研究沉淀下来,而不是另起一套与工作完全脱节的任务。
如何培养团队的技术氛围
这个问题由主持人从公司层面问起。范文杰先提到技术周报、公众号与交流活动,随后主动把回答转到自己能推动的小团队:给成员确定一两个月内值得学习的方向,再用文章或分享检查是否学明白,而不只是催一篇输出。能力相近的人可以结伴研究;已有经验的人也可以带新人。他说起曾见过同事工作做得熟练却看不到下一步,于是离开团队,这让“学什么、怎样继续成长”成为管理中需要回答的问题。
范文杰先提到当时字节内部及对外的技术文章、周报、直播和技术交流,再把回答缩小到自己更能直接影响的小团队。他介绍的做法包括定期技术分享、关注内容深度,以及结合成员当下的能力,为接下来一段时间确定值得学习的方向。
文章和分享在这里是检验学习结果的一种方式。团队也会把能力相近,或能相互帮助的成员配对,共同研究、共同输出。初期需要较多推动,之后希望成员逐渐形成判断自己下一步该学什么的意识。范文杰说,这也回应了他曾遇到的情况:有人已经熟悉工作,却因看不到成长而想离开;新的学习方向既可能带来个人变化,也可能给团队问题提供新的解法。
这是他介绍的团队实践,不代表整个公司的统一考核制度,也不能仅凭输出数量判断一个人是否真正掌握了技术。
看候选人和同事时,重视什么
主持人先问招聘时除技术之外看什么。范文杰承认,短暂的面试无法判断一个人的所有性格特点,所以重点观察候选人能否听懂问题、有条理地说明思路。答案一时不对,可以继续讨论;若讲不清从哪一步推到下一步,他就很难判断对方是否真正理解。入职以后,观察才转向实际交付:给出目标和背景后,是否主动想到更好的做法,能否在基本要求之外推进结果。
他把面试与入职后的观察分开。面试中能看到的信息有限,他会关注候选人是否理解问题,以及能否有条理地表达推理。没有立刻给出正确答案,不必然意味着沟通失败;相反,回答非常零碎、无法说明思路,会让他更难了解对方。这里重视的是表达和逻辑组织能力,不能简单等同于性格外向。
在日常合作中,他更关注一个人在理解目标和背景后,是否会主动思考怎样取得更好的结果。达到基本岗位要求之后,还能否向前一步,发现机会、补充判断、改善交付,而不是一直停留在刚好完成任务的状态。
当工作涉及更多职能和更复杂的合作时,沟通、理解他人与协调也会影响结果。他与主持人都谈到,技术能力之外还需要这些能力支持更大范围的协作;这并不是说所有岗位都应放弃技术深度去追求同一种管理角色。
对后续发展的安排
最后谈到个人规划,范文杰提到当时工作中有一个重要问题,既影响业务,也属于自己较擅长的方向,希望继续推进;具体业务细节不适合公开。与此同时,他想保持适度的社区输出,用写作和分享促使自己继续学习,并把团队带得更好。
主持人希望他再说具体一点,他明确表示部分业务细节不便公开,于是改谈怎样规划:先定职业目标,反推需要完成的项目和能力,再设置阶段节点并执行。他没有把尚未完成的项目包装成已经取得的成果。社区写作在他的计划里也是一条适度的成长线索,不打算让它压过工作中要解决的核心问题。
他仍用目标、里程碑与执行路径解释这些安排:先知道自己希望达到什么状态,再反推需要完成的事情。主持人回应,很多人会在实践中摸索出类似方法,提前理解这些方法也许能帮助减少部分绕路。两人没有据此保证某条路线一定带来晋升或收入增长。
完整原片、分段信息可从第 11 期访谈页继续查看。

