作者:vivo互联网前端团队-
一、背景
现在大型的 Vue 项目基本都是多人协同开发,随着版本的迭代,Vue 项目中的组件数量会越来越多。如果此时负责不熟悉的页面功能的开发,即使是刚加入项目,如何快速找到整个项目代码中的相关组件?文件位置呢?想必大家都采取了以下方法:
以上方法确实可以帮我们找到具体的代码文件路径,但是都需要手动查找,效率不高。还有其他方法吗?更有效的方法呢?
答案是肯定的。 vue官方提供了一个vue-,可以在插件中自动打开对应页面组件的源码文件。操作路径如下:
使用vue-可以大大提高查找对应页面组件代码的效率,但是只能定位到对应的组件代码。如果我们想直接找到页面上某个元素相关的具体代码位置,还需要找到页面上某个元素相关的具体代码位置。在组件源代码中进行二次搜索,每次都要先选择组件,然后点击Open按钮打开代码文件,速度不是特别快。
针对这个问题,我们开发了一个轻量级的页面元素代码映射插件。使用该插件,可以点击页面元素,一键打开对应的代码源文件,准确定位对应的代码行。无需手动搜索,可大大提升开发效率和体验。实际使用效果如下:
二、实现原理
整个插件主要分为3个功能模块: , , add-code-, 端向端发送特定请求,端接收请求并执行定位码行命令,添加-code- 模块用于源代码转换。
2.1
这里的终端实际上是指浏览器。当我们点击页面元素时,浏览器会向末尾发送一个具体的请求,请求信息包括具体的代码文件路径和对应的代码行号信息。
function openEditor(filePath) {
axios
.get(`${protocol}//${host}:${port}/code`, {
params: {
filePath: `${filePath}`
}
})
.catch(error => {
console.log(error)
})
}
监控页面元素的点击事件,通过事件代理的方式全局监控,绑定点击事件,监控键盘鼠标点击组合事件,发起定位代码行请求,避免与页面原生点击事件发生冲突。
function openCode(e) {
if (isShiftKey || isMetaKey || e.metaKey || e.shiftKey) {
e.preventDefault()
const filePath = getFilePath(e.target)
openEditor(filePath)
}
...
}
2.2
客户端是指可以监控客户端发送的特定请求的本地服务器。当收到执行定位命令的请求时,执行命令打开代码文件,定位到对应的代码行。
2.2.1
如果是构建项目,开发服务器已经提供了一个属性,可以用来监听并发送给开发服务器的请求。
before: function (app) {
app.get('/code', function (req, res) {
if (req.query.filePath) {
// 执行vscode定位代码行命令
openCodeFile(req.query.filePath)
...
}
...
})
}
2.2.2 vite
如果是用Vite搭建的项目,可以使用Vite插件来实现终端监听具体请求,Vite插件扩展了插件接口,在原有基础上增加了一些独特的钩子功能,比如钩子,可以用来配置开发服务器监控特定的请求。
const codeServer = () => ({
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 执行定位指令
当 end 监听到 end 发送的具体请求后,下一步就是执行 code line命令。其实可以通过code命令来启动编辑器,相应地使用一些命令行参数,例如:
“code –reuse-”或“code -r”命令可以打开最后一个活动窗口具体的文件路径和行列号可以在“code–goto”或者“code -g”后面拼接“ 命令。使用“code -g file:line:”命令时,可以打开一个文件,定位到具体的行列位置。
利用编辑器的这个特性,我们可以实现自动定位代码行的功能。可以从终端发送的请求信息中获取对应的代码路径信息,然后使用node的.exec方法执行定位代码。行命令。
const child_process = require('child_process')
function openCodeFile(path) {
let pathBefore = __dirname.substring(0, __dirname.search('node_modules'))
let filePath = pathBefore + path
child_process.exec(`code -r -g ${filePath}`)
}
另外,为了正常使用Code命令,我们需要确保将Code命令添加到环境变量中。 Mac系统用户可以使用界面中的+shift+p快捷键,然后在路径中搜索Code并选择’code’;用户可以找到安装位置的bin文件夹目录,将该目录添加到系统环境变量中。
2.3 add-code-
通过前面的介绍,大家应该了解了终端和终端的执行机制,在执行定位命令时需要获取页面元素的具体代码路径,以属性的形式与DOM元素绑定。这时候我们就需要在编译时使用add-code-来转换我们的源码,并在DOM元素中添加对应的代码路径属性。 .
整个源码转换过程如下:
2.3.1 获取文件路径
源码转换过程的第一步是获取代码文件的具体路径。对于打包的项目,适合对源代码字符串进行处理。此对象的上下文包含资源文件的路径属性。使用这个属性我们可以很容易的得到每个代码文件的具体路径。
module.exports = function (source) {
const { resourcePath } = this
return sourceCodeChange(source, resourcePath)
}
Vite搭建的项目,源代码的转换也是通过插件完成的。 Vite 插件有通用的钩子,可以用来转换加载的文件。模块内容,它接收两个参数,code参数代表源字符串,id参数是文件的全路径。
module.exports = function() {
return {
name: 'add-code-location',
transform(code, id) {
...
return sourceCodeChange(code, id)
}
}
}
2.3.2 计算代码行号
然后在遍历源文件的过程中,需要处理对应的vue文件模板中的代码,模板部分字符串除以“n”为数组,每行的代码行号HTML标签的数量可以通过数组的索引准确获取。
function codeLineTrack(str, resourcePath) {
let lineList = str.split('n')
let newList = []
lineList.forEach((item, index) => {
newList.push(addLineAttr(item, index + 1, resourcePath)) // 添加位置属性,index+1为具体的代码行号
})
return newList.join('n')
}
2.3.3 添加位置属性
在得到代码文件路径和代码行号之后,下一步就是在Vue模板中分割的每一行标签元素中添加最终位置属性。这里采用正则替换的方法添加位置属性,每行标签元素首先匹配所有元素的开始标签部分,例如
function addLineAttr(lineStr, line, resourcePath) {
let reg = / {
if (item && item.indexOf('template') == -1) {
let regx = new RegExp(`${item}`, 'g')
let location = `${item} code-location="${resourcePath}:${line}"`
lineStr = lineStr.replace(regx, location)
}
})
}
return lineStr
}
2.4 其他处理2.4.1 源码相对路径
给DOM元素添加对应的源码位置 指定属性时,实际使用的是相对路径,可以让DOM元素上的属性值更加简洁明了。该文件夹通常在项目的根目录下,插件以npm包的形式安装在路径中。使用node变量可以得到当前模块的绝对路径,所以在源码转换过程中可以得到项目的根路径。 ,这样就可以得到Vue代码文件的相对路径了。
let pathBefore = __dirname.substring(0, __dirname.search('node_modules'))
let filePath = filePath.substring(pathBefore.length) // vue代码相对路径
在终端执行代码定位命令时,将对应的代码相对路径拼接成完整的绝对路径。
2.4.2个外部导入组件
add-code-虽然可以在本地vue文件中添加代码路径信息,但是对于外部导入的组件或者,目前没有办法转换加载的组件,比如ui组件。实际上,这行代码信息只会添加到ui组件的最外层。此时,终端在获取到被点击元素的代码路径后,会进行向上搜索的过程,获取其父节点的代码路径。如果仍然不存在,则继续搜索父节点的父节点,直到成功获取代码路径。
function getFilePath(element) {
if (!element || !element.getAttribute) return null
if (element.getAttribute('code-location')) {
return element.getAttribute('code-location')
}
return getFilePath(element.parentNode)
}
这样,当你点击后台ui构建的页面元素时,也可以成功定位并打开对应的代码文件。
三、访问计划
通过前面的介绍,我想你已经对页面元素代码映射插件的原理有了一个清晰的认识。访问方法。访问方式其实很简单,可以选择只在本地开发环境访问,不用担心影响我们的生产环境,可以放心使用。
3.1 构建项目
对于构建好的项目,首先配置构建配置项vue..js文件,然后在main.js入口文件中初始化插件。
// vue.config.js
const openCodeServe = require('@vivo/vue-dev-code-link/server')
devServer: {
...
before: openCodeServe.before
},
if (!isProd) { // 本地开发环境
config.module
.rule('vue')
.test(/.vue/)
.use('@vivo/vue-dev-code-link/add-location-loader')
.loader('@vivo/vue-dev-code-link/add-location-loader')
.end()
}
// main.js
import openCodeClient from '@vivo/vue-dev-code-link/client'
if (process.env.NODE_ENV == 'development') {
openCodeClient.init()
}
3.2 Vite 构建项目
Vite构建项目对该插件的访问与构建项目基本相同,唯一不同的是打包配置文件中引入了两个Vite插件。
// vite.config.js
import openCodeServer from '@vivo/vue-dev-code-link/vite/server'
import addCodeLocation from '@vivo/vue-dev-code-link/vite/add-location'
export default defineConfig({
plugins: [
openCodeServer(),
addCodeLocation()
]
}
四、总结
以上是对页面元素代码映射插件的核心原理和访问方案的介绍。该方法充分利用了项目代码打包和构建过程。其实无论使用哪种打包工具,本质上都是源代码文件的转换处理。在了解了打包工具的运行机制之后,我们就可以做一些我们认为有意义的事情了。事情。以页面元素代码映射插件为例。使用它可以大大提高开发效率,不再需要花时间去寻找代码文件,特别是对于页面和组件较多的项目,只需点击页面元素即可。一键打开对应代码文件,精准定位具体代码行,无需搜索,无需点击,轻松搞定!
暂无评论内容