Skip to content

Commit 5ec21a8

Browse files
committed
Instanciate one bridge/proxy/backend by iframe
1 parent c170640 commit 5ec21a8

File tree

14 files changed

+261
-168
lines changed

14 files changed

+261
-168
lines changed

shells/chrome/manifest.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
{
3939
"matches": ["<all_urls>"],
4040
"js": ["build/hook.js"],
41-
"run_at": "document_start"
41+
"run_at": "document_start",
42+
"all_frames": true
4243
},
4344
{
4445
"matches": ["<all_urls>"],

shells/chrome/src/backend.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ function handshake (e) {
99
if (e.data.source === 'vue-devtools-proxy' && e.data.payload === 'init') {
1010
window.removeEventListener('message', handshake)
1111

12+
console.log('handshaked!')
1213
let listeners = []
1314
const bridge = new Bridge({
1415
listen (fn) {
@@ -26,7 +27,7 @@ function handshake (e) {
2627
payload: data
2728
}, '*')
2829
}
29-
})
30+
}, document.URL)
3031

3132
bridge.on('shutdown', () => {
3233
listeners.forEach(l => {
@@ -35,6 +36,7 @@ function handshake (e) {
3536
listeners = []
3637
})
3738

39+
console.log('init backend', bridge.frameURL)
3840
initBackend(bridge)
3941
}
4042
}

shells/chrome/src/background.js

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,52 @@
44
const ports = {}
55

66
chrome.runtime.onConnect.addListener(port => {
7-
let tab
7+
let tabId
8+
let frameId, frameURL
89
let name
9-
if (isNumeric(port.name)) {
10-
tab = port.name
10+
let id
11+
if (isNumeric(port.name.split('#')[0])) {
12+
tabId = +port.name.split('#')[0]
13+
frameURL = port.name.split('#')[1]
14+
id = port.name
1115
name = 'devtools'
12-
installProxy(+port.name)
16+
installProxy(tabId, id)
1317
} else {
14-
tab = port.sender.tab.id
18+
tabId = port.sender.tab.id
19+
frameId = port.sender.frameId
20+
frameURL = port.sender.url
21+
id = tabId + '#' + frameURL
22+
console.log('heard of backend for tab#frame ', id)
1523
name = 'backend'
1624
}
1725

18-
if (!ports[tab]) {
19-
ports[tab] = {
26+
if (!ports[id]) {
27+
ports[id] = {
2028
devtools: null,
2129
backend: null
2230
}
2331
}
24-
ports[tab][name] = port
32+
ports[id][name] = port
2533

26-
if (ports[tab].devtools && ports[tab].backend) {
27-
doublePipe(tab, ports[tab].devtools, ports[tab].backend)
34+
if (ports[id].devtools && ports[id].backend) {
35+
doublePipe(id, ports[id].devtools, ports[id].backend)
2836
}
2937
})
3038

3139
function isNumeric (str) {
3240
return +str + '' === str
3341
}
3442

35-
function installProxy (tabId) {
43+
function installProxy(tabId, portId) {
3644
chrome.tabs.executeScript(tabId, {
37-
file: '/build/proxy.js'
45+
file: '/build/proxy.js',
46+
allFrames: true
3847
}, function (res) {
3948
if (!res) {
40-
ports[tabId].devtools.postMessage('proxy-fail')
49+
ports[portId].devtools.postMessage('proxy-fail')
50+
console.log('proxy fails', portId)
4151
} else {
42-
console.log('injected proxy to tab ' + tabId)
52+
console.log('injected proxy to all frames of tab ' + tabId)
4353
}
4454
})
4555
}

shells/chrome/src/devtools-background.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function createPanelIfHasVue () {
1717
chrome.devtools.inspectedWindow.eval(
1818
'!!(window.__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue)',
1919
function (hasVue) {
20-
if (!hasVue || created) {
20+
if (created) { //!hasVue ||
2121
return
2222
}
2323
clearInterval(checkVueInterval)

shells/chrome/src/devtools.js

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,17 @@
11
// this script is called when the VueDevtools panel is activated.
22

3-
import { initDevTools } from 'src/devtools'
3+
import { initDevTools, registerFrame } from 'src/devtools'
44
import Bridge from 'src/bridge'
55

66
initDevTools({
7-
87
/**
98
* Inject backend, connect to background, and send back the bridge.
109
*
1110
* @param {Function} cb
1211
*/
1312

14-
connect (cb) {
15-
// 1. inject backend code into page
16-
injectScript(chrome.runtime.getURL('build/backend.js'), () => {
17-
// 2. connect to background to setup proxy
18-
const port = chrome.runtime.connect({
19-
name: '' + chrome.devtools.inspectedWindow.tabId
20-
})
21-
let disconnected = false
22-
port.onDisconnect.addListener(() => {
23-
disconnected = true
24-
})
25-
26-
const bridge = new Bridge({
27-
listen (fn) {
28-
port.onMessage.addListener(fn)
29-
},
30-
send (data) {
31-
if (!disconnected) {
32-
port.postMessage(data)
33-
}
34-
}
35-
})
36-
// 3. send a proxy API to the panel
37-
cb(bridge)
38-
})
13+
connect(cb) {
14+
cb()
3915
},
4016

4117
/**
@@ -44,20 +20,37 @@ initDevTools({
4420
* @param {Function} reloadFn
4521
*/
4622

47-
onReload (reloadFn) {
23+
onReload(reloadFn) {
4824
chrome.devtools.network.onNavigated.addListener(reloadFn)
4925
}
5026
})
5127

28+
29+
function handleRes (res) {
30+
if (res.type === 'document') {
31+
createPortForSubFrame(res.url)
32+
}
33+
}
34+
35+
// Search for iframes...
36+
// ...on devtool panel load
37+
chrome.devtools.inspectedWindow.getResources(function (res) {
38+
res.map(handleRes)
39+
})
40+
// ...when they are added to the page afterwards
41+
chrome.devtools.inspectedWindow.onResourceAdded.addListener(handleRes)
42+
43+
5244
/**
5345
* Inject a globally evaluated script, in the same context with the actual
5446
* user app.
5547
*
5648
* @param {String} scriptName
49+
* @param {String} [frameURL]
5750
* @param {Function} cb
5851
*/
5952

60-
function injectScript (scriptName, cb) {
53+
function injectScriptInFrame (scriptName, frameURL, cb) {
6154
const src = `
6255
(function() {
6356
var script = document.constructor.prototype.createElement.call(document, 'script');
@@ -66,10 +59,41 @@ function injectScript (scriptName, cb) {
6659
script.parentNode.removeChild(script);
6760
})()
6861
`
69-
chrome.devtools.inspectedWindow.eval(src, function (res, err) {
62+
chrome.devtools.inspectedWindow.eval(src, { frameURL: frameURL }, function (res, err) {
7063
if (err) {
7164
console.log(err)
7265
}
7366
cb()
7467
})
7568
}
69+
70+
function createPortForSubFrame(frameURL) {
71+
console.log('Frame added:', frameURL)
72+
// 1. inject backend code into frame
73+
injectScriptInFrame(chrome.runtime.getURL('build/backend.js'), frameURL, () => {
74+
// 2. connect to background to setup proxy
75+
const port = chrome.runtime.connect({
76+
name: '' + chrome.devtools.inspectedWindow.tabId + '#' + frameURL,
77+
})
78+
let disconnected = false
79+
port.onDisconnect.addListener(() => {
80+
disconnected = true
81+
})
82+
83+
const bridge = new Bridge({
84+
listen(fn) {
85+
port.onMessage.addListener(fn)
86+
},
87+
send(data) {
88+
if (!disconnected) {
89+
port.postMessage(data)
90+
}
91+
}
92+
}, port.name)
93+
// 3. send the new frame along with the proxy API to the panel
94+
registerFrame({
95+
url: frameURL,
96+
bridge: bridge
97+
})
98+
})
99+
}

shells/chrome/src/proxy.js

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,37 @@
33
// to the chrome runtime API. It serves as a proxy between the injected
44
// backend and the Vue devtools panel.
55

6-
const port = chrome.runtime.connect({
7-
name: 'content-script'
8-
})
6+
// Install the proxy only once
7+
if (!window.__VUE_DEVTOOL_PROXY_INSTALLED__) {
8+
window.__VUE_DEVTOOL_PROXY_INSTALLED__ = true
99

10-
port.onMessage.addListener(sendMessageToBackend)
11-
window.addEventListener('message', sendMessageToDevtools)
12-
port.onDisconnect.addListener(handleDisconnect)
10+
const port = chrome.runtime.connect({
11+
name: 'content-script'
12+
})
1313

14-
sendMessageToBackend('init')
14+
port.onMessage.addListener(sendMessageToBackend)
15+
window.addEventListener('message', sendMessageToDevtools)
16+
port.onDisconnect.addListener(handleDisconnect)
1517

16-
function sendMessageToBackend (payload) {
17-
window.postMessage({
18-
source: 'vue-devtools-proxy',
19-
payload: payload
20-
}, '*')
21-
}
18+
console.log('proxy added for frame ', window.location.href)
19+
sendMessageToBackend('init')
2220

23-
function sendMessageToDevtools (e) {
24-
if (e.data && e.data.source === 'vue-devtools-backend') {
25-
port.postMessage(e.data.payload)
21+
function sendMessageToBackend(payload) {
22+
window.postMessage({
23+
source: 'vue-devtools-proxy',
24+
payload: payload
25+
}, '*')
26+
}
27+
28+
function sendMessageToDevtools(e) {
29+
if (e.data && e.data.source === 'vue-devtools-backend') {
30+
port.postMessage(e.data.payload)
31+
}
32+
}
33+
34+
function handleDisconnect() {
35+
window.removeEventListener('message', sendMessageToDevtools)
36+
sendMessageToBackend('shutdown')
2637
}
27-
}
2838

29-
function handleDisconnect () {
30-
window.removeEventListener('message', sendMessageToDevtools)
31-
sendMessageToBackend('shutdown')
3239
}

src/backend/index.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { highlight, unHighlight, getInstanceRect } from './highlighter'
55
import { initVuexBackend } from './vuex'
66
import { initEventsBackend } from './events'
77
import { stringify, classify, camelize } from '../util'
8-
import { getDocumentTarget, setDocumentTarget, getAllTargets } from './target-document'
98
import path from 'path'
109

1110
// Use a custom basename functions instead of the shimed version
@@ -42,6 +41,7 @@ export function initBackend (_bridge) {
4241
}
4342

4443
function connect () {
44+
console.log('connect')
4545
hook.currentTab = 'components'
4646
bridge.on('switch-tab', tab => {
4747
hook.currentTab = tab
@@ -77,13 +77,6 @@ function connect () {
7777
flush()
7878
})
7979

80-
bridge.on('change-target', (id) => {
81-
const target = getAllTargets().find(t => t.id === id)
82-
if (target) {
83-
setDocumentTarget(target.doc)
84-
scan()
85-
}
86-
})
8780
bridge.on('refresh', scan)
8881
bridge.on('enter-instance', id => highlight(instanceMap.get(id)))
8982
bridge.on('leave-instance', unHighlight)
@@ -111,10 +104,11 @@ function connect () {
111104
*/
112105

113106
function scan () {
107+
console.log('scan')
114108
rootInstances.length = 0
115109
let inFragment = false
116110
let currentFragment = null
117-
walk(getDocumentTarget(), function (node) {
111+
walk(document, function (node) {
118112
if (inFragment) {
119113
if (node === currentFragment._fragmentEnd) {
120114
inFragment = false

src/backend/target-document.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ function packTarget (doc) {
3232

3333
export function getAllTargets () {
3434
const targets = [packTarget(document)]
35+
console.log('find targets', findTargetsInElement(targets[0]))
3536
return targets.concat(findTargetsInElement(targets[0]))
3637
}
3738

src/bridge.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { EventEmitter } from 'events'
22

33
export default class Bridge extends EventEmitter {
4-
constructor (wall) {
4+
constructor(wall, portName) {
55
super()
66
// Setting `this` to `self` here to fix an error in the Safari build:
77
// ReferenceError: Cannot access uninitialized variable.
88
// The error might be related to the webkit bug here:
99
// https://bugs.webkit.org/show_bug.cgi?id=171543
1010
const self = this
11+
self.portName = portName
1112
self.setMaxListeners(Infinity)
1213
self.wall = wall
1314
wall.listen(message => {

0 commit comments

Comments
 (0)