背景
作为前端程序员,我们并不是每次都会参与到新项目中,很多时候还要去维护旧代码。通常,我们为了熟悉项目,会先根据项目的README
等,按照步骤把项目跑起来。然后再去看对应路由下的页面的展示效果。
其中,有的项目可能特别大,组件拆分也比较多(上千个)。可能本次需求就是更改一两个标签的样式,但是由于不熟悉项目,需要先在浏览器检查对应标签上的class等属性,找到一个比较特定的字符串,再到代码编辑器里去找到对应的组件。(然后发现很多重复的结果T_T)
有没有可以根据渲染出来的页面,像浏览器检查元素一样,快速定位到组件源代码的方案呢?
解决方案
code-inspector
Git地址:code-inspector
code-inspector-plugin
是一款基于webpack/vite/rspack/nextjs/nuxt/umijs plugin
的提升开发效率的工具,点击页面上的 DOM,它能够自动打开你的 IDE 并将光标定位到 DOM 对应的源代码位置。
优势
- 较高的社区活跃度(
1k+ star
) - 跨技术栈的完整解决方案(
webpack/vite/rspack/nextjs/nuxt/umijs plugin
)
缺点
- 会在dom里插入一长串源码路径,导致class、style、以及自定义的属性等被挤到后面,不好辨认,尤其对于UnoCSS等项目
- 只能找到dom元素所在位置(template),无法定位js代码位置
click-to-vue-component
基于
vue-cli
,快速定位Vue组件源码
这是我根据团队需求,结合社区方案开发的一款仅针对Vue项目的元素定位源代码的解决方案。
在社区方案的基础上,提供了以下增强实现:
- 解决了会在元素上写入一大段源码路径的问题(hash映射)
- 提供了控制台日志跳转源代码的功能
使用方法
- 安装
npm install click-to-vue-component -D
- 在项目根目录的
vue.config.js
文件中添加以下代码:(@vue/cli-service@^5.x)
const { defineConfig } = require('@vue/cli-service')
+const clickToVueComponent = require('click-to-vue-component')
module.exports = defineConfig({
+ chainWebpack: (config) => {
+ clickToVueComponent(config)
+ }
})
- 启动项目,打开测试页面,按住
option
,然后点击页面上的任意元素即可跳转到vscode源码所在位置。
标签跳转
日志跳转
实现原理
标签跳转
对于项目中的所有vue
文件,会通过自定义的loader来处理。
因为vue
源文件是一个类HTML
的结构,所以这里会借助parse5来处理,得到所有的标签的位置信息:所在文件路径:行:列,存储到全局变量global.__vueSourceCodeLocMap
上,然后在webpack
构建完成后,将这个map信息通过websocket
推送到客户端,并挂载在window
上。
const { startOffset, startLine, startCol } = node.sourceCodeLocation
const codeLoc = `${filePath}:${startLine}:${startCol}`
const hash = CryptoJS.MD5(codeLoc).toString().substring(0, 8)
const sourceCodeLocation = ` data-code-loc='${hash}' `
const insertPos = startOffset + node.nodeName.length + 1
global.__vueSourceCodeLocMap[hash] = codeLoc
result =
result.substring(0, insertPos) +
sourceCodeLocation +
result.substring(insertPos)
window.__vueSourceCodeLocMap
然后我们会通过自定义的webpack plugin,在输出的index.html
中插入客户端逻辑,主要就是监听页面的点击事件,然后获取到所点击的元素,以及在元素上绑定的data-code-loc
属性,通过data-code-loc
得到hash
值,然后在window.__vueSourceCodeLocMap
对应标签的位置信息,并通过vscode://file
协议打开vscode,并跳转到源码位置。
日志跳转
同标签跳转一样,通过loader
,我们全局搜索源代码中所有的console
,然后在同行console
后面在插入一个带样式的console
,这样就会在控制台渲染一个类似按钮的效果:
点击这个查看源码
就能通过浏览器打开vscode
,定位到源码位置。
export default function (source: string) {
try {
const { resourcePath } = this
const lines = source.split(/\r|\n/g)
const newLinse = lines.slice()
lines.forEach((str, index) => {
const res = str.match(/console.log\(.*?\)\s*$/g)
if (res) {
const ln = index + 1
const col = str.indexOf('console') + 1
newLinse[index] += `; console.log('%c查看源码%cvscode://file${resourcePath}%3A${ln}%3A${col}', 'padding: 1px 3px; border-radius: 6px; background-color: #ff6400; color: #fff;', 'font-size: 0.8px; line-height: 18px; background: transparent; margin-left: -48px;')`
}
})
// 返回修改后的源代码
return newLinse.join('\n')
} catch (error) {
console.log(error)
return source
}
}
热更新
因为我们采用了hash
映射源码位置的做法,所以每次热更新的时候我们需要去更新window
上挂载的__vueSourceCodeLocMap
信息,否则对于新的代码,就无法找到源码。
所以我们在项目启动的时候,会同时开启一个websocket
服务器,每当热更新的时候,我们就会把最新的map
信息推送到客户端
compiler.hooks.emit.tapAsync('ClickToVueComponentPlugin', (compilation, callback) => {
// ...
const vueSourceCodeLocMap = JSON.stringify(global.__vueSourceCodeLocMap)
getWsInstance().then(ws => {
ws.send(vueSourceCodeLocMap)
})
callback()
})
客户端:
socket.addEventListener('message', (event) => {
const data = event.data
try {
window.__vueSourceCodeLocMap = JSON.parse(data || '{}')
} catch {}
})
注:此文受神光大佬写的一篇文章React 项目里,如何快速定位你的组件源码?启发而来