Skip to content

Commit

Permalink
refactor: separate window messaging (#282)
Browse files Browse the repository at this point in the history
  • Loading branch information
webfansplz authored Mar 16, 2024
1 parent c475e67 commit bb57ec2
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 87 deletions.
67 changes: 13 additions & 54 deletions packages/client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import '@unocss/reset/tailwind.css'
import 'floating-vue/dist/style.css'

import type { BridgeInstanceType } from '@vue/devtools-core'
import { BROADCAST_CHANNEL_NAME, isInChromePanel, isInElectron, isInIframe } from '@vue/devtools-shared'
import { Bridge, HandShakeServer, createDevToolsVuePlugin, initViteClientHotContext, setupDevToolsBridge } from '@vue/devtools-core'
import { isInChromePanel, isInElectron, isInIframe } from '@vue/devtools-shared'
import { Bridge, HandShakeServer, createDevToolsVuePlugin, initDevToolsSeparateWindow, initDevToolsSeparateWindowBridge, initViteClientHotContext, setupDevToolsBridge } from '@vue/devtools-core'

import type { App as AppType } from 'vue'
import { createApp } from 'vue'
import { createMemoryHistory, createRouter } from 'vue-router'
import App from './App.vue'
Expand Down Expand Up @@ -128,66 +127,26 @@ window.addEventListener('message', (event) => {
}
})

// @TODO: refactor separate window channel
if (!isInIframe && !isInChromePanel && !isInElectron) {
function initSeparateWindowChannel() {
const connectionInfo: {
connected: boolean
timer: NodeJS.Timeout | null
app: AppType<Element> | null
} = {
connected: false,
timer: null,
app: null,
}

const channel = new BroadcastChannel(BROADCAST_CHANNEL_NAME)

function connect() {
connectionInfo.timer = setInterval(() => {
channel.postMessage({
source: '__VUE_DEVTOOLS_CLIENT__',
data: {
event: 'ready',
},
})
}, 2000)
}

connectionInfo.app = createConnectionApp()

channel.onmessage = (event) => {
if (event.data?.data?.event === '__VUE_DEVTOOLS_CREATE_CLIENT__') {
connectionInfo.app?.unmount()
connectionInfo.connected = true
clearInterval(connectionInfo.timer!)
function initSeparateWindow() {
const connectionApp = createConnectionApp()

initDevToolsSeparateWindow({
onConnected: (channel) => {
connectionApp?.unmount()
initDevTools({
connect: (callback) => {
const bridge = new Bridge({
tracker(fn) {
channel.onmessage = (event) => {
if (event.data.source === '__VUE_DEVTOOLS_USER_APP__')
fn(event.data.data)
}
},
trigger(data) {
channel.postMessage({
source: '__VUE_DEVTOOLS_CLIENT__',
data,
})
},
})
const bridge = initDevToolsSeparateWindowBridge(channel)
bridge.on('disconnect', () => {
channel.close()
initSeparateWindowChannel()
initSeparateWindow()
})
callback(bridge)
},
})
}
}
connect()
},
})
}
initSeparateWindowChannel()

initSeparateWindow()
}
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './bridge'
export * from './vite-bridge'
export * from './bridge-events/devtools-actions'
export * from './bridge-events/devtools-listeners'
export * from './separate-window'
91 changes: 91 additions & 0 deletions packages/core/src/separate-window/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Bridge } from '../bridge'
import { prepareInjection } from '../injection'

const BROADCAST_CHANNEL_NAME = '__vue-devtools-broadcast-channel__'

const MESSAGING_APP_TARGET = '__VUE_DEVTOOLS_USER_APP__'
const MESSAGING_DEVTOOLS_TARGET = '__VUE_DEVTOOLS_CLIENT__'
const CHECK_CONNECTION_EVENT = '__VUE_DEVTOOLS_CHECK_CONNECTION__'
const CONNECTED_EVENT = '__VUE_DEVTOOLS_CONNECTED__'

// used in user app side
export function initAppSeparateWindow() {
const channel = new BroadcastChannel(BROADCAST_CHANNEL_NAME)
const bridge = new Bridge({
tracker(fn) {
channel.onmessage = (event) => {
if (event.data.target === MESSAGING_DEVTOOLS_TARGET)
fn(event.data.data)
}
},
trigger(data) {
channel.postMessage({
target: MESSAGING_APP_TARGET,
data,
})
},
})
prepareInjection(bridge)

bridge.on(CHECK_CONNECTION_EVENT, () => {
bridge.emit(CONNECTED_EVENT)
// force sync to make sure that connect the devtools client
setTimeout(() => {
bridge.emit('syn')
}, 200)

window.addEventListener('beforeunload', () => {
bridge.emit('disconnect')
})
})
}

export function initDevToolsSeparateWindowBridge(channel: BroadcastChannel) {
const bridge = new Bridge({
tracker(fn) {
channel.onmessage = (event) => {
if (event.data.target === MESSAGING_APP_TARGET)
fn(event.data.data)
}
},
trigger(data) {
channel.postMessage({
target: MESSAGING_DEVTOOLS_TARGET,
data,
})
},
})

return bridge
}

// used in devtools client side
export function initDevToolsSeparateWindow(
options: {
onConnected?: (channel: BroadcastChannel) => void
} = {},
) {
const { onConnected = () => {} } = options
let connectionTimer: NodeJS.Timeout | null = null
const channel = new BroadcastChannel(BROADCAST_CHANNEL_NAME)

function connect() {
connectionTimer = setInterval(() => {
channel.postMessage({
target: MESSAGING_DEVTOOLS_TARGET,
data: {
event: CHECK_CONNECTION_EVENT,
},
})
}, 2000)
}

channel.onmessage = (event) => {
if (event.data?.data?.event === CONNECTED_EVENT) {
clearInterval(connectionTimer!)
onConnected(channel)
}
}

connect()
}
35 changes: 2 additions & 33 deletions packages/vite/src/overlay.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import vueDevToolsOptions from 'virtual:vue-devtools-options'
import { Bridge, prepareInjection, setDevToolsClientUrl } from '@vue/devtools-core'
import { BROADCAST_CHANNEL_NAME } from '@vue/devtools-shared'
import { initAppSeparateWindow, setDevToolsClientUrl } from '@vue/devtools-core'
import { addCustomTab, devtools, setDevToolsEnv, toggleComponentInspectorEnabled } from '@vue/devtools-kit'

const overlayDir = `${vueDevToolsOptions.clientHost || ''}${vueDevToolsOptions.base || '/'}@id/virtual:vue-devtools-path:overlay`
Expand Down Expand Up @@ -49,34 +48,4 @@ body.appendChild(script)
// Used in the browser extension
window.__VUE_DEVTOOLS_VITE_PLUGIN_CLIENT_URL__ = `${window.location.origin}${devtoolsClientUrl}`

// @TODO: refactor separate window channel
const channel = new BroadcastChannel(BROADCAST_CHANNEL_NAME)

const bridge = new Bridge({
tracker(fn) {
channel.onmessage = (event) => {
if (event.data.source === '__VUE_DEVTOOLS_CLIENT__')
fn(event.data.data)
}
},
trigger(data) {
channel.postMessage({
source: '__VUE_DEVTOOLS_USER_APP__',
data,
})
},
})

prepareInjection(bridge)

bridge.on('ready', () => {
bridge.emit('__VUE_DEVTOOLS_CREATE_CLIENT__')
// force sync to make sure that connect the devtools client
setTimeout(() => {
bridge.emit('syn')
}, 200)

window.addEventListener('beforeunload', (event) => {
bridge.emit('disconnect')
})
})
initAppSeparateWindow()

0 comments on commit bb57ec2

Please sign in to comment.