likes
comments
collection
share

0-1开发一个vite插件,原来项目上手可以这么快!

作者站长头像
站长
· 阅读数 31

先说用法,按住 ctrl 左击页面节点,可以跳转到编辑器中对应行,no bb 看效果演示 0-1开发一个vite插件,原来项目上手可以这么快!

git地址 github.com/kongweigen/… npm地址 www.npmjs.com/package/vit…

说一下背景,平时开发过程中,不会都是从 0-1 的项目,一些中途接手的项目,页面组件等熟悉起来就会比较费劲。有没有一个插件,来实现一键跳转到指定代码呢?那肯定是有的,npm上也有类似的插件,原理类似,就想着实现一个一键跳转, vite-plugin-jump-code 应运而生。鼠标点击,一键直达🚀🚀🚀

实现思路

  1. 通过 vite 的 transform 在页面节点插入源码路径
  2. 通过 vite 的 transformIndexHtml 插入脚本
  3. 监听鼠标点击事件,调用中间件服务,dom 上的路径作为参数
  4. 调用命令来拉起编辑器,并定位到指定位置。

具体实现

Talk is cheap, show me the code 多说无益,展示代码

1. vite 的 transform

transform 钩子是一个自定义插件的生命周期钩子,用于在构建过程中对模块进行转换或修改。例如自定义的代码转译、动态注入代码等。我们可以利用这个钩子函数,来实现源码地址的插入。

...省略
/**
 * 
 * @param code 字符串,表示当前模块的源代码 
 * @param path 字符串,表示当前模块的标识符,绝对路径
 * @returns 返回修改后的代码
 */
transform(code, path) {
  return transform(code, path)
}
...省略

transform 里面进行代码转换

  • vue文件进行转换,通过后缀辨别是否vue文件
  • 分割行,提取domtagName,拼接文件源码路径和行号
  • 拼接好路径插入的当前dom
import path from 'path'
import { normalizePath } from 'vite'

function generate(code: string, filePath: string) {
  // 根据回车拆分代码文件
  let codeArr = code.split('\n')
  let cwd = normalizePath(process.cwd())
  codeArr.forEach((codeRow, rowIndedx) => {
    // 获取相对路径
    filePath = filePath.replace(cwd, '')
    let tagName = getTagName(codeRow)
    if (tagName) {
      codeArr[rowIndedx] = codeRow.replaceAll(
        `<${tagName}`,
        `<${tagName} data-loc="${filePath}:${rowIndedx + 1}"`
      )
    }
  })
  code = codeArr.join('\n')
  return code
}
function getTagName(codeRow: string) {
  codeRow = codeRow.trim()
  // 判断是否 < 开头
  if (!/^<[a-zA-z]/.test(codeRow)) return ''
  // /\b/ 分词 '<div class="card">'.replace(/\b/g, "#") 
  // '<#div# #class#="#card#">'
  return codeRow.replace(/\b/g, '#').split('#')[1]
}
function transform(code: string, filePath: string) {
  let ext = path.extname(filePath)
  switch (ext) {
    case '.vue':
      return generate(code, filePath)
    default:
      return code
  }
}

export default transform

2. vite 的 transformIndexHtml

transformIndexHtml 转换 index.html 的专用钩子。通过这个方法,注入发起命令的脚本

...省略
transformIndexHtml: {
  transform() {
    return [
      {
        injectTo: 'head', // 指定插入位置 'head' | 'body' | 'head-prepend' | 'body-prepend'
        tag: 'script', // string 插入的节点名称
        children: inject // string | HtmlTagDescriptor[]  插入的内容
      }
    ]
  }
},
...省略

// inject 的具体内容
let injectFn = `
(function(){
  document.addEventListener('click', (e) => {
    // 在不同操作系统上对应不同的键,如 Command 键或 Windows 键
    // shift 或者 ctrl 按键
    if (e.metaKey || e.shiftKey || e.ctrlKey) {
      e.preventDefault();
      e.stopPropagation();
      let loc = getFilePath(e.target)
      // 调用中间件的服务,传入path
      loc && fetch('/jumpcode?path=' + loc)
    }
  })

  function getFilePath(el){
    if(!el) return
    let { loc } = el.dataset || {}
    // 三方的组件没有插入path,寻找父节点
    if(!loc){
      return getFilePath(el.parentElement)
    }else{
      return loc
    }
  }
})()
`
export default injectFn

3. vite 的 configureServer 和中间件

configureServer 是用于配置开发服务器的钩子。函数接收一个参数,即 server 对象 具体实现可以查看 connect

configureServer(server) {
  // 方法还采用与传入请求 URL 的开头相匹配的可选路径字符串。这允许基本的路由
  server.middlewares.use('/jumpcode', middleware)
},

// middlewar e具体实现
function middleware(req, res) {
  let cwd = normalizePath(process.cwd())
  const queryParams = url.parse(req.url!, true)
  let path = queryParams.query.path as string
  let pathList = path.split(':')
  // 行号
  let rowIndex = pathList[pathList.length - 1]
  // path: E:/xxx/vite-vue3/src/components/HelloWorld.vue
  path = cwd + pathList[0]

  try {
    openEditor(path, Number(rowIndex))
    // 定义状态码返回
    res.statusCode = 200
    res.end('ok')
  } catch (error) {
    console.log('打开失败', error)
    res.statusCode = 500
    res.end('ok')
  }
}

4. 编辑器的另一种打开方式

不知道大家是否知道,cmd 是可以直接打开文件,并且可以直接调用 vscode,打开指定文件的某一行。 cmd 打开文件,直接输入文件的绝对路径即可;还可以通过 code 命令调用 vscode 来打开指定文件的指定行。 0-1开发一个vite插件,原来项目上手可以这么快! 对应的文件就被打开,并且定位到对应行 0-1开发一个vite插件,原来项目上手可以这么快! 在VSCode中,"-g" 是一个命令行选项,用于在打开文件时定位到指定的行号。它的完整形式是 "--goto"。当然只有在使用 "code" 命令调用 VSCode 时有效。但是我们可能会有不同的编辑器、系统,手动兼容会很烦,所以我们可以直接使用create-react-app项目组的launchEditor.jslaunchEditor.js 会检查系统中已安装的编辑器,并尝试使用默认的编辑器打开文件。它会尝试使用以下编辑器(按优先级顺序):Visual Studio Code、Atom、Sublime Text、WebStorm。并定位到错误的文件和行号。地址 打开跳转的前置条件,vscode 需要先配置

0-1开发一个vite插件,原来项目上手可以这么快!

0-1开发一个vite插件,原来项目上手可以这么快!

效果

最终我们会看到实际的dom上,会插入doc-loc=/xxx/xxx/*vue:11,这就是我们用来定位文件的核心。 0-1开发一个vite插件,原来项目上手可以这么快!

总结

通过这次插件的实现,了解了不少vite插件的执行流程和中间件的使用,当然还没完成,现阶段仅支持vite,后续计划完善一下,支持webpack和cli。 分享的过程也是学习巩固的过程,一起进步,共勉。

转载自:https://juejin.cn/post/7281118263966072844
评论
请登录