vue devtools源码学习

144 阅读4分钟

本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
**这是源码共读的第1期,链接:juejin.cn/post/708499…
安装步骤和调试步骤源码共读里面都写明了,不会的可以再去百度或其他搜索看看都简单,我主要写下我的读后感和拓展。
首先明白一点,devtools是基于node和webpack-dev-server的,打包上线的应用没有办法调试。然后就是看这些源码需要node和webpack-dev-server的基础,而webpack-dev-server就是基于Node和webpack的一个简易服务器,这样拓展就太多了,一口也吃不成胖子,所以这次先看node里用到的内容,当然主要我node的基础薄弱,基础好的同学可以不用看了。

app.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`
)))

这里就是监听一个请求,我本地发送的请求是 https://localhost:8088/__open-in-editor?file=src/components/header.vue
而服务监听请求后的处理是

const url = require('url')
const path = require('path')
srcRoot = srcRoot || process.cwd()
return function launchEditorMiddleware (req, res, next) {
    const { file } = url.parse(req.url, true).query || {}
    if (!file) {
        res.statusCode = 500
        res.end(`launch-editor-middleware: required query param "file" is missing.`)
    } else {
        launch(path.resolve(srcRoot, file), specifiedEditor, onErrorCallback)
        res.end()
    }
}

这里就用到了url和path path是一个系统模块,不需要单独安装,主要用于格式化或拼接完整路径

var path = require('path');
//拼接路径:将多个字符串拼接成一个完整的路径
var file = path.join(__dirname,``'file1.txt'``);
console.log("当前路径:"+file);
//返回路径中的文件夹部分
var dirname = path.dirname(file);
//返回路径中的文件部分,包含文件名和扩展名
var filename = path.basename(file);
//返回路径中的扩展名
var extname = path.extname(file);
//解析路径对象,返回一个对象
var p = path.parse(file);
//path.resolve([from ...], to)
//将 第二个 参数解析为绝对路径,给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径。 例如,给定的路径片段的序列为:/foo、/bar、baz,则调用 path.resolve('/foo', '/bar', 'baz') 会返回 /bar/baz。
var fullPath = path.resolve(__dirname,file);
console.log("dirname:"+dirname);
console.log("filename:"+filename);
console.log("extname:"+extname);
console.log("parse解析后的对象:");
console.log(p)

这里参考www.runoob.com/nodejs/node…
通过学习发现 launch(path.resolve(srcRoot, file), specifiedEditor, onErrorCallback)这个方法里的第一个参数就是获取文件的完整路径
url 和 querystring 模块是用来解析URL地址的

import path from "path";
import url from "url";
import querystring from "querystring";
console.log(path);
let URL = url.parse("http://localhost:8888/start?foo=bar&hello=world");
console.log(URL);
console.log(querystring.parse(URL.query));

我们在程序中也是可以用的,现在程序中那个解析地址的插件qs是自己写的的解析方法,为什么不用node原生的这些,后面我再研究吧,今天先到这。 关于不用原生node这个已经知道为什么了,原生的代码需要运行在node环境里,也就是写在node服务端,客户端还要用js写。

然后我们继续,获取了文件后,通过中间件launchEditorMiddleware,进入launch主方法

const parsed = parseFile(file)
let { fileName } = parsed
const { lineNumber, columnNumber } = parsed
if (!fs.existsSync(fileName)) {
return
}

开头是这么写的,我们看函数的三个参数,

function launchEditor (file, specifiedEditor, onErrorCallback)

file是完整的文件路径,specifiedEditor这个是undefined,如果是vue2或者不是vue-cli框架生成的项目,在webpack里面自己写的话,这个应该是传入需要运行的当前编辑器。 parseFile方法是解析文件路径中的行和列的,这个我调试的时候路径中没有,不知道什么情况下有?这个算是一个遗留问题。 后面就是找到对应的进程和对应的文件然后打开它,这里用到了child_process

Node 提供了 child_process 模块来创建子进程,方法有:

  • exec - child_process.exec 使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数参数的形式返回。
  • .execSync - child_process.execSync 同步执行命令。
  • spawn - child_process.spawn 使用指定的命令行参数创建新进程。
  • fork - child_process.fork 是 spawn()的特殊形式,用于在子进程中运行的模块,如 fork('./son.js') 相当于 spawn('node', ['./son.js']) 。与spawn方法不同的是,fork会在父进程与子进程之间,建立一个通信管道,用于进程之间的通信。

不同的系统获取进程的方式 ios系统

const output = childProcess.execSync('ps x').toString()

window系统

const output = childProcess
.execSync('powershell -Command "Get-Process | Select-Object Path"', {
stdio: ['pipe', 'pipe', 'ignore']
})
.toString()

linux系统

const output = childProcess
.execSync('ps x --no-heading -o comm --sort=comm')
.toString()

根据不同的内容作处理,具体看源码 获取了编辑器后

_childProcess = childProcess.spawn(editor, args, { stdio: 'inherit' })

创建新的子进程,在对应的项目中打开了需要的文件。

学习心得: 1.vue devtools是本地开发的调试工具,以node和webpack-dev-server环境为基础,主要是打开进程的方式打开本地的文件(child_process) 2.学习了node的基础,path,url,child_process,还有很多全局对象,如:process、__dirname等。