glass-easel-devtools-extension 0.10.2 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  "description": "DevTools extension for developing glass-easel applications",
3
3
  "manifest_version": 3,
4
4
  "name": "glass-easel DevTools",
5
- "version": "0.10.1",
5
+ "version": "0.12.0",
6
6
  "homepage_url": "https://github.com/wechat-miniprogram/glass-easel-devtools",
7
7
  "icons": {
8
8
  "16": "icons/glass-easel-16.png",
@@ -2,7 +2,7 @@
2
2
  "description": "DevTools extension for developing glass-easel applications",
3
3
  "manifest_version": 3,
4
4
  "name": "glass-easel DevTools",
5
- "version": "0.10.1",
5
+ "version": "0.12.0",
6
6
  "homepage_url": "https://github.com/wechat-miniprogram/glass-easel-devtools",
7
7
  "icons": {
8
8
  "16": "icons/glass-easel-16.png",
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "glass-easel-devtools-extension",
3
- "version": "0.10.2",
3
+ "version": "0.12.1",
4
4
  "main": "src/utils.ts",
5
5
  "dependencies": {
6
- "glass-easel": "^0.10.2",
7
- "glass-easel-devtools-agent": "0.10.2",
8
- "glass-easel-devtools-panel": "0.10.2"
6
+ "glass-easel": ">=0.12.0",
7
+ "glass-easel-devtools-agent": "0.12.1",
8
+ "glass-easel-devtools-panel": "0.12.1"
9
9
  },
10
10
  "devDependencies": {
11
11
  "archiver": "^7.0.1",
@@ -1,7 +1,7 @@
1
1
  import { getDevTools, type protocol } from 'glass-easel-devtools-agent'
2
2
  import { type DevToolsBridge } from '../utils'
3
3
 
4
- export type AgentSendMessageMeta = protocol.AgentSendMessage | { kind: '_init' }
4
+ export type AgentSendMessageMeta = protocol.AgentSendMessage | { kind: '_preinit' | '_init' }
5
5
 
6
6
  if (window.top !== window) {
7
7
  // for iframes, connect to the top frame
@@ -4,16 +4,19 @@ import { ConnectionSource } from '../utils'
4
4
 
5
5
  // inject a small user script
6
6
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
7
- chrome.scripting.registerContentScripts([
8
- {
9
- id: 'glassEaselDevToolsUser',
10
- world: 'MAIN',
11
- matches: ['<all_urls>'],
12
- allFrames: true,
13
- js: ['dist/stub.js'],
14
- runAt: 'document_start',
15
- },
16
- ])
7
+ const USER_SCRIPT_ID = 'glassEaselDevToolsUser'
8
+ chrome.scripting
9
+ .registerContentScripts([
10
+ {
11
+ id: USER_SCRIPT_ID,
12
+ world: 'MAIN',
13
+ matches: ['<all_urls>'],
14
+ allFrames: true,
15
+ js: ['dist/stub.js'],
16
+ runAt: 'document_start',
17
+ },
18
+ ])
19
+ .catch(() => {})
17
20
 
18
21
  // inject main agent when needed
19
22
  const injectContentScript = (tabId: number) => {
@@ -42,15 +45,13 @@ const injectAgentScript = (tabId: number) => {
42
45
  const tabMetaMap = Object.create(null) as Record<
43
46
  number,
44
47
  {
45
- devTools: chrome.runtime.Port
46
- contentScript?: chrome.runtime.Port
48
+ devTools?: chrome.runtime.Port
49
+ pendingMessages: AgentSendMessageMeta[]
47
50
  }
48
51
  >
49
52
  chrome.runtime.onConnect.addListener((port) => {
50
53
  if (port.name === ConnectionSource.DevToolsPanel) {
51
54
  newDevToolsConnection(port)
52
- } else if (port.name === ConnectionSource.ContentScript) {
53
- newContentScriptConnection(port)
54
55
  }
55
56
  })
56
57
 
@@ -58,20 +59,23 @@ chrome.runtime.onConnect.addListener((port) => {
58
59
  const newDevToolsConnection = (port: chrome.runtime.Port) => {
59
60
  let tabId = 0
60
61
  port.onMessage.addListener((message: PanelSendMessageMeta) => {
61
- if (message.kind === '_init') {
62
+ if (message.kind === '_init' || message.kind === '_reconnect') {
62
63
  if (tabId) delete tabMetaMap[tabId]
63
64
  tabId = message.tabId
64
- tabMetaMap[tabId] = { devTools: port }
65
- injectContentScript(tabId)
66
- } else if (message.kind !== '') {
67
- const tabMeta = tabMetaMap[tabId]
68
- if (!tabMeta) return
69
- if (tabMeta.contentScript) {
70
- tabMeta.contentScript.postMessage(message)
65
+ if (tabMetaMap[tabId]) {
66
+ tabMetaMap[tabId].devTools = port
67
+ const pendingMessages = tabMetaMap[tabId].pendingMessages
68
+ tabMetaMap[tabId].pendingMessages = []
69
+ pendingMessages.forEach((message) => {
70
+ port.postMessage(message)
71
+ })
71
72
  } else {
72
- // eslint-disable-next-line no-console
73
- console.warn('Failed to send message to agent since the agent is not connected')
73
+ tabMetaMap[tabId] = { devTools: port, pendingMessages: [] }
74
74
  }
75
+ if (message.kind === '_init') injectContentScript(tabId)
76
+ } else {
77
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
78
+ chrome.tabs.sendMessage(tabId, message)
75
79
  }
76
80
  })
77
81
  port.onDisconnect.addListener((_port) => {
@@ -80,28 +84,27 @@ const newDevToolsConnection = (port: chrome.runtime.Port) => {
80
84
  }
81
85
 
82
86
  // connections from content script
83
- const newContentScriptConnection = (port: chrome.runtime.Port) => {
84
- const tabId = port.sender?.tab?.id
85
- if (tabId === undefined) return
87
+ chrome.runtime.onMessage.addListener((message: AgentSendMessageMeta, sender) => {
88
+ if (sender.id !== chrome.runtime.id) return
89
+ const tabId = sender.tab?.id
90
+ if (!tabId) return
86
91
  const tabMeta = tabMetaMap[tabId]
87
- if (!tabMeta) return
88
- port.onMessage.addListener((message: AgentSendMessageMeta) => {
89
- const tabMeta = tabMetaMap[tabId]
90
- if (!tabMeta) return
91
- if (message.kind === '_init') {
92
- tabMeta.contentScript = port
93
- tabMeta.devTools.postMessage({ kind: '_connected' })
94
- } else {
95
- tabMeta.devTools.postMessage(message)
96
- }
97
- })
98
- port.onDisconnect.addListener((_port) => {
99
- const tabMeta = tabMetaMap[tabId]
100
- if (!tabMeta) return
101
- tabMeta.contentScript = undefined
102
- })
103
- injectAgentScript(tabId)
104
- }
92
+ if (!tabMeta) {
93
+ tabMetaMap[tabId] = { pendingMessages: [message] }
94
+ return
95
+ }
96
+ if (!tabMeta.devTools) {
97
+ tabMeta.pendingMessages.push(message)
98
+ return
99
+ }
100
+ if (message.kind === '_preinit') {
101
+ injectAgentScript(tabId)
102
+ } else if (message.kind === '_init') {
103
+ tabMeta.devTools.postMessage({ kind: '_connected' })
104
+ } else {
105
+ tabMeta.devTools.postMessage(message)
106
+ }
107
+ })
105
108
 
106
109
  // inject agent when reloaded
107
110
  chrome.webNavigation.onDOMContentLoaded.addListener((ev) => {
@@ -1,5 +1,6 @@
1
1
  import { type protocol } from 'glass-easel-devtools-agent'
2
- import { ConnectionSource, inFirefox } from '../utils'
2
+ import { type AgentSendMessageMeta } from '../agent'
3
+ import { inFirefox } from '../utils'
3
4
 
4
5
  declare function cloneInto<T>(x: T, target: Window): T
5
6
 
@@ -29,17 +30,12 @@ hostElement.setAttribute('style', hostNodeStyle)
29
30
  document.documentElement.appendChild(hostElement)
30
31
 
31
32
  // messaging from background to agent
32
- const background = chrome.runtime.connect({
33
- name: ConnectionSource.ContentScript,
34
- })
35
- const sendHeartbeat = () => {
36
- setTimeout(() => {
37
- background.postMessage({ kind: '' })
38
- sendHeartbeat()
39
- }, 15000)
33
+ const postToBackground = (msg: AgentSendMessageMeta) => {
34
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
35
+ chrome.runtime.sendMessage(msg)
40
36
  }
41
- sendHeartbeat()
42
- background.onMessage.addListener((message: protocol.AgentRecvMessage) => {
37
+ chrome.runtime.onMessage.addListener((message: protocol.AgentRecvMessage, sender) => {
38
+ if (sender.id !== chrome.runtime.id) return
43
39
  const ev = new CustomEvent('glass-easel-devtools-agent-recv', {
44
40
  detail: prepareDataToAgent(message),
45
41
  })
@@ -49,5 +45,6 @@ background.onMessage.addListener((message: protocol.AgentRecvMessage) => {
49
45
  // messaging from agent to background
50
46
  hostElement.addEventListener('glass-easel-devtools-agent-send', (ev) => {
51
47
  const { detail } = ev as CustomEvent<protocol.AgentSendMessage>
52
- background.postMessage(detail)
48
+ postToBackground(detail)
53
49
  })
50
+ postToBackground({ kind: '_preinit' })
@@ -7,31 +7,42 @@ import {
7
7
  } from 'glass-easel-devtools-panel'
8
8
  import { ConnectionSource } from '../utils'
9
9
 
10
- export type PanelSendMessageMeta = PanelSendMessage | { kind: '_init'; tabId: number }
10
+ export type PanelSendMessageMeta =
11
+ | PanelSendMessage
12
+ | { kind: '_init' | '_reconnect'; tabId: number }
11
13
  export type PanelRecvMessageMeta = PanelRecvMessage | { kind: '_connected' }
12
14
 
13
15
  // build connection to main service
14
- const background = chrome.runtime.connect({
16
+ let background = chrome.runtime.connect({
15
17
  name: ConnectionSource.DevToolsPanel,
16
18
  })
17
19
  const postToBackground = (msg: PanelSendMessageMeta) => {
18
- background.postMessage(msg)
20
+ try {
21
+ background.postMessage(msg)
22
+ } catch {
23
+ reconnect()
24
+ background.postMessage(msg)
25
+ }
19
26
  }
20
- const sendHeartbeat = () => {
21
- setTimeout(() => {
22
- postToBackground({ kind: '' })
23
- sendHeartbeat()
24
- }, 15000)
27
+ const bindListener = () => {
28
+ background.onMessage.addListener((message: PanelRecvMessageMeta) => {
29
+ if (message.kind === '_connected') {
30
+ restart()
31
+ } else {
32
+ listener?.(message)
33
+ }
34
+ })
25
35
  }
26
- sendHeartbeat()
27
- background.onMessage.addListener((message: PanelRecvMessageMeta) => {
28
- if (message.kind === '_connected') {
29
- restart()
30
- } else {
31
- listener?.(message)
32
- }
33
- })
36
+ const reconnect = () => {
37
+ background = chrome.runtime.connect({
38
+ name: ConnectionSource.DevToolsPanel,
39
+ })
40
+ bindListener()
41
+ postToBackground({ kind: '_reconnect', tabId: chrome.devtools.inspectedWindow.tabId })
42
+ }
43
+ bindListener()
34
44
  postToBackground({ kind: '_init', tabId: chrome.devtools.inspectedWindow.tabId })
45
+ background.onDisconnect.addListener(reconnect)
35
46
 
36
47
  // passing massage through channel
37
48
  let listener: ((data: PanelRecvMessage) => void) | null = null