glass-easel-devtools-extension 0.13.0 → 0.17.2

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.12.1",
5
+ "version": "0.17.2",
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.12.1",
5
+ "version": "0.17.2",
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.13.0",
3
+ "version": "0.17.2",
4
4
  "main": "src/utils.ts",
5
5
  "dependencies": {
6
- "glass-easel": ">=0.13.0",
7
- "glass-easel-devtools-agent": "0.13.0",
8
- "glass-easel-devtools-panel": "0.13.0"
6
+ "glass-easel": ">=0.17.2",
7
+ "glass-easel-devtools-agent": "0.17.2",
8
+ "glass-easel-devtools-panel": "0.17.2"
9
9
  },
10
10
  "devDependencies": {
11
11
  "archiver": "^7.0.1",
@@ -1,7 +1,9 @@
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: '_preinit' | '_init' }
4
+ export type AgentSendMessageMeta =
5
+ | protocol.AgentSendMessage
6
+ | { kind: '_preinit' | '_init' | '_reconnect' }
5
7
 
6
8
  if (window.top !== window) {
7
9
  // for iframes, connect to the top frame
@@ -1,9 +1,11 @@
1
+ /* eslint-disable @typescript-eslint/no-deprecated */
2
+
3
+ import { type protocol } from 'glass-easel-devtools-agent'
1
4
  import { type AgentSendMessageMeta } from '../agent'
2
- import { type PanelSendMessageMeta } from '../panel'
5
+ import type { PanelRecvMessageMeta, PanelSendMessageMeta } from '../panel'
3
6
  import { ConnectionSource } from '../utils'
4
7
 
5
8
  // inject a small user script
6
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
7
9
  const USER_SCRIPT_ID = 'glassEaselDevToolsUser'
8
10
  chrome.scripting
9
11
  .registerContentScripts([
@@ -44,14 +46,21 @@ const injectAgentScript = (tabId: number) => {
44
46
  // states
45
47
  const tabMetaMap = Object.create(null) as Record<
46
48
  number,
47
- {
48
- devTools?: chrome.runtime.Port
49
- pendingMessages: AgentSendMessageMeta[]
50
- }
49
+ | {
50
+ content: chrome.runtime.Port | null
51
+ contentPendingMessages: protocol.AgentRecvMessage[]
52
+ devTools: chrome.runtime.Port | null
53
+ pendingMessages: PanelRecvMessageMeta[]
54
+ }
55
+ | undefined
51
56
  >
52
57
  chrome.runtime.onConnect.addListener((port) => {
53
58
  if (port.name === ConnectionSource.DevToolsPanel) {
54
59
  newDevToolsConnection(port)
60
+ } else if (port.name === ConnectionSource.ContentScript) {
61
+ const tabId = port.sender?.tab?.id
62
+ if (!tabId) return
63
+ newContentScriptConnection(tabId, port)
55
64
  }
56
65
  })
57
66
 
@@ -60,51 +69,79 @@ const newDevToolsConnection = (port: chrome.runtime.Port) => {
60
69
  let tabId = 0
61
70
  port.onMessage.addListener((message: PanelSendMessageMeta) => {
62
71
  if (message.kind === '_init' || message.kind === '_reconnect') {
63
- if (tabId) delete tabMetaMap[tabId]
72
+ if (tabId && tabMetaMap[tabId]) tabMetaMap[tabId]!.devTools = null
64
73
  tabId = message.tabId
65
74
  if (tabMetaMap[tabId]) {
66
- tabMetaMap[tabId].devTools = port
67
- const pendingMessages = tabMetaMap[tabId].pendingMessages
68
- tabMetaMap[tabId].pendingMessages = []
75
+ tabMetaMap[tabId]!.contentPendingMessages.length = 0
76
+ tabMetaMap[tabId]!.devTools = port
77
+ const pendingMessages = tabMetaMap[tabId]!.pendingMessages
78
+ tabMetaMap[tabId]!.pendingMessages = []
69
79
  pendingMessages.forEach((message) => {
70
80
  port.postMessage(message)
71
81
  })
82
+ if (message.kind === '_init') injectContentScript(tabId)
72
83
  } else {
73
- tabMetaMap[tabId] = { devTools: port, pendingMessages: [] }
84
+ tabMetaMap[tabId] = {
85
+ content: null,
86
+ contentPendingMessages: [],
87
+ devTools: port,
88
+ pendingMessages: [],
89
+ }
90
+ injectContentScript(tabId)
74
91
  }
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)
92
+ } else if (tabMetaMap[tabId]) {
93
+ const content = tabMetaMap[tabId]!.content
94
+ if (content) content.postMessage(message)
95
+ else tabMetaMap[tabId]!.contentPendingMessages.push(message as protocol.AgentRecvMessage)
79
96
  }
80
97
  })
81
98
  port.onDisconnect.addListener((_port) => {
82
- if (tabId) delete tabMetaMap[tabId]
99
+ if (tabMetaMap[tabId]) tabMetaMap[tabId]!.devTools = null
83
100
  })
84
101
  }
85
102
 
86
103
  // connections from content script
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
91
- const tabMeta = tabMetaMap[tabId]
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
- })
104
+ const newContentScriptConnection = (tabId: number, port: chrome.runtime.Port) => {
105
+ port.onMessage.addListener((message: AgentSendMessageMeta) => {
106
+ const tabMeta = tabMetaMap[tabId]
107
+ if (message.kind === '_preinit') {
108
+ injectAgentScript(tabId)
109
+ return
110
+ }
111
+ let panelMessage: PanelRecvMessageMeta
112
+ if (message.kind === '_init' || message.kind === '_reconnect') {
113
+ panelMessage = { kind: '_connected' }
114
+ } else {
115
+ panelMessage = message as protocol.AgentSendMessage
116
+ }
117
+ if (!tabMeta) {
118
+ tabMetaMap[tabId] = {
119
+ content: port,
120
+ contentPendingMessages: [],
121
+ devTools: null,
122
+ pendingMessages: [panelMessage],
123
+ }
124
+ return
125
+ }
126
+ if (panelMessage.kind === '_connected') {
127
+ tabMeta.content = port
128
+ const messages = tabMeta.contentPendingMessages
129
+ tabMeta.contentPendingMessages = []
130
+ messages.forEach((message) => {
131
+ port.postMessage(message)
132
+ })
133
+ }
134
+ if (!tabMeta.devTools) {
135
+ if (panelMessage.kind === '_connected') tabMeta.pendingMessages.length = 0
136
+ tabMeta.pendingMessages.push(panelMessage)
137
+ return
138
+ }
139
+ tabMeta.devTools.postMessage(panelMessage)
140
+ })
141
+ port.onDisconnect.addListener(() => {
142
+ if (tabMetaMap[tabId]) tabMetaMap[tabId].content = null
143
+ })
144
+ }
108
145
 
109
146
  // inject agent when reloaded
110
147
  chrome.webNavigation.onDOMContentLoaded.addListener((ev) => {
@@ -1,6 +1,8 @@
1
+ /* eslint-disable @typescript-eslint/no-deprecated */
2
+
1
3
  import { type protocol } from 'glass-easel-devtools-agent'
2
4
  import { type AgentSendMessageMeta } from '../agent'
3
- import { inFirefox } from '../utils'
5
+ import { ConnectionSource, inFirefox } from '../utils'
4
6
 
5
7
  declare function cloneInto<T>(x: T, target: Window): T
6
8
 
@@ -10,41 +12,62 @@ const prepareDataToAgent = <T>(data: T): T => {
10
12
  }
11
13
 
12
14
  // avoid double injection
13
- const existingElements = document.querySelectorAll('glass-easel-devtools')
14
- for (let i = 0; i < existingElements.length; i += 1) {
15
- const hostElement = existingElements[i]
16
- hostElement.parentNode?.removeChild(hostElement)
17
- }
15
+ const existingElement = document.querySelector('glass-easel-devtools')
16
+ if (existingElement) {
17
+ const ev = new CustomEvent('glass-easel-devtools-reconnect', {})
18
+ existingElement.dispatchEvent(ev)
19
+ } else {
20
+ const hostElement = document.createElement('glass-easel-devtools')
21
+ hostElement.addEventListener('glass-easel-devtools-reconnect', () => {
22
+ reconnect()
23
+ })
18
24
 
19
- // create a host node
20
- const hostElement = document.createElement('glass-easel-devtools')
21
- const hostNodeStyle = `
22
- display: none;
23
- position: fixed;
24
- left: 0;
25
- top: 0;
26
- right: 0;
27
- bottom: 0;
28
- `
29
- hostElement.setAttribute('style', hostNodeStyle)
30
- document.documentElement.appendChild(hostElement)
25
+ // host node styles
26
+ const hostNodeStyle = `
27
+ display: none;
28
+ position: fixed;
29
+ left: 0;
30
+ top: 0;
31
+ right: 0;
32
+ bottom: 0;
33
+ `
34
+ hostElement.setAttribute('style', hostNodeStyle)
35
+ document.documentElement.appendChild(hostElement)
31
36
 
32
- // messaging from background to agent
33
- const postToBackground = (msg: AgentSendMessageMeta) => {
34
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
35
- chrome.runtime.sendMessage(msg)
36
- }
37
- chrome.runtime.onMessage.addListener((message: protocol.AgentRecvMessage, sender) => {
38
- if (sender.id !== chrome.runtime.id) return
39
- const ev = new CustomEvent('glass-easel-devtools-agent-recv', {
40
- detail: prepareDataToAgent(message),
37
+ // messaging from background to agent
38
+ let background = chrome.runtime.connect({
39
+ name: ConnectionSource.ContentScript,
41
40
  })
42
- hostElement.dispatchEvent(ev)
43
- })
41
+ const postToBackground = (msg: AgentSendMessageMeta) => {
42
+ try {
43
+ background.postMessage(msg)
44
+ } catch {
45
+ reconnect()
46
+ background.postMessage(msg)
47
+ }
48
+ }
49
+ const bindListener = () => {
50
+ background.onMessage.addListener((message: unknown) => {
51
+ const ev = new CustomEvent('glass-easel-devtools-agent-recv', {
52
+ detail: prepareDataToAgent(message),
53
+ })
54
+ hostElement.dispatchEvent(ev)
55
+ })
56
+ }
57
+ const reconnect = () => {
58
+ background = chrome.runtime.connect({
59
+ name: ConnectionSource.ContentScript,
60
+ })
61
+ bindListener()
62
+ postToBackground({ kind: '_reconnect' })
63
+ }
64
+ bindListener()
65
+ background.onDisconnect.addListener(reconnect)
44
66
 
45
- // messaging from agent to background
46
- hostElement.addEventListener('glass-easel-devtools-agent-send', (ev) => {
47
- const { detail } = ev as CustomEvent<protocol.AgentSendMessage>
48
- postToBackground(detail)
49
- })
50
- postToBackground({ kind: '_preinit' })
67
+ // messaging from agent to background
68
+ hostElement.addEventListener('glass-easel-devtools-agent-send', (ev) => {
69
+ const { detail } = ev as CustomEvent<protocol.AgentSendMessage>
70
+ postToBackground(detail)
71
+ })
72
+ postToBackground({ kind: '_preinit' })
73
+ }
@@ -1,3 +1,5 @@
1
+ /* eslint-disable @typescript-eslint/no-deprecated */
2
+
1
3
  import { inFirefox } from '../utils'
2
4
 
3
5
  chrome.devtools.panels.create(
@@ -1,3 +1,5 @@
1
+ /* eslint-disable @typescript-eslint/no-deprecated */
2
+
1
3
  import * as glassEasel from 'glass-easel'
2
4
  import {
3
5
  startup,
@@ -16,6 +18,7 @@ export type PanelRecvMessageMeta = PanelRecvMessage | { kind: '_connected' }
16
18
  let background = chrome.runtime.connect({
17
19
  name: ConnectionSource.DevToolsPanel,
18
20
  })
21
+ let reconnecting = false
19
22
  const postToBackground = (msg: PanelSendMessageMeta) => {
20
23
  try {
21
24
  background.postMessage(msg)
@@ -27,7 +30,11 @@ const postToBackground = (msg: PanelSendMessageMeta) => {
27
30
  const bindListener = () => {
28
31
  background.onMessage.addListener((message: PanelRecvMessageMeta) => {
29
32
  if (message.kind === '_connected') {
30
- restart()
33
+ if (reconnecting) {
34
+ reconnecting = false
35
+ } else {
36
+ restart()
37
+ }
31
38
  } else {
32
39
  listener?.(message)
33
40
  }
@@ -39,6 +46,7 @@ const reconnect = () => {
39
46
  })
40
47
  bindListener()
41
48
  postToBackground({ kind: '_reconnect', tabId: chrome.devtools.inspectedWindow.tabId })
49
+ reconnecting = true
42
50
  }
43
51
  bindListener()
44
52
  postToBackground({ kind: '_init', tabId: chrome.devtools.inspectedWindow.tabId })
package/src/stub/index.ts CHANGED
@@ -1,5 +1,3 @@
1
- /* eslint-disable class-methods-use-this */
2
-
3
1
  import type * as glassEasel from 'glass-easel'
4
2
  import { type DevTools, type DevToolsBridge, type InspectorDevTools } from '../utils'
5
3
 
package/.eslintignore DELETED
@@ -1,3 +0,0 @@
1
- /node_modules
2
- /dist
3
- /pkg