点击DOM元素跳转源码位置插件
# 图例
- 开发环境下,按住
command
键,点击元素,自动打开 vscode,并跳转到该 dom 对应的源码位置


# 插件功能
- 在多人协作的项目里,如果有改 bug、改他人代码、改不熟悉的功能代码的场景,都能直接从浏览器快速定位到 VSCode 中的代码行,极大地提高了开发效率。
# 实现思路
生成
fileMap.json
文件,为项目中的所有文件创建了一个编号映射,并且存到这个文件中写一个方法
getAllFiles
,递归遍历项目目录,获取这个目录下所有文件的完整路径写一个方法
generateFileMap
,使用getAllFiles
方法,为 src 下所有的文件生成一个映射 Map 并且保存到本地fileMap.json
文件里
实现插件
vite-plugin-open-in-vscode
初始化的时候,在
configResolved
钩子里面执行,当 Vite 项目配置解析完成后,如果当前环境是开发环境,插件会调用generateFileMap
生成fileMap.json
文件。确保了在开发过程中,fileMap.json
始终是最新的,包含了项目中所有文件的映射。- 需要注意的是,如果在一次开发过程中,如果新建了很多文件,需要重新
yarn dev
,才能生成这些新建文件的映射
- 需要注意的是,如果在一次开发过程中,如果新建了很多文件,需要重新
集成一个
express
服务,这个服务用来提供一个接口http://localhost:6003/vscode/openfile
,这个接口的主要作用是根据接口的参数filePath
和lineNumber
,通过exec
命令调用 vscode,从而打开指定文件filePath
定位到指定行lineNumber
- 这个接口会在开发环境下,通过开发者的特定操作(按住
command
的时候鼠标左边点击 dom 元素),获取该 dom 元素的data-sf
和data-sl
属性,触发请求vscode/openfile
,其中 dom 元素的data-sf
和data-sl
属性就是接口的请求参数filePath
和lineNumber
- 这个接口会在开发环境下,通过开发者的特定操作(按住
# 实现代码
点击 展开/收起 jsx 代码
import express from 'express';
import { exec } from 'child_process';
import fs, { readFileSync } from 'fs';
import path from 'path';
import { join } from 'path';
// 获取所有文件路径的函数
function getAllFiles(dirPath, arrayOfFiles = []) {
const files = fs.readdirSync(dirPath);
files.forEach((file) => {
if (fs.statSync(path.join(dirPath, file)).isDirectory()) {
arrayOfFiles = getAllFiles(path.join(dirPath, file), arrayOfFiles);
} else {
arrayOfFiles.push(path.join(dirPath, file));
}
});
return arrayOfFiles;
}
// 生成文件映射的函数
function generateFileMap() {
const allFiles = getAllFiles('./src'); // 遍历 src 目录下的所有文件
const fileMap = {};
allFiles.forEach((file, index) => {
fileMap[index] = file;
});
fs.writeFileSync('fileMap.json', JSON.stringify(fileMap, null, 2));
}
export default function openInVSCodePlugin() {
return {
name: 'vite-plugin-open-in-vscode',
configResolved(config) {
if (process.env.NODE_ENV === 'development') {
// 项目运行之前生成文件映射
generateFileMap();
}
},
configureServer(server) {
const app = express();
app.use(express.json());
app.get('/vscode/openfile', async (req, res) => {
const { filePath, lineNumber, columnNumber } = req.query;
// 读取文件映射
const fileMap = JSON.parse(
readFileSync(join(process.cwd(), 'fileMap.json'), 'utf8'),
);
if (filePath && lineNumber) {
exec(
`code -g ${fileMap[filePath]}:${lineNumber}:${columnNumber || 1}`,
(err) => {
if (err) {
console.error(`Error opening file in VSCode: ${err.message}`);
res.status(500).send('Error opening file in VSCode');
return;
}
res.send('File opened in VSCode');
},
);
} else {
console.error('Invalid filePath or lineNumber');
res.status(400).send('Invalid filePath or lineNumber');
}
});
app.listen(6003, () => {
console.log(`Express server running on http://localhost:${6003}`);
});
server.middlewares.use(app);
},
};
}