vue-devtools打开文件的魔法之旅
前言
vue-devtools点击就可以在IDE中打开对应组件文件,这是什么魔法?本文一探究竟。
先上图:
环境准备
vue-devtools 按照文档安装浏览器插件。
vue-cli使用vue-cli搭建一个vue项目,安装好依赖。
vscode设置code命令配置
vscode开启debugger,运行vue项目
vscode设置code命令
cmd + shift + p
输出shell
施法
vue-devtools点击app.vue的位置,追溯app.vue是怎么打开的
WebpackDevServer开启服务监听
vue-cli-service serve 复制代码
上面执行node_modules/@vue/cli-service/lib/commands/serve.js
如下图给/__open-in-editor路径绑定launchEditorMiddleware事件
按钮其实对应地址就是http://localhost:8080/__open-in-editor?file=src/App.vue
Tips: vscode可点击名称,鼠标右键,选择转到定义可直接跳转到定义的位置
before (app, server) { // 通过 http://localhost:8080/__open-in-editor?file=监听打开文件服务(取query中的file) 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` ))) // allow other plugins to register middlewares, e.g. PWA api.service.devServerConfigFns.forEach(fn => fn(app, server)) // apply in project middlewares projectDevServerOptions.before && projectDevServerOptions.before(app, server) } 复制代码
launchEditorMiddleware
通过回调参数寻找文件,没有则抛出错误,结束服务。找到则通过launch寻找IDE命令执行
const launch = require('launch-editor') // 省略若干 return function launchEditorMiddleware (req, res, next) { // 例子:http://localhost:8080/__open-in-editor?file=src/App.vue const { file } = url.parse(req.url, true).query || {} // src/App.vue if (!file) { res.statusCode = 500 res.end(`launch-editor-middleware: required query param "file" is missing.`) } else { // path.resolve('/Users/zhouguang/Desktop/own/vue/vue2', 'src/App.vue') launch(path.resolve(srcRoot, file), specifiedEditor, onErrorCallback) // 结束服务 res.end() } } 复制代码
launch-editor
寻找IDE对应执行命令并且打开传入的文件
找文件
const parsed = parseFile(file) // 完整文件路径:'/Users/zhouguang/Desktop/own/vue/vue2/src/views/docs/index.vue' let { fileName } = parsed const { lineNumber, columnNumber } = parsed // 找不到则退出 if (!fs.existsSync(fileName)) { return } 复制代码
错误回调函数包装处理
// 参数转移 if (typeof specifiedEditor === 'function') { onErrorCallback = specifiedEditor specifiedEditor = undefined } // 包裹函数,利于封装本身错误处理以及扩展外部错误处理 onErrorCallback = wrapErrorCallback(onErrorCallback) 复制代码
寻找IDE对应code命令以及传参
const [editor, ...args] = guessEditor(specifiedEditor) 复制代码
guessEditor
根据环境寻找IDE对应的执行命令,下面以mac + vscode为例:
process.platform
ps x是返回unix所有安装的程序
osx.js
module.exports = { // 省略。。。 '/Applications/Visual Studio Code.app/Contents/MacOS/Electron': 'code' // 省略。。。 } 复制代码
// 引入mac中各IDE对应命令字典 const COMMON_EDITORS_OSX = require('./editor-info/osx') // darwin对应unix系统 if (process.platform === 'darwin') { // ps x log出程序列表 const output = childProcess.execSync('ps x').toString() // 找出拥有的程序在osx对应的程序命令并返回 // '/Applications/Visual Studio Code.app/Contents/MacOS/Electron' => 'code' 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]] } } } 复制代码
继续回到launch-editor
// args加入完整路径.例子:/Users/zhouguang/Desktop/own/vue/vue2/src/App.vue args.push(fileName) 复制代码
// node子进程执行 code /Users/zhouguang/Desktop/own/vue/vue2/src/App.vue _childProcess = childProcess.spawn(editor, args, { stdio: 'inherit' }) 复制代码
结束服务
// 结束服务 res.end() 复制代码
总结
一句话流程:输入:/path/file,输出code /path/file
包装函数有利于封装自身处理函数以及处理回调
参数转移解决传参几个变成一个问题
感谢
若川源码共读活动
据说 99% 的人不知道 vue-devtools 还能直接打开对应组件文件?本文原理揭秘
作者:惜时自珍
链接:https://juejin.cn/post/7031053057798438948