# vue-tools
# 学习流程
- 安装 vue-devtools 对应vue3版本
- 克隆项目,按照文章中流程,先跑起来
- 本文仓库地址 (opens new window):git clone https://github.com/lxchuan12/open-in-editor.git,本文最佳阅读方式,克隆仓库自己动手调试,容易吸收消化。
- 调试全流程
- 记录笔记
# 环境准备
- 安装 vue-devtools 对应 vue3版本 链接: https://pan.baidu.com/s/1cV4IvrZJkJmV_nGpUj9xyg 提取码: udgm (已解压)
- 克隆 git clone https://github.com/lxchuan12/open-in-editor.git, 或者创建一个 新的 vue3 project(这里的版本需要与vue-devtools的版本对应)
# 定点调试
打开克隆好的文件夹,使用 vscode 搜索下'launch-editor-middleware'这个中间件,vscode搜索文件一般会屏蔽 node_modules
, 需要手动进行配置一下。
# launch-editor-middleware
搜索出来的,launch-editor-middleware 中 index.js 的源码:
const url = require('url')
const path = require('path')
const launch = require('launch-editor')
module.exports = (specifiedEditor, srcRoot, onErrorCallback) => {
if (typeof specifiedEditor === 'function') {
onErrorCallback = specifiedEditor
specifiedEditor = undefined
}
if (typeof srcRoot === 'function') {
onErrorCallback = srcRoot
srcRoot = undefined
}
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()
}
}
}
返回一个函数,对传入的路径进行判断,如果路径中解析出一个文件路径,则调用launch打开
# launch-editor
nodejs_modules中launch-editor的 index.js文件
这里只梳理大致的函数逻辑:
const fs = require('fs')
const os = require('os')
const path = require('path')
const chalk = require('chalk')
const childProcess = require('child_process')
const guessEditor = require('./guess')
const getArgumentsForPosition = require('./get-args')
let _childProcess = null
// 主体函数
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
}
// linux mnt
if (
process.platform === 'linux' &&
fileName.startsWith('/mnt/') &&
/Microsoft/i.test(os.release())
) {
fileName = path.relative('', fileName)
}
if (lineNumber) {
const extraArgs = getArgumentsForPosition(editor, fileName, lineNumber, columnNumber)
args.push.apply(args, extraArgs)
} else {
args.push(fileName)
}
if (_childProcess && isTerminalEditor(editor)) {
_childProcess.kill('SIGKILL')
}
if (process.platform === 'win32') {
_childProcess = childProcess.spawn(
'cmd.exe',
['/C', editor].concat(args),
{ stdio: 'inherit' }
)
} else {
_childProcess = childProcess.spawn(editor, args, { stdio: 'inherit' })
}
_childProcess.on('exit', function (errorCode) {
_childProcess = null
if (errorCode) {
onErrorCallback(fileName, '(code ' + errorCode + ')')
}
})
_childProcess.on('error', function (error) {
onErrorCallback(fileName, error.message)
})
}
# guess.js
如果编辑器有配置,则直接返回。
如果没有配置,则根据操作系统的不同进行猜测编辑器,猜测编辑器的做法:
- 配置特定操作系统可能出现的编辑器
- 使用 子进程 执行对应操作系统的命令来 获取已在活跃的进程
- 将上一步获取的数据与对应操作系统进行对比,如果存在,则返回编辑器。
- 如果当中出现错误或者编辑器找不到,则返回空。
const path = require('path')
const shellQuote = require('shell-quote')
const childProcess = require('child_process')
// 三个操作系统中的编辑器配置。
const COMMON_EDITORS_OSX = require('./editor-info/osx')
const COMMON_EDITORS_LINUX = require('./editor-info/linux')
const COMMON_EDITORS_WIN = require('./editor-info/windows')
module.exports = function guessEditor (specifiedEditor) {
if (specifiedEditor) {
return shellQuote.parse(specifiedEditor)
}
try {
if (process.platform === 'darwin') {
const output = childProcess.execSync('ps x').toString()
const processNames = Object.keys(COMMON_EDITORS_OSX)
for (let i = 0; i < processNames.length; i++) {
const processName = processNames[i]
if (output.indexOf(processName) !== -1) {
return [COMMON_EDITORS_OSX[processName]]
}
}
} else if (process.platform === 'win32') {
const output = childProcess
.execSync('powershell -Command "Get-Process | Select-Object Path"', {
stdio: ['pipe', 'pipe', 'ignore']
})
.toString()
const runningProcesses = output.split('\r\n')
for (let i = 0; i < runningProcesses.length; i++) {
// `Get-Process` sometimes returns empty lines
if (!runningProcesses[i]) {
continue
}
const fullProcessPath = runningProcesses[i].trim()
const shortProcessName = path.basename(fullProcessPath)
if (COMMON_EDITORS_WIN.indexOf(shortProcessName) !== -1) {
return [fullProcessPath]
}
}
} else if (process.platform === 'linux') {
const output = childProcess
.execSync('ps x --no-heading -o comm --sort=comm')
.toString()
const processNames = Object.keys(COMMON_EDITORS_LINUX)
for (let i = 0; i < processNames.length; i++) {
const processName = processNames[i]
if (output.indexOf(processName) !== -1) {
return [COMMON_EDITORS_LINUX[processName]]
}
}
}
} catch (error) {
}
if (process.env.VISUAL) {
return [process.env.VISUAL]
} else if (process.env.EDITOR) {
return [process.env.EDITOR]
}
return [null]
}
# parseFIle
const positionRE = /:(\d+)(:(\d+))?$/
function parseFile (file) {
const fileName = file.replace(positionRE, '')
const match = file.match(positionRE)
const lineNumber = match && match[1]
const columnNumber = match && match[3]
return {
fileName,
lineNumber,
columnNumber
}
}
# 参考资料
第二期 →