@@ -3,7 +3,7 @@ import debugConnection from '../../utils/debugConnection';
3
3
/*
4
4
* background.js
5
5
*
6
- * Runs all the time and serves as a central message hub for panels, contentScript, backend
6
+ * Runs as a service worker serves as a central message hub for panels, contentScript, backend
7
7
*/
8
8
9
9
if ( process . env . NODE_ENV === 'test' ) {
@@ -100,59 +100,27 @@ const installContentScript = tabId => {
100
100
if ( err ) {
101
101
handleInstallError ( tabId , err ) ;
102
102
} else {
103
- chrome . tabs . executeScript ( tabId , { file : '/contentScript .js' } , res => {
103
+ chrome . scripting . executeScript ( { target : { tabId } , files : [ '/backend .js'] } , res => {
104
104
const installError = chrome . runtime . lastError ;
105
105
if ( err || ! res ) handleInstallError ( tabId , installError ) ;
106
106
} ) ;
107
107
}
108
108
} ) ;
109
109
} ;
110
110
111
- function doublePipe ( one , two ) {
112
- if ( ! one . $i ) {
113
- one . $i = Math . random ( ) . toString ( 32 ) . slice ( 2 ) ;
114
- }
115
- if ( ! two . $i ) {
116
- two . $i = Math . random ( ) . toString ( 32 ) . slice ( 2 ) ;
117
- }
118
-
119
- debugConnection ( `BACKGORUND: connect ${ one . name } <-> ${ two . name } [${ one . $i } <-> ${ two . $i } ]` ) ;
120
-
121
- function lOne ( message ) {
122
- debugConnection ( `${ one . name } -> BACKGORUND -> ${ two . name } [${ one . $i } -${ two . $i } ]` , message ) ;
123
- try {
124
- two . postMessage ( message ) ;
125
- } catch ( e ) {
126
- if ( __DEV__ ) console . error ( 'Unexpected disconnect, error' , e ) ; // eslint-disable-line no-console
127
- shutdown ( ) ; // eslint-disable-line no-use-before-define
128
- }
129
- }
130
- function lTwo ( message ) {
131
- debugConnection ( `${ two . name } -> BACKGORUND -> ${ one . name } [${ two . $i } -${ one . $i } ]` , message ) ;
132
- try {
133
- one . postMessage ( message ) ;
134
- } catch ( e ) {
135
- if ( __DEV__ ) console . error ( 'Unexpected disconnect, error' , e ) ; // eslint-disable-line no-console
136
- shutdown ( ) ; // eslint-disable-line no-use-before-define
137
- }
138
- }
139
- one . onMessage . addListener ( lOne ) ;
140
- two . onMessage . addListener ( lTwo ) ;
141
- function shutdown ( ) {
142
- debugConnection ( `SHUTDOWN ${ one . name } <-> ${ two . name } [${ one . $i } <-> ${ two . $i } ]` ) ;
143
- one . onMessage . removeListener ( lOne ) ;
144
- two . onMessage . removeListener ( lTwo ) ;
145
- one . disconnect ( ) ;
146
- two . disconnect ( ) ;
147
- }
148
- one . onDisconnect . addListener ( shutdown ) ;
149
- two . onDisconnect . addListener ( shutdown ) ;
150
- }
151
-
152
111
if ( chrome . contextMenus ) {
153
- // electron doesn't support this api
154
- chrome . contextMenus . onClicked . addListener ( ( _ , contentWindow ) => {
155
- openWindow ( contentWindow . id ) ;
112
+ chrome . contextMenus . onClicked . addListener ( ( info , tab ) => {
113
+ console . log ( 'Context menu clicked' , info , tab ) ;
114
+ if ( info . menuItemId === 'mobx-devtools' ) {
115
+ try {
116
+ console . log ( 'Attempting to open window for tab' , tab . id ) ;
117
+ window . contentTabId = tab . id ;
118
+ installContentScript ( tab . id ) ;
119
+ openWindow ( tab . id ) ;
120
+ } catch ( err ) {
121
+ console . error ( 'Error opening devtools window:' , err ) ;
122
+ }
123
+ }
156
124
} ) ;
157
125
}
158
126
@@ -176,54 +144,57 @@ if (chrome.browserAction) {
176
144
} ) ;
177
145
}
178
146
179
- chrome . runtime . onInstalled . addListener ( ( ) => {
180
- chrome . contextMenus . create ( {
181
- id : 'mobx-devtools' ,
182
- title : 'Open Mobx DevTools' ,
183
- contexts : [ 'all' ] ,
184
- } ) ;
147
+ // Keep service worker alive
148
+ chrome . runtime . onConnect . addListener ( port => {
149
+ console . log ( 'Service worker connected to port:' , port . name ) ;
185
150
} ) ;
186
151
152
+ // Create a long-lived connection for the content script
153
+ let contentScriptPorts = new Map ( ) ;
154
+
187
155
chrome . runtime . onConnect . addListener ( port => {
188
- let tab = null ;
189
- let name = null ;
190
- if ( isNumeric ( port . name ) ) {
191
- tab = port . name ;
192
- name = 'devtools' ;
193
- installContentScript ( + port . name ) ;
194
- } else {
195
- tab = port . sender . tab . id ;
196
- name = 'content-script' ;
197
- }
156
+ if ( port . name === 'content-script' ) {
157
+ const tabId = port . sender . tab . id ;
158
+ contentScriptPorts . set ( tabId , port ) ;
198
159
199
- if ( ! orphansByTabId [ tab ] ) {
200
- orphansByTabId [ tab ] = [ ] ;
160
+ port . onDisconnect . addListener ( ( ) => {
161
+ contentScriptPorts . delete ( tabId ) ;
162
+ } ) ;
201
163
}
164
+ } ) ;
202
165
203
- if ( name === 'content-script' ) {
204
- const orphan = orphansByTabId [ tab ] . find ( t => t . name === 'devtools' ) ;
205
- if ( orphan ) {
206
- doublePipe ( orphan . port , port ) ;
207
- orphansByTabId [ tab ] = orphansByTabId [ tab ] . filter ( t => t !== orphan ) ;
208
- } else {
209
- const newOrphan = { name, port } ;
210
- orphansByTabId [ tab ] . push ( newOrphan ) ;
211
- port . onDisconnect . addListener ( ( ) => {
212
- if ( __DEV__ ) console . warn ( 'orphan devtools disconnected' ) ; // eslint-disable-line no-console
213
- orphansByTabId [ tab ] = orphansByTabId [ tab ] . filter ( t => t !== newOrphan ) ;
166
+ // Handle messages from panel
167
+ chrome . runtime . onMessage . addListener ( ( message , sender , sendResponse ) => {
168
+ if ( message . type === 'panel-to-backend' ) {
169
+ // Use the existing port to send to content script
170
+ const port = contentScriptPorts . get ( message . tabId ) ;
171
+ if ( port ) {
172
+ port . postMessage ( {
173
+ type : 'panel-message' ,
174
+ data : message . data ,
214
175
} ) ;
215
- }
216
- } else if ( name === 'devtools' ) {
217
- const orphan = orphansByTabId [ tab ] . find ( t => t . name === 'content-script' ) ;
218
- if ( orphan ) {
219
- orphansByTabId [ tab ] = orphansByTabId [ tab ] . filter ( t => t !== orphan ) ;
220
176
} else {
221
- const newOrphan = { name, port } ;
222
- orphansByTabId [ tab ] . push ( newOrphan ) ;
223
- port . onDisconnect . addListener ( ( ) => {
224
- if ( __DEV__ ) console . warn ( 'orphan content-script disconnected' ) ; // eslint-disable-line no-console
225
- orphansByTabId [ tab ] = orphansByTabId [ tab ] . filter ( t => t !== newOrphan ) ;
226
- } ) ;
177
+ console . error ( 'No connection to content script for tab:' , message . tabId ) ;
227
178
}
228
179
}
180
+ // Return true to indicate we'll respond asynchronously
181
+ return true ;
182
+ } ) ;
183
+
184
+ // Handle messages from content script to panel
185
+ chrome . runtime . onMessage . addListener ( ( message , sender ) => {
186
+ if ( sender . tab && message . type === 'content-to-panel' ) {
187
+ // Broadcast to all extension pages
188
+ chrome . runtime
189
+ . sendMessage ( {
190
+ tabId : sender . tab . id ,
191
+ data : message . data ,
192
+ } )
193
+ . catch ( err => {
194
+ // Ignore errors about receiving end not existing
195
+ if ( ! err . message . includes ( 'receiving end does not exist' ) ) {
196
+ console . error ( 'Error sending message:' , err ) ;
197
+ }
198
+ } ) ;
199
+ }
229
200
} ) ;
0 commit comments