小姐姐笔记:我是如何学习简单源码拓展视野的

大家好,我是若川。这是我上周组织的源码共读纪年小姐姐的笔记,写得很好。所以分享给大家。欢迎加我微信 ruochuan12,进源码共读群。其他更多人的笔记可以阅读原文查看。


川哥的源码解读文章:据说 99% 的人不知道 vue-devtools 还能直接打开对应组件文件?本文原理揭秘

???? 非常感谢川哥组织的源码阅读活动

1. 解读前的准备

1.1 粗略阅读一遍川哥的源码解读文章,弄清楚文章的主旨内容:探究 vue-devtools「在编辑器中打开组件」功能实现原理**,它的核心实现就是 launch-editor**。

1.2 明确自己到底要学习什么:

1)学习调试源码的方法;

2)在调试过程中探究 launch-editor 源码是如何实现在编辑器打开对应的文件;

目标:跟着川哥的文章完整走完一遍调试的流程,并对外输出记录文档。

1.3 资源:

  • 下载川哥的源码:git clone https://github.com/lxchuan12/open-in-editor.git,进入 vue3-project 目录,安装依赖yarn install

  • 安装 vue-devtools 谷歌扩展:翻墙去应用商店下载安装即可(下载 6.0.0 beta 版)

  • 了解 launch-editor[1]:主要功能是在编辑器中打开带有行号的文件

2. 开始学习,浅尝辄止

上述的准备工作搞完之后,我们动手操作一下。

2.1 开始动手

我使用的编辑器是 VSCode。

打开 vue3-project 目录的 package.json,点击调试,选择 serve。这一步操作,使得我们以 debug 的形式,运行了 vue-cli-service serve 这个命令。

img

跟着文章实现到这里的时候,我有点懵逼,因为我不知道接下来为什么突然要搜索【launch-editor-middleware】这个库。

直到我再次通读一遍文章,发现川哥前面有提到 vue-devtools 的 Open component in editor[2] 这个文档,这个文档里面描述了引用了【launch-editor-middleware】这个库来实现打开文档的功能。而我之前先入为主地以为,这期是解读 vue-devtools 的源码,其实这只是解读实现打开文档功能的源码而已。

理解了这一层,我们可以直接搜项目里(包括 node_modules)里的【launch-editor-middleware】关键字,就可以找到这个库的源码位置了。

2.2 调试之旅

调试的流程就是打断点,点击调试的流程面板,经过不断调试,观察数据的变化。

下图【launch-editor-middleware】的源码,在这份源码中我们能很轻易地分析出,最终运行的是 launch 函数,我们可以这这里打一个断点,然后进入到【launch-editor】的源码,实际运行的是 launchEditor 函数。

img
img

粗略看一遍 launchEditor 函数,发现它实际上是做了四件事:

  • 获取 fileName,lineNumber,columnNumber

  • 异常处理:是否存在文件,onErrorCallback,是否存在 editor

  • 猜测当前正在使用的编辑器:guessEditor

  • 使用 child_process.spwan 异步打开一个子进程模块,它调起了 cmd.exe 工具打开我们的编辑器,并打开了文件(args 就是文件的参数)

看完了这个函数,其实大概实现的原理也就出来了,核心代码如下:

if (process.platform === 'win32') {_childProcess = childProcess.spawn('cmd.exe',['/C', editor].concat(args),{ stdio: 'inherit' })
} else {_childProcess = childProcess.spawn(editor, args, { stdio: 'inherit' })
}

但我们肯定还有很多疑惑,比如:

  • 在浏览器控制台点击按钮,编辑器是怎么接收到它的请求信息呢?

  • 用到了哪些 API/编程技巧?

  • 这个功能实现如果让我们来实现,是怎么实现呢(复述思路)?

3. 动手操作,深入实践

在前面的拆解中,虽然很多地方看似看懂了,但又没完全懂,那我们来解答一下在看源码的时候的疑问:

3.1 编辑器如何接收到浏览器的请求信息

点击 vue-devtools 的按钮时,我们会发现它发送了一个请求:http://localhost:8080/__open-in-editor?file=src/components/HelloWorld.vue

img

那编辑器是如何接收到这个请求呢?搜索【launch-editor-middleware】关键字,我们会发现,在 @vue/cli-service 的 serve.js 文件中,使用了 app.use("/__open-in-editor"),用过 express 的小伙伴会比较熟悉,这是express 引入中间件的用法。当浏览器发送 http://localhost:8080/__open-in-editor?file=src/components/HelloWorld.vue 这个请求的时候,就进入到下面这个代码了。

// vue3-project/node_modules/@vue/cli-service/lib/commands/serve.js
// 46行
const launchEditorMiddleware = require('launch-editor-middleware')
// 192行
before (app, server) {// launch editor support.// this works with vue-devtools & @vue/cli-overlayapp.use('/__open-in-editor', launchEditorMiddleware(() => console.log(`To specify an editor, specify the EDITOR env variable or ` +`add "editor" field to your Vue project config.\n`)))// 省略若干代码...
}

3.2 用到了哪些 API/编程技巧

3.2.1 函数的重载

在【launch-editor-middleware】的入口函数这里,使用了函数重载的写法,这种写法在很多源码中都很常见,目的是方便用户调用时传参,针对不定量的参数对应不同的操作内容。

// vue3-project/node_modules/launch-editor-middleware/index.js
const url = require('url')
const path = require('path')
const launch = require('launch-editor')module.exports = (specifiedEditor, srcRoot, onErrorCallback) => {// specifiedEditor => 这里传递过来的则是 () => console.log() 函数// 所以和 onErrorCallback 切换下,把它赋值给错误回调函数if (typeof specifiedEditor === 'function') {onErrorCallback = specifiedEditorspecifiedEditor = undefined}// 如果第二个参数是函数,同样把它赋值给错误回调函数// 这里传递过来的是undefinedif (typeof srcRoot === 'function') {onErrorCallback = srcRootsrcRoot = undefined}// srcRoot 是传递过来的参数,或者当前 node 进程的目录srcRoot = srcRoot || process.cwd()// 最后返回一个函数, express 中间件return function launchEditorMiddleware (req, res, next) {// 省略 ...}
}

3.2.2 装饰器模式

这段代码 wrapErrorCallback 先执行其他代码,再去执行 onErrorCallback,这种包裹函数的形式在很多源码里都也很常见,可以理解为一个装饰器,把 onErrorCallback 包装了起来,对原函数进行了增强。

这也是设计模式中的装饰器设计模式:

function wrapErrorCallback (cb) {return (fileName, errorMessage) => {console.log()console.log(chalk.red('Could not open ' + path.basename(fileName) + ' in the editor.'))if (errorMessage) {if (errorMessage[errorMessage.length - 1] !== '.') {errorMessage += '.'}console.log(chalk.red('The editor process exited with an error: ' + errorMessage))}console.log()if (cb) cb(fileName, errorMessage)}
}onErrorCallback = wrapErrorCallback(onErrorCallback)

3.2.3 apply

apply 语法:func.apply(thisArg, [argsArray]),也经常在源码中可以看到。这里使用 apply 是把 extraArgs 作为 push 方法的 arguments 传进去。

if (lineNumber) {// getArgumentsForPosition 返回一个数组const extraArgs = getArgumentsForPosition(editor, fileName, lineNumber, columnNumber)// 将 extraArgs 参数 push 到 args 里args.push.apply(args, extraArgs)
} else {args.push(fileName)
}

3.2.4 child_process

child_process 是 Node.js 的一个模块,它提供了衍生子进程的能力,默认情况下,会在父 Node.js 进程和衍生的子进程之间建立 stdin、stdout 和 stderr 的管道。

3.2.5 process.platform

用于标识运行 Node.js 进程的操作系统平台,返回字符串,目前可能的值有: "aix" | "darwin" | "freebsd" | "linux" | "openbsd" | "sunos" | "win32"

3.3 如何实现(复述思路)

  • 浏览器与编辑器的通讯:借助 Node.js 进程,与浏览器发生通讯

  • 浏览器将需要打开的文件路径通过参数传递给编辑器

  • 判断操作系统平台和所使用的编辑器(每个平台的命令行程序不一样,每个编辑器的环境变量也不一样)

  • 借助 Node 调起 cmd.exe 工具打开我们的编辑器,打开对应路径的文件

// 伪代码
app.use("__open-in-editor", handleLaunchEditor)function handleLaunchEditor(filePath) {const platform = process.platformconst editor = guessEditor()childProcess.spawn(editor, fileArgs, { stdio: 'inherit' })
}

4. 感想

  • 编码能力:通过解读 launch-editor 源码,学习/重温了【函数的重载】【装饰器模式】【apply 使用方法】,源码的组织结构也非常值得我们学习,比如里面很多功能代码都单独封装起来,封装成函数或者模块,使得整个源码的结构非常清晰,核心通俗易懂,易于解读和维护。(这也可以理解为自顶向下的编程方法)

  • 拓展视野:源码中包含了很多与 Node.js 相关的方法,有很多都是我不熟悉的,在解读源码的过程也是我学习 Node.js 的过程。

  • 工作中可能会用到:

    • 开发 VSCode 插件与外界通讯可借助 Node.js 进程

    • 装饰器模式的应用

    • 判断操作系统平台

参考资料

[1]

launch-editor: https://github.com/yyx990803/launch-editor

[2]

Open component in editor: https://github.com/vuejs/devtools/blob/legacy/docs/open-in-editor.md


最近组建了一个江西人的前端交流群,如果你是江西人可以加我微信 ruochuan12 私信 江西 拉你进群。


推荐阅读

我在阿里招前端,该怎么帮你(可进面试群)
我读源码的经历

面对 this 指向丢失,尤雨溪在 Vuex 源码中是怎么处理的
老姚浅谈:怎么学JavaScript?

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》多篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。
同时,活跃在知乎@若川,掘金@若川。致力于分享前端开发经验,愿景:帮助5年内前端人走向前列。

识别方二维码加我微信、拉你进源码共读

今日话题

略。欢迎分享、收藏、点赞、在看我的公众号文章~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275584.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php表决器代码,三人表决器:VHDL源代码

描述--三人表决器(三种不同的描述方式) vhdl-- Three-input Majority Voter-- The entity declaration is followed by three alternative architectures which achieve the same functionality in different ways.ENTITY maj ISPORT(a,b,c : IN BIT; m : OUT BIT);END maj;--D…

保持危机感和紧迫感_什么是紧迫的:您需要知道的一切

保持危机感和紧迫感Putting the finishing touches on a graphic design project calls for a keen eye. But you already know this, because perfectionism is just a part of the job! You look at every nook and cranny of a project before you can consider it complete…

剑指offer java版(一)

二维数组中的查找 问题描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断…

如何系统搭建现代 Web CI/CD

大家好,我是若川。今天分享一篇00后写的CI/CD直播文字稿。之前发过他的故事:一位00后前端2年经验的成长历程。我最近组织了源码共读活动,感兴趣的加我微信 ruochuan12。本次直播录播链接:https://live.juejin.cn/4354/595741[1]开…

sqlserver oracle 数据类型对应关系,SQLSERVER和ORACLE数据类型对应关系详解和对应表格整理...

Oracle SQLServer 比较 SQLServer 常见的 数据 库 类型 字符 数据 类型 CHAR CHAR :都是固定长度字符资料但oracle里面最大度为2kb,SQLServer里面最大长度为8kb 变长字符 数据 类型 VARCHAR2 VARCHAR :racle里面最大长度为4kb,SQLServer里面最大长度为8k…

优化算法汇总

interior point block coordinate relaxation Boltzmann machine 求解L1范数最小化 E. Candes, M. B. Wakin, and S. P. Boyd, “Enhancing sparsity by reweighted l1 minimization,” Journalof Fourier Analysis and Applications, vol. 14, pp. 877-905, Dec. 2008.I. Daub…

对接百度地图API

一、准备工作 百度地图开发文档 注册百度账号&#xff0c;成为开发人员&#xff0c;同时获取AK实例代码&#xff1a;<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content&quo…

ui边框设计图_UI设计形状和对象基础知识:填充和边框

ui边框设计图第2部分 (Part 2) Welcome to the second part of the UI Design shapes basics. This time we’ll cover two of the most essential properties of a shape — fills and borders. This is also a part of the free chapters from Designing User Interfaces.欢迎…

如何移除项目中无用的 console.log 代码

大家好&#xff0c;我是若川。早些天时&#xff0c;我看到一个后端公众号发《辞退了一个前端》&#xff0c;当时还想着现在后端公众号都开始吊打前端了嘛。其中有个理由就是线上还一堆console.log...我猜很多人都会移除项目中无用的console.log。可以复习一下。前言说起console…

WCF - 服务实例管理模式

WCF 提供了三种实例上下文模式&#xff1a;PreCall、PreSession 以及 Single。开发人员通过 ServiceBehavior.InstanceContextMode 就可以很容易地控制服务对象的实例管理模式。而当 WCF 释放服务对象时&#xff0c;会检查该对象是否实现了 IDisposable 接口&#xff0c;并调用…

oracle io lost,磁盘IO故障

测试工作正在如火如荼的进行&#xff0c;突然数据库就连接不上了。我连接上主机发现数据库alert_sid日志中有如下信息&#xff1a;KCF: write/open error block0x9a6 online1file2 /oracle_data1/UNDOTBS3.dbferror27072 txt: Linux Error: 5: Input/output errorAdditional in…

易思汇完成近亿元B轮融资,信中利投资

3月19日消息&#xff0c;近日&#xff0c;留学生在线付费平台易思汇宣布已在3月份完成由信中利投资的近亿元B轮融资。 易思汇联合创始人高宇同表示&#xff0c;本轮融资将主要用于留学生信用卡、留学家庭金融商城等新产品布局&#xff0c;以及扩大团队和市场投入。 易思汇成立…

远程连接 错误 内部错误_关于错误的性质和原因。 了解错误因素

远程连接 错误 内部错误Back in 2012, I was a young[er] product designer working in a small tech agency in Valencia, Spain. In parallel, I worked as a freelancer on several side projects for different clients. One day I was contacted by a new health services…

得到鹅厂最新前端开发手册一份

又逢金九银十&#xff0c;拿到大厂offer一直是程序员朋友的目标&#xff0c;但是去大厂就得拿出实力来。除了需要积累技术&#xff0c;了解并掌握面试的技巧&#xff0c;熟悉大厂面试流程&#xff0c;也必不可少。这里分享一份最新入职腾讯的前端社招面经&#xff0c;来看看鹅厂…

性能测试分析之带宽瓶颈的疑惑

第一部分&#xff0c; 测试执行 先看一图&#xff0c;再看下文 这个当然就是压力过程中带宽的使用率了&#xff0c;我们的带宽是1Gbps的&#xff0c;合计传输速率为128MB/s&#xff0c;也正因为这个就让我越来越疑惑了&#xff0c;不过通过压力过程中的各项数据我又不得不相信。…

Android 中的LayoutInflater的理解

LayoutInflater与findViewById的区别&#xff1f; 对于一个已经载入的界面&#xff0c;就可以使用findViewById()方法来获得其中的界面元素。对于一个没有被载入或者想要动态载入的界面&#xff0c;就需要使用LayoutInflater对象的inflate()方法来载入。findViewById()是查找已…

linux rootfs编译进内核,九鼎x6818开发板笔记:uboot、kernel、rootfs编译和烧写

下面记录了如何搭建嵌入开发环境&#xff0c;如何编译uboot、kernel、和文件系统&#xff0c;如何烧写镜像以及如何配置uboot环境变量。阅读注意&#xff1a;记录中(Base框中的内容)一些操作故意被添加&#xff0c;为了展示文件内容&#xff0c;故意调用cat(Ubuntu)或者type(wi…

figma下载_素描vs Figma困境

figma下载I distinctly remember how much hatred I had in my heart when I lived through my first UI update. The year was 2009; I had just gotten my braces off and I was ready to smash that ‘Like’ button on my high school crush’s status when I logged into …

祝大家七夕快乐,邀你源码共读,顺带发点红包

大家好&#xff0c;我是若川。这是一个普通的周六。只不过又叫七夕节&#xff0c;祝大家七夕节快乐~所以就不更新技术文了。估计还是有很多读者不知道我。若川名字由来是取自&#xff1a;上善若水&#xff0c;海纳百川。顺便放两篇文章。我读源码的经历&#xff0c;跟各位读者朋…

windows 系统监视器 以及建议阀值

windows 系统监视器 以及建议阀值 计数器的说明可以在添加计数器那边 资源 对象\计数器建议的阈值注释磁盘Physical Disk\% Free SpaceLogical Disk\% Free Space15%磁盘Physical Disk\% Disk Time Logical Disk\% Disk Time90%磁盘Physical Disk\Disk Reads/sec、Physical Dis…