什么!react-developer-tool居然不支持打开vscode,那自行实现一个

362 阅读2分钟

背景

目前 Vue Devtools 已支持通过点击跳转至 VSCode 对应文件。但在 Vite 项目中,React Devtools 暂不支持此功能。

原因分析

React Devtools 的「Open in Editor」功能依赖形如 vscode://{file}/{path}:{line} 的跳转链接,该链接来源于 source map 中的 file 信息。

然而,Vite 默认生成的 source map 并不包含 file 字段,导致无法构建出正确的跳转链接,功能因此被置灰。

相关问题详见:facebook/react#28999

目标实现效果

目前有现有插件vite-plugin-vue-inspector,仿照它的效果来实现一个react的版本,效果如下:

image.png

实现原理分析

具体细节


function VitePluginInspector(): Plugin {
  return {
    name: "unplugin-react-inspector",
    // 应用顺序
    enforce: "pre",
    // 含义: 转换钩子,接收每个传入请求模块的内容和文件路径
    // 应用: 在这个钩子对jsx\tsx模版进行解析并注入自定义属性
    transform(code, id) {

    },
    // 含义: 配置开发服务器钩子,可以添加自定义中间件
    // 应用: 在这个钩子实现Open Editor调用服务
    configureServer(server) {

    },
    // 含义: 转换index.html的专用钩子,接收当前HTML字符串和转换上下文
    // 应用: 在这个钩子自动注入交互功能
    transformIndexHtml(html) {

    },
  }
}


  • 编译时注入

transform钩子进行ast解析,将resovledIdloc的信息注入

  • 交互层注入

通过虚造路径,加载解析对应虚造的路径文件

async resolveId(id) {
    // 处理虚拟路径
    if (id.startsWith('virtual:react-inspector-path:')) {
        const resolved = id.replace('virtual:react-inspector-path:', `${inspectorPath}/`)
        return resolved
    }
},

async load(resolveId) {
    // 加载解析文件
    if (resolveId.startsWith(inspectorPath)) {
        if (fs.existsSync(resolveId)) {
            return fs.readFileSync(resolveId, 'utf-8')
        }
        else {
            console.error(`[unplugin-react-inspector] failed to find file: ${resolveId}`)
        }
    }
},
  • 获取文件信息

在编译时已经为每一个元素注入了options信息,提供了file、line、column信息。在经过元素的时候,可以拿到attribute属性,只需拿到有options属性的元素即可

const path = e.composedPath() as Element[]
// 过滤没有options属性的元素
const ignoreIndex = path.findIndex(node => node?.hasAttribute?.(KEY_IGNOE))
const targetNode = path.slice(ignoreIndex + 1).find((node: Element) => getData(node))
  • 打开编辑器

vite内置已经实现了/__open_in_editor中间件,只需要发起fecth(url)

const openEditor = (baseUrl: URL, file: any, line: any, column: any) => {
        const _url = baseUrl instanceof URL ? baseUrl : `/__open-in-editor?file=${encodeURIComponent(`${file}:${line}:${column}`)}`
        const promise = fetch(_url, { mode: 'no-cors' })
        return promise
}

vite的open in edtior也是参考react-developer-tool的utils文件实现的,它封装了一个服务中间件。因此直接使用即可。 具体可以参考:github.com/yyx990803/l…

致谢

整个实现都参考了两个项目: 1、vite-plugin-vue-inpsector 2、react-dev-inspector

总结

相关代码地址见下方,欢迎参考: github.com/Triumph-lig…

📌 如果觉得有帮助,欢迎点个 Star~
💬 如有问题,欢迎提 Issue 或指出改进建议!