1.背景
目前的许多项目都是使用vue进行开发的,当一个vue项目做大时维护起来非常麻烦,当我们需要找到某个文件的时候非常麻烦,传统快速定位到某个文件可以使用类名、或者路由路径等方式找到对应的文件。
2、vue devTools介绍
vue devTools是vue开发的一个插件,它同时也具备着能够快速定位到某个文件的功能:
点击这个图标然后点击某个元素即可打开某个vue文件的详情
点击右上角的图标即可在编辑器中打开该文件
3、自定义快速打开元素插件
虽然vue提供的插件已经足够满足我们日常开发需求了,但是我觉得速度依然不够快于是决定采用自定义插件的方式实现按住shift+鼠标左键的方式快速打开某个元素对应的vue文件。
3.1 以VUE3+Vite为例子
创建openCodeClient.ts文件,用于向当前server端发起网络请求
import axios from 'axios'
function openEditor(filePath: string): void {
console.log(filePath);
axios
.get('/code', {
params: { filePath }
})
.catch(error => {
console.error(error)
})
}
function getFilePath(element: HTMLElement | null): string | null {
if (!element || !element.getAttribute) return null
const codeLocation = element.getAttribute('code-location')
if (codeLocation) {
return codeLocation
}
return getFilePath(element.parentElement)
}
function openCode(e: MouseEvent): void {
const isShiftKey = e.shiftKey
const isMetaKey = e.metaKey
if (isShiftKey || isMetaKey) {
e.preventDefault()
const target = e.target as HTMLElement
const filePath = getFilePath(target)
if (filePath) {
openEditor(filePath)
}
}
}
function init(): void {
document.addEventListener('click', openCode, true)
}
export default { init }
3.2 创建server.ts文件
用于接收client端发起的网络请求并打开vscode对应的vue文件
import { exec } from 'child_process'
import type { Plugin } from 'vite';
import { IncomingMessage, ServerResponse } from 'http'
function openCodeFile(path: string): void {
exec(`code -r -g ${path}`, (error, stdout, stderr) => {
if (error) {
console.error(`Error executing command: ${error.message}`)
return
}
if (stderr) {
console.error(`Error output: ${stderr}`)
return
}
console.log(`Command output: ${stdout}`)
})
}
const codeServer = (): Plugin => ({
name: 'open-code-vite-server',
configureServer(server) {
server.middlewares.use((req: IncomingMessage, res: ServerResponse, next: () => void) => {
const url = new URL(req.url || '', `http://${req.headers.host}`)
const filePath = url.searchParams.get('filePath')
if (url.pathname === '/code' && filePath) {
openCodeFile(filePath)
res.statusCode = 200
res.end()
} else {
next()
}
})
}
})
export default codeServer
3.3 创建vite-plugin-add-code-location.ts文件
用来给当前页面每一个元素添加一个自定义属性,属性名叫add-code-location,值是对应的文件路径+代码行
import type { Plugin } from 'vite';
export default function addCodeLocationPlugin(): Plugin {
return {
name: 'add-code-location',
transform(code: string, id: string) {
return sourceCodeChange(code, id);
},
};
}
function sourceCodeChange(source: string, resourcePath: string): string {
// 只对 .vue 文件进行处理
if (resourcePath.endsWith('.vue')) {
const templateMatch = source.match(/<template>([\s\S]*?)<\/template>/);
if (templateMatch) {
const templateContent = templateMatch[1];
const modifiedTemplate = codeLineTrack(templateContent, resourcePath);
// 替换原有的 template 内容
source = source.replace(templateContent, modifiedTemplate);
}
}
return source;
}
function codeLineTrack(str: string, resourcePath: string): string {
const lineList = str.split('\n');
const newList = lineList.map((item, index) => addLineAttr(item, index + 1, resourcePath));
return newList.join('\n');
}
function addLineAttr(lineStr: string, line: number, resourcePath: string): string {
const reg = /<[\w-]+/g;
let leftTagList = lineStr.match(reg);
if (leftTagList) {
leftTagList = Array.from(new Set(leftTagList));
leftTagList.forEach(item => {
if (item && item.indexOf('template') === -1) {
const regx = new RegExp(`${item}`, 'g');
const location = `${item} code-location="${resourcePath}:${line}"`;
lineStr = lineStr.replace(regx, location);
}
});
}
return lineStr;
}
4、配置vite.config.ts
在vite.config.ts中引入我们写好的自定义插件,我把两个函数都放在最前面了因为放后面可能会被其它插件干扰到
5、配置tsconfig.node.json
这里的主要目的是让vite能识别根目录下的文件不然在vite.config.ts中引入插件路径会报错,或者不生效的情况
识别src下的所有文件,让它能够识别出我们自定义的插件
6、在main.ts中加载全局监听事件监听内容
判断当前是否属于开发环境,如果是则可以触发监听,比较生产根本不需要,监听用户如果按住shift+左键点击某个元素则会获取到该元素上的code-location属性拿到文件路径包括行号
import openCodeClient from '@/utils/openCodeClient';
if (import.meta.env.MODE === 'development') {
openCodeClient.init();
// 添加全局点击事件监听
// 添加全局点击事件监听
document.addEventListener('click', (event) => {
const target = event.target as HTMLElement;
const codeLocation = target.getAttribute('code-location');
// 检查是否按住了 Shift 键并且点击了左键
if (event.shiftKey && event.button === 0 && codeLocation) {
fetch(`/code?filePath=${encodeURIComponent(codeLocation)}`)
.then((response) => {
if (response.ok) {
console.log('Code opened successfully');
} else {
console.error('Failed to open code');
}
})
.catch((error) => {
console.error('Error fetching code location:', error);
});
}
});
}
7、测试结果
如果插件正常加载成功,按f12打开元素审查会看到每个元素都有一个自定义属性,如果不成功则再检查看看是哪里有问题了
该项目借鉴了一位前端大佬的文章,文章链接。文章里有详细的设计思路和代码片段。 本来打算直接用大佬的项目,但是对方说暂时只在他们公司内部使用,故本人自己写了一个简单版的。