vue-devtools
本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
这是源码共读的第2期,链接: juejin.cn/post/708499… 。
本期任务目标:
- 一句话简述其原理
code path/to/file
一句话简述:通过NodeJSde 的child_process,执行了类似code path/to/file的命令,于是编辑器打开对应文件,对应编辑器是通过ps x(Windows则使用Get-Process)命令查找的,当然也可以自己指定编辑器。
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切换下,把它赋值给onErrorCallback 错误回调函数
if (typeof specifiedEditor === 'function') {
onErrorCallback = specifiedEditor
specifiedEditor = undefined
}
// 如果第二个参数是函数,同样把它赋值给错误回调函数
// 这里传递过来是undefined
if (typeof srcRoot === 'function') {
onErrorCallback = srcRoot
srcRoot = undefined
}
// srcRoot是传递过来的参数,或者是当前node进程目录
srcRoot = srcRoot || process.cwd()
// 最后返回一个中间件,express中间件
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-editor打卡文件
launch(path.resolve(srcRoot, file), specifiedEditor, onErrorCallback)
res.end()
}
}
}
上段代码中,切换参数的方式在很多源码中很常见。为的是方便用户调用时传参,虽然是多个参数,但是可以传一个或多个。
launch-editor
// vue3-project/node_modules/launch-editor/index.js
function launchEditor (file, specifiedEditor, onErrorCallback) {
// 解析文件路径和行号列号信息
const parsed = parseFile(file)
let { fileName } = parsed
const { lineNumber, columnNumber } = parsed
// 判断文件是否存在,不存在直接返回
if (!fs.existsSync(fileName)) {
return
}
// 第二个参数传递过来是函数,把它赋值给错误函数
if (typeof specifiedEditor === 'function') {
onErrorCallback = specifiedEditor
specifiedEditor = undefined
}
// 包装一层函数
onErrorCallback = wrapErrorCallback(onErrorCallback)
// 猜测当前进程运行的是那个编辑器
const [editor, ...args] = guessEditor(specifiedEditor)
if (!editor) {
onErrorCallback(fileName, null)
return
}
省略剩余部分...
}
wrapErrorCallback 包裹错误函数回调
onErrorCallback = wrapErrorCallback(onErrorCallback)
这段代码就是传递错误回调函数,wrapErrorCallback会返回一个新的函数,wrapErrorCallback执行时,再去执行onErrorCallback(cb)
// vue3-project/node_modules/launch-editor/index.js
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)
}
}
guessEditor 猜测当前正在使用的编辑器
这个函数主要做了四件事情:
1、如果指明了编辑器,则直接返回
2、找出当前进程中正在运行的编辑器。Linux和MacOS 用ps x;Windows则用Get-Process.
3、如果都没找到就用process.env.VISUAL或者process.env.EDITOR.这就是为啥开头解决方法之一可以使用环境变量指定编辑器。
4、最后还是没有找到就返回[null],则会报错。
const [editor, ...args] = guessEditor(specifiedEditor)
if (!editor) {
onErrorCallback(fileName, null)
return
}
// vue3-project/node_modules/launch-editor/guess.js
launch-editor 剩余部分
function launchEditor (file, specifiedEditor, onErrorCallback) {
// 省略上部分...
// 主要部分代码
if (_childProcess && isTerminalEditor(editor)) {
// There's an existing editor process already and it's attached
// to the terminal, so go kill it. Otherwise two separate editor
// instances attach to the stdin/stdout which gets confusing.
_childProcess.kill('SIGKILL')
}
if (process.platform === 'win32') {
// On Windows, launch the editor in a shell because spawn can only
// launch .exe files.
_childProcess = childProcess.spawn(
'cmd.exe',
['/C', editor].concat(args),
{ stdio: 'inherit' }
)
} else {
_childProcess = childProcess.spawn(editor, args, { stdio: 'inherit' })
}
省略下部分
}
此文章为11月Day2源码共读,以梦为马,11月进步💪💪