作者|vivo互联网大前端团队-友辰一、背景现在的大型Vue项目基本都是多人协作开发,而且随着版本的迭代,Vue项目中的组件数量也会随之增加增加。如果此时,你负责的是不熟悉的页面功能开发,即使你刚刚加入这个项目,你又如何快速找到整个项目代码中相关组件的文件位置呢?想必大家都采取过以下方法:【查找类名】,在项目文件中查找页面DOM元素中的样式类名【查找路由】,根据页面链接查找匹配Vue路由的页面组件【查找someone],找到负责开发页面的人,询问对应的代码路径。以上方法确实可以帮助我们找到具体的代码文件路径,但是都需要手动查找,效率不是很高。还有其他更有效的方法吗??答案是肯定的。Vue官方提供了一个vue-devtools插件,可以在VSCode中自动打开相应页面组件的源码文件。运行路径如下:使用vue-devtools插件可以提高我们查找对应页面组件代码的效率,但是只能定位到对应的组件代码。如果我们想直接找到页面中某个元素相关的具体代码位置,需要在当前组件源代码中进行二次搜索,每次都先选择。组件,然后点击打开按钮,打开代码文件,速度不是特别快。针对这个问题,我们开发了一款轻量级的页面元素代码映射插件,可以通过点击页面元素,一键打开对应的代码源文件,准确定位到对应的代码行,无需手动搜索,可以大大提高为提高开发效率和体验,实际使用效果如下:二、实现原理整个插件主要分为3个功能模块:client,server,add-code-location,client发送具体请求到服务端,服务端收到请求后执行命令定位代码行,使用add-code-location模块进行源码转换。2.1客户端这里的客户端实际上是指浏览器。当我们点击一??个页面元素时,浏览器会向服务器端发送一个特定的请求。请求信息包括具体的代码文件路径和对应的代码行号信息。functionopenEditor(filePath){axios.get(`${protocol}//${host}:${port}/code`,{params:{filePath:`${filePath}`}}).catch(error=>{console.log(error)})}并通过事件代理的全局监听监听页面元素的点击事件,将点击事件绑定到文档上,监听键盘鼠标点击事件的组合发起一个请求定位代码行,避免与页面原生点击事件冲突。functionopenCode(e){if(isShiftKey||isMetaKey||e.metaKey||e.shiftKey){e.preventDefault()constfilePath=getFilePath(e.target)openEditor(filePath)}...}2.2服务器服务器side是指本地服务器,可以监听客户端发送的特定请求。当收到执行定位命令的请求时,执行VSCode打开代码文件命令,定位到对应的代码行。2.2.1webpackdevServer如果项目是用webpack搭建的,webpack的devServer开发服务器提供了一个before属性,可以用来监听发往开发服务器的请求。before:function(app){app.get('/code',function(req,res){if(req.query.filePath){//执行vscode定位代码行命令openCodeFile(req.query.filePath)...}...})}2.2.2viteconfigureServer如果项目是用Vite搭建的,可以在server端使用Vite插件监听特定的请求。Vite插件扩展了rollup插件接口,增加了一些特定的钩子函数,比如configureServer钩子,可以通过这个钩子函数配置开发服务器监听特定的请求。constcodeServer=()=>({name:'open-code-vite-server',configureServer(server){server.middlewares.use((req,res,next)=>{...if(pathname=='/code'){...if(filePath){openCodeFile(filePath)//执行vscode定位代码行命令...}res.end()}...})}})2.2.3执行VSCode定位命令当服务端监听到客户端发送的具体请求后,下一步就是执行VSCode定位代码行命令。其实VSCode编辑器是可以通过code命令来启动的,可以相应的使用一些命令行参数,例如:“code--reuse-window”或者“code-r”命令可以打开编辑器的文件或文件夹最后一个活动窗口;“code--goto”或“code-g”命令后面可以拼接具体的文件路径和行列号,使用“code-gfile:line:column”命令时,可以打开一个文件并定位到具体的文件行和列的位置。利用VSCode编辑器的这个特性,我们可以实现自动定位代码行的功能。可以从客户端发送的请求信息中获取对应的代码路径信息,然后使用node的child_process.exec方法执行VSCode定位代码行命令。constchild_process=require('child_process')functionopenCodeFile(path){letpathBefore=__dirname.substring(0,__dirname.search('node_modules'))letfilePath=pathBefore+pathchild_process.exec(`code-r-g${filePath}`)}另外,为了正常使用VSCode的Code命令,我们需要确保将VSCode的Code命令添加到环境变量中。Mac系统用户可以在VSCode界面使用command+shift+p快捷键,然后搜索Code,在路径中选择install‘code’命令;Windows用户可以找到VSCode安装位置的bin文件夹目录,将此目录添加到系统环境变量中。2.3add-code-location通过前面的介绍,应该了解了客户端和服务端的执行机制,执行location命令时需要获取页面元素的代码路径,具体的代码路径绑定在formofattributes当涉及到DOM元素时,我们需要使用add-code-location模块在编译时转换我们的源代码,并为DOM元素添加相应的代码路径属性。整个源码转换过程如下:2.3.1获取文件路径源码转换过程的第一步是获取代码文件的具体路径。对于webpack打包的项目,webpackloader适合处理源码字符串。loader的context这个对象包含一个resourcePath资源文件的path属性,利用这个属性我们可以很方便的获取到每个代码文件的具体路径。module.exports=function(source){const{resourcePath}=thisreturnsourceCodeChange(source,resourcePath)}对于Vite构建的项目,源码的转换也是通过插件完成的。vite插件有一个通用的hooktransform,可以用来对加载的模块内容进行转换,它接收两个参数,code参数代表源代码字符串,id参数是文件的完整路径。module.exports=function(){return{name:'add-code-location',transform(code,id){...returnsourceCodeChange(code,id)}}}2.3.2计算代码行号,然后遍历源码文件的过程中,需要对对应vue文件的template模板中的代码进行处理,将template模板的部分字符串用“\n”分割成一个数组,准确获取代码行号每行HTML标签通过数组的索引。functioncodeLineTrack(str,resourcePath){letlineList=str.split('\n')letnewList=[]lineList.forEach((item,index)=>{newList.push(addLineAttr(item,index+1,resourcePath))//添加location属性,index+1为具体代码行号})returnnewList.join('\n')}2.3.3添加location属性获取到代码文件路径和代码行号后,接下来就是就是给vue模板模板中划分的每一行label元素加上最后的position属性。这里使用正则替换的方式来添加position属性。对于每一行label元素,首先正则匹配所有元素的开始标签部分,比如
