Skip to content

Instantly share code, notes, and snippets.

@ka2n
Created December 27, 2021 05:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ka2n/24aabfc4c641a4a987885f69ab2363ce to your computer and use it in GitHub Desktop.
Save ka2n/24aabfc4c641a4a987885f69ab2363ce to your computer and use it in GitHub Desktop.
Open source code location in VS Code without babel plugin
declare global {
interface Window {
__openSourceHandlers: {
teardown: () => unknown
} | null
}
}
if (process.env.NODE_ENV === "development") {
;(function () {
type ModKeys = "Alt" | "Ctrl" | "Shift"
class OpenSource {
private size: { width: number; height: number }
private host: HTMLElement
private shadow: ShadowRoot
private canvas: HTMLCanvasElement
private ctx: CanvasRenderingContext2D
private activeTarget: HTMLElement | null
private _active: Boolean
modKey: ModKeys
setup() {
this.createNode()
document.addEventListener("keyup", this.handleKeyUp)
document.addEventListener("keydown", this.handleKeyDown)
document.addEventListener("resize", this.handleResize)
}
teardown() {
document.removeEventListener("keyup", this.handleKeyUp)
document.removeEventListener("keydown", this.handleKeyDown)
document.removeEventListener("resize", this.handleResize)
this.host.remove()
}
constructor(modKey: ModKeys = "Alt") {
this.modKey = modKey
}
set active(isActive: boolean) {
if (isActive) {
document.addEventListener("mouseover", this.handleMouseOver)
document.addEventListener("click", this.handleClick)
} else {
document.removeEventListener("mouseover", this.handleMouseOver)
document.removeEventListener("click", this.handleClick)
this.ctx.clearRect(0, 0, this.size.width, this.size.height)
}
this._active = isActive
}
get active(): boolean {
return !!this._active
}
private handleMouseOver = (e: MouseEvent) => {
if (!this.active) return
if (!e.target) return
const fiberNode = getClosestInstanceFromElement(
e.target as HTMLElement,
"node"
)
if (!fiberNode) return
this.activeTarget = fiberNode.stateNode
this.render()
}
private handleClick = (e: MouseEvent) => {
if (!this.active) return
e.preventDefault()
e.stopPropagation()
const fiberNode = getClosestInstanceFromElement(
e.target as HTMLElement,
"source"
)
if (!fiberNode) return
this.active = false
this.openEditor(fiberNode)
}
private handleKeyDown = (e: KeyboardEvent) => {
if (e.key !== this.modKey) return
this.active = true
}
private handleKeyUp = (e: KeyboardEvent) => {
if (e.key !== this.modKey) return
this.active = false
}
private render() {
if (!this.activeTarget) {
this.ctx.clearRect(0, 0, this.size.width, this.size.height)
return
}
const size = this.size
const elem = this.activeTarget
const ctx = this.ctx
// This code is borrowed from https://github.com/ilyashubin/hover-inspect/blob/master/app/hoverinspect.js
const rect = elem.getBoundingClientRect()
const box = {
width: rect.width,
height: rect.height,
top: rect.top,
left: rect.left,
}
ctx.clearRect(0, 0, size.width, size.height)
ctx.fillStyle = "rgba(255,165,0,0.5)"
ctx.fillRect(box.left, box.top, box.width, box.height)
// rulers (horizontal - =)
let x = -10
let y = Math.floor(box.top) + 0.5
let width = size.width + 10
let height = box.height - 1
ctx.beginPath()
ctx.setLineDash([10, 3])
ctx.fillStyle = "rgba(0,0,0,0.02)"
ctx.strokeStyle = "rgba(13, 139, 201, 0.45)"
ctx.lineWidth = 1
ctx.rect(x, y, width, height)
ctx.stroke()
ctx.fill()
// rulers (vertical - ||)
x = box.left
y = -10
width = box.width
height = size.height + 10
ctx.beginPath()
ctx.setLineDash([10, 3])
ctx.fillStyle = "rgba(0,0,0,0.02)"
ctx.strokeStyle = "rgba(13, 139, 201, 0.45)"
ctx.lineWidth = 1
ctx.rect(x, y, width, height)
ctx.stroke()
ctx.fill()
}
private handleResize() {
this.size = { width: window.innerWidth, height: window.innerHeight }
this.canvas.width = this.size.width
this.canvas.height = this.size.height
this.render()
}
private openEditor(node: FiberNode) {
const sourceLoc = node._debugSource
if (!sourceLoc) return
window.open(
"vscode://file/" + sourceLoc.fileName + ":" + sourceLoc.lineNumber
)
}
private createNode() {
const host = document.createElement("div")
const shadow = host.attachShadow({ mode: "open" })
shadow.innerHTML =
'<div style="position: fixed; top: 0; left:0; right:0;bottom:0; pointer-events: none; z-index:9999999;"><canvas id="canvas" /></div>'
const canvas = shadow.getElementById("canvas") as HTMLCanvasElement
const ctx = canvas.getContext("2d")!
const size = { width: window.innerWidth, height: window.innerHeight }
canvas.width = size.width
canvas.height = size.height
this.host = host
this.shadow = shadow
this.ctx = ctx
this.size = size
document.body.appendChild(host)
}
}
const getClosestInstanceFromElement = (
node: HTMLElement,
traverse?: "source" | "node"
) => {
const fiberMetadataKey = Object.keys(node).find((key) =>
key.startsWith("__reactFiber")
)
if (!fiberMetadataKey) return
let currentFilberNode = node[fiberMetadataKey] as FiberNode
switch (traverse) {
case "source":
return findClosestInstance(
currentFilberNode,
(node) => !!node._debugSource
)
case "node":
return findClosestInstance(
currentFilberNode,
(node) => !!node.stateNode
)
default:
return currentFilberNode
}
}
const findClosestInstance = (
node: FiberNode,
filter: (node: FiberNode) => boolean
): FiberNode | undefined => {
let current: FiberNode | null = node
while (true) {
if (!current) return
if (filter(current)) {
return current
} else {
current = current._debugOwner
}
}
}
const inject = () => {
if (typeof window !== "object") return
if (window.__openSourceHandlers) {
window.__openSourceHandlers.teardown()
}
const instance = new OpenSource()
window.__openSourceHandlers = instance
instance.setup()
}
inject()
})()
}
type DebugSource = {
fileName: string
lineNumber: number
columnNumber: number
}
type FiberNode = {
type: string
elementType: React.ReactElement
stateNode: HTMLElement | null
child: FiberNode | null
_debugOwner: FiberNode
_debugSource: null | DebugSource
}
export {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment