背景
开发中遇到的痛点
在开发前端应用的过程中,修改页面内容的途径就是找到对应的源文件,并修改对应的代码。如果同时在调试多个页面功能,或者项目架构命名混乱,则将会有大量时间浪费在找文件上。真的是开发 5 分钟,查找 2 小时。。。
所以如果有一种方式可以直接通过页面打开源文件,那么开发效率则会有明显提升!
现存的解决方案
我接触的 vue 项目居多,所以就说说 vue 里面现有的解决方案
vue-devtools
vue-devtools 有打开 editor 的功能,但是需要频繁打开控制台、选择组件、点击按钮进行操作,个人觉得还是不够简便。

目标
最终想达到点击元素直接通过编辑器打开源代码的对应位置,就像使用 ctrl + c/v 一样流畅!

1 定位到页面级别
在实现最终目标之前,我们先从最简单的开始做起,能否先通过元素打开当前所在页面呢?
找到页面文件的路径
想要打开文件,必须先知道文件的绝对路径,幸运的是 vue-router 将页面的路径信息就储存在$route
里面。

可以这样拿到文件路径:
this.$route.matched[0].components.default.__file
打开编辑器
如果你使用的是 vscode,则可以通过终端使用 code
命令在编辑器内打开文件。这就为我们使用命令打开编辑器称为可能。
code a.js

实现打开动作
接下的要做的是前端将文件路径传递给一个后端服务,让后端服务通过nodejs
执行code
命令
前端
// 前端页面
const filePath = this.$route.matched[0].components.default.__file
const devServerPort = 8700;
axios.get(`http://localhost:${devServerPort}/code`, {
params: {
filePath: `-g ${filePath}`
}
});
后端
// webpack devServer 配置
devServer: {
port: 8700,
before: function (app) {
const child_process = require("child_process");
app.get("/code", function (req, res) {
child_process.exec(`code ${req.query.filePath}`);
res.send("文件打开成功!");
});
}
},
webpack 的 devServer 本身就是一个服务,所以我们可以通过对其进行配置来添加我们自己的逻辑

2 定位到组件级别
通过上面的操作可以跳转到页面的源码,但是如果能直接跳转到组件则更实用
找到组件的路径
在使用 vue-loader 解析 vue 文件时,通过配置 exposeFilename 属性可以将组件的路径放到组件实例中
// vue.config.js
chainWebpack: config => {
// ...
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap(options => {
options.exposeFilename = true
return options
})
},
并可以通过这样获取到组件文件路径:
this.$options.__file
组合键点击组件触发操作
获取到组件路径了,下一步可以给组件注册点击事件,就可以完成点击组件跳转到源码。
这里将注册点击事件的逻辑写在一个 vue 插件里,插件内部用 mixin 在每个组件挂载的时候都给每个组件都注册一个事件。
同时这里采用了 alt + 左键 组合点击的方式,为了避免和普通的业务操作相互混淆
// client.js
import axios from "axios";
import Vue from 'vue'
function launchEditor(filePath) {
if (!filePath) return
const devServerPort = 8700
axios
.get(`http://localhost:${devServerPort}/code`, {
params: {
filePath: `-g ${filePath}`
}
})
}
const openComponentPlugin = {
install(Vue) {
Vue.mixin({
mounted() {
this.__injectedFn = (e) => {
if (e.altKey) {
e.preventDefault()
let filePath = this.$options.__file
if (filePath) {
e.stopPropagation()
launchEditor(filePath)
}
}
}
this.$el.addEventListener('click', this.__injectedFn)
},
destroyed() {
this.$el.removeEventListener('click', this.__injectedFn)
}
});
}
};
Vue.use(openComponentPlugin);
// main.js
import "./client";
效果

后续
目前实现了点击组件进入源代码了,不过当组件过大时,还是需要二次查找代码的具体位置。下篇将讲述:如何精确定位到源代码行列级别。
本文代码实现方式可能有些会造成性能问题,但是不必担心,后续也都会优化掉。