@lynker-desktop/electron-window-manager 0.0.4-alpha.8 → 0.0.5-alpha.0

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.
package/main/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const _ = require('lodash');
1
+ const lodash = require('lodash');
2
2
  const electron = require('electron');
3
3
  const remote = require('@electron/remote/main');
4
4
  const eIpc = require('@lynker-desktop/electron-ipc/main');
@@ -16,6 +16,18 @@ function _interopNamespaceDefault(e) {
16
16
 
17
17
  const remote__namespace = /*#__PURE__*/_interopNamespaceDefault(remote);
18
18
 
19
+ const getCustomSession = (() => {
20
+ let customSession;
21
+ return () => {
22
+ if (!customSession) {
23
+ customSession = electron.session.fromPartition('persist:__global_main_session__');
24
+ }
25
+ return customSession;
26
+ };
27
+ })();
28
+ electron.app.on('ready', () => {
29
+ getCustomSession();
30
+ });
19
31
  if (!remote__namespace.isInitialized()) {
20
32
  remote__namespace.initialize();
21
33
  }
@@ -23,50 +35,162 @@ const enable = (win) => {
23
35
  remote__namespace.enable(win);
24
36
  };
25
37
  class WindowsManager {
26
- constructor(preload) {
38
+ constructor(preload, loadingViewUrl, errorViewUrl) {
27
39
  this.preload = preload;
28
40
  this.windows = new Map();
41
+ this.loadingViewUrl = `${loadingViewUrl ?? ''}`;
42
+ this.errorViewUrl = `${errorViewUrl ?? ''}`;
29
43
  }
30
44
  create(options) {
31
- const { name = 'anonymous', loadingView, browserWindow: browserWindowOptions = {}, openDevTools = false, preventOriginClose = false, } = options;
32
- const window = new electron.BrowserWindow(_.merge({
33
- acceptFirstMouse: true,
34
- }, browserWindowOptions, {
35
- webPreferences: {
36
- plugins: true,
37
- nodeIntegration: true,
38
- contextIsolation: false,
39
- backgroundThrottling: false,
40
- nativeWindowOpen: false,
41
- webSecurity: false,
42
- preload: browserWindowOptions?.webPreferences?.preload || this.preload,
45
+ let window;
46
+ try {
47
+ const { type = 'BW', name = 'anonymous', url, loadingView = { url: undefined }, errorView = { url: undefined }, browserWindow: browserWindowOptions, openDevTools = false, preventOriginClose = false, } = options;
48
+ options.type = type;
49
+ try {
50
+ loadingView.url = `${loadingView?.url ?? this.loadingViewUrl}`;
51
+ lodash.merge(options, {
52
+ loadingView,
53
+ });
43
54
  }
44
- }));
45
- remote__namespace.enable(window.webContents);
46
- window._name = name;
47
- if (loadingView?.url) {
48
- this._setLoadingView(window, options);
49
- }
50
- window.on('close', (event) => {
51
- if (preventOriginClose) {
52
- event.preventDefault();
53
- return;
55
+ catch (error) {
56
+ log('error', 'loadingView error:', loadingView, this.loadingViewUrl);
54
57
  }
55
- this.windows.delete(window.id);
56
- });
57
- window.webContents.on('dom-ready', () => {
58
- if (openDevTools) {
59
- window.webContents.openDevTools();
58
+ try {
59
+ errorView.url = `${errorView?.url ?? this.errorViewUrl}`;
60
+ lodash.merge(options, {
61
+ errorView,
62
+ });
60
63
  }
61
- });
62
- this.windows.set(window.id, window);
63
- if (/^file/gi.test(options.url)) {
64
- window.loadFile(options.url);
64
+ catch (error) {
65
+ log('error', 'errorView error:', errorView, this.errorViewUrl);
66
+ }
67
+ let parentWin = undefined;
68
+ if (typeof browserWindowOptions?.parent === 'number') {
69
+ parentWin = electron.BrowserWindow.fromId(browserWindowOptions?.parent) || undefined;
70
+ if (parentWin) {
71
+ browserWindowOptions.parent = parentWin;
72
+ }
73
+ else {
74
+ browserWindowOptions.parent = undefined;
75
+ }
76
+ }
77
+ log('log', 'create 1: ', options);
78
+ log('log', 'create 2: ', `parentWin: ${parentWin?.id}`);
79
+ window = type === 'BV' ?
80
+ new electron.BrowserView(lodash.merge((browserWindowOptions || {}), {
81
+ parent: undefined,
82
+ webPreferences: {
83
+ // session: getCustomSession(),
84
+ plugins: true,
85
+ nodeIntegration: true,
86
+ contextIsolation: false,
87
+ backgroundThrottling: false,
88
+ nativeWindowOpen: false,
89
+ webSecurity: false,
90
+ preload: browserWindowOptions?.webPreferences?.preload || this.preload,
91
+ }
92
+ }))
93
+ : new electron.BrowserWindow(lodash.merge({
94
+ acceptFirstMouse: true,
95
+ }, (browserWindowOptions || {}), {
96
+ parent: parentWin,
97
+ webPreferences: {
98
+ // session: getCustomSession(),
99
+ plugins: true,
100
+ nodeIntegration: true,
101
+ contextIsolation: false,
102
+ backgroundThrottling: false,
103
+ nativeWindowOpen: false,
104
+ webSecurity: false,
105
+ preload: browserWindowOptions?.webPreferences?.preload || this.preload,
106
+ }
107
+ }));
108
+ try {
109
+ remote__namespace.enable(window.webContents);
110
+ }
111
+ catch (error) {
112
+ log('error', 'enable: ', error);
113
+ }
114
+ // @ts-ignore
115
+ try {
116
+ window.id = Number(`${window.id || window.webContents.id}`);
117
+ }
118
+ catch (error) {
119
+ // log('error', 'set id: ', error)
120
+ }
121
+ // @ts-ignore
122
+ try {
123
+ window._id = Number(`${window.id || window.webContents.id}`);
124
+ }
125
+ catch (error) {
126
+ // log('error', 'set id: ', error)
127
+ }
128
+ window._type = type;
129
+ window._name = name;
130
+ window._extraData = `${options?.extraData || ''}`;
131
+ log('log', 'create 5: ', window.id, window._id, window._name);
132
+ if (loadingView?.url) {
133
+ if (type === 'BW') {
134
+ // @ts-ignore
135
+ this._setLoadingView(window, options);
136
+ }
137
+ }
138
+ if (errorView?.url) {
139
+ const showErrorView = lodash.debounce(() => {
140
+ const _url = window?.webContents?.getURL?.() || url;
141
+ /**
142
+ * 判断是否是错误视图
143
+ */
144
+ const isErrorView = `${_url}`.toUpperCase().startsWith(`${errorView?.url}`.toUpperCase());
145
+ if (!isErrorView && _url) {
146
+ // @ts-ignore
147
+ window.loadURL ? window.loadURL(`${errorView?.url}`) : window.webContents.loadURL(`${errorView?.url}`);
148
+ window.webContents.executeJavaScript(`
149
+ var key = '__ELECTRON_WINDOW_MANAGER_DID_FAIL_LOAD_URL__';
150
+ window[key] = "${_url}";
151
+ sessionStorage.setItem(key, "${_url}");
152
+ `);
153
+ }
154
+ }, 300);
155
+ window.webContents.on('did-fail-load', () => {
156
+ showErrorView();
157
+ });
158
+ window.webContents.on('did-start-loading', () => {
159
+ showErrorView.cancel();
160
+ });
161
+ }
162
+ window.webContents.on('close', () => {
163
+ this.windows.delete(window.id || window._id);
164
+ });
165
+ window.webContents.on('destroyed', () => {
166
+ this.windows.delete(window.id || window._id);
167
+ });
168
+ window.webContents.on('dom-ready', () => {
169
+ if (openDevTools) {
170
+ window.webContents.openDevTools();
171
+ }
172
+ });
173
+ if (type === 'BW') {
174
+ // @ts-ignore
175
+ window.on('closed', () => {
176
+ log('log', 'closed', window.id, window._name);
177
+ this.windows.delete(window.id || window._id);
178
+ });
179
+ }
180
+ if (type === 'BV') {
181
+ parentWin?.addBrowserView(window);
182
+ log('log', 'create - addBrowserView');
183
+ }
184
+ // @ts-ignore
185
+ window.loadURL ? window.loadURL(options.url) : window.webContents.loadURL(options.url);
186
+ // @ts-ignore
187
+ window.focus ? window.focus() : window.webContents.focus();
188
+ this.windows.set(window.id || window._id || window.webContents.id, window);
189
+ log('log', 'create', this.windows.keys());
65
190
  }
66
- else {
67
- window.loadURL(options.url);
191
+ catch (error) {
192
+ log('error', 'create', error);
68
193
  }
69
- window.focus();
70
194
  return window;
71
195
  }
72
196
  _setLoadingView(window, createOptions) {
@@ -74,6 +198,7 @@ class WindowsManager {
74
198
  const { loadingView, preventOriginNavigate = false, } = createOptions;
75
199
  let _loadingView = new electron.BrowserView({
76
200
  webPreferences: {
201
+ // session: getCustomSession(),
77
202
  contextIsolation: false,
78
203
  nodeIntegration: true,
79
204
  // 允许loadURL与文件路径在开发环境
@@ -92,9 +217,10 @@ class WindowsManager {
92
217
  width: viewWidth || 10,
93
218
  height: viewHeight || 10,
94
219
  });
220
+ log('log', 'loadLoadingView', window._name);
95
221
  _loadingView.webContents.loadURL(loadingView?.url || '');
96
222
  };
97
- const onFailure = () => {
223
+ const onFailure = lodash.debounce(() => {
98
224
  if (_loadingView.webContents && !_loadingView.webContents.isDestroyed()) {
99
225
  _loadingView.webContents.close();
100
226
  }
@@ -104,9 +230,9 @@ class WindowsManager {
104
230
  if (window) {
105
231
  window.removeBrowserView(_loadingView);
106
232
  }
107
- };
233
+ }, 300);
108
234
  loadLoadingView();
109
- window.on('resize', _.debounce(() => {
235
+ window.on('resize', lodash.debounce(() => {
110
236
  if (_loadingView.webContents && !_loadingView.webContents.isDestroyed()) {
111
237
  if (window.isDestroyed()) {
112
238
  return;
@@ -136,61 +262,134 @@ class WindowsManager {
136
262
  window.webContents.on('crashed', onFailure);
137
263
  window.webContents.on('unresponsive', onFailure);
138
264
  window.webContents.on('did-fail-load', onFailure);
265
+ window.webContents.on('did-finish-load', onFailure);
266
+ window.webContents.on('did-stop-loading', onFailure);
139
267
  }
140
268
  }
141
- get(name) {
142
- let win = undefined;
143
- this.windows.forEach((i) => {
144
- if (i._name === name) {
145
- win = i;
269
+ get(idOrName) {
270
+ log('log', 'get', idOrName);
271
+ let win;
272
+ this.windows.forEach((i, key) => {
273
+ try {
274
+ if (!(i && i?.webContents?.isDestroyed && !i?.webContents?.isDestroyed?.())) {
275
+ this.windows.delete(key);
276
+ }
277
+ }
278
+ catch (error) {
279
+ log('error', 'get');
280
+ }
281
+ if (typeof idOrName === 'number') {
282
+ if (i?.id === idOrName || i?._id === idOrName) {
283
+ win = i;
284
+ }
285
+ }
286
+ else if (typeof idOrName === 'string') {
287
+ if (i?._name === idOrName) {
288
+ win = i;
289
+ }
146
290
  }
147
291
  });
148
- return win;
292
+ // @ts-ignore
293
+ if (win && win?.webContents?.isDestroyed && !win?.webContents?.isDestroyed?.()) {
294
+ return win;
295
+ }
296
+ return undefined;
149
297
  }
150
- getById(id) {
151
- let win = undefined;
152
- this.windows.forEach((i) => {
153
- if (i.id === id) {
154
- win = i;
298
+ getAll(type) {
299
+ log('log', 'getAll');
300
+ const bwWindows = new Map();
301
+ const bvWindows = new Map();
302
+ this.windows.forEach((win, key) => {
303
+ log('log', 'getAll', key, win, win?.webContents?.isDestroyed, win?.webContents?.isDestroyed?.());
304
+ if (!(win && win?.webContents?.isDestroyed && !win?.webContents?.isDestroyed?.())) {
305
+ this.windows.delete(key);
306
+ }
307
+ if (win?._type === 'BW') {
308
+ bwWindows.set(key, win);
309
+ }
310
+ if (win?._type === 'BV') {
311
+ bvWindows.set(key, win);
155
312
  }
156
313
  });
157
- return win;
158
- }
159
- getAll() {
314
+ if (type === 'BW') {
315
+ return bwWindows;
316
+ }
317
+ if (type === 'BV') {
318
+ return bvWindows;
319
+ }
160
320
  return this.windows;
161
321
  }
162
- close(name) {
322
+ close(idOrName) {
323
+ log('log', 'close', idOrName);
163
324
  let win = undefined;
164
325
  this.windows.forEach((i) => {
165
- if (i._name === name) {
166
- win = i;
326
+ if (typeof idOrName === 'number') {
327
+ if (i?.id === idOrName || i?._id === idOrName) {
328
+ win = i;
329
+ }
330
+ }
331
+ else if (typeof idOrName === 'string') {
332
+ if (i?._name === idOrName) {
333
+ win = i;
334
+ }
167
335
  }
168
336
  });
169
337
  // @ts-ignore
170
338
  win && this.windows.delete(win?.id);
171
339
  // @ts-ignore
172
- return win && win?.destroy();
340
+ if (win) {
341
+ // @ts-ignore
342
+ if (win._type === 'BV') {
343
+ this.windows.forEach(i => {
344
+ if (i?._type === 'BW') {
345
+ const _win = i;
346
+ _win.removeBrowserView(win);
347
+ }
348
+ });
349
+ }
350
+ // @ts-ignore
351
+ win?.webContent?.close?.();
352
+ // @ts-ignore
353
+ win?.close?.();
354
+ // @ts-ignore
355
+ win?.destroy?.();
356
+ }
357
+ return true;
173
358
  }
174
- closeById(id) {
175
- let win = undefined;
176
- this.windows.forEach((i) => {
177
- if (i.id === id) {
178
- win = i;
359
+ closeAll() {
360
+ log('log', 'closeAll');
361
+ this.windows.forEach((win) => {
362
+ try {
363
+ win && this.windows.delete(win?.id);
364
+ // @ts-ignore
365
+ if (win._type === 'BV') {
366
+ this.windows.forEach(i => {
367
+ if (i?._type === 'BW') {
368
+ const _win = i;
369
+ _win.removeBrowserView(win);
370
+ }
371
+ });
372
+ }
373
+ // @ts-ignore
374
+ win?.webContent?.close?.();
375
+ // @ts-ignore
376
+ win?.close?.();
377
+ // @ts-ignore
378
+ win?.destroy?.();
379
+ }
380
+ catch (error) {
179
381
  }
180
382
  });
181
- // @ts-ignore
182
- win && this.windows.delete(win?.id);
183
- // @ts-ignore
184
- return win && win?.destroy();
185
383
  }
186
384
  getPreload() {
385
+ log('log', 'getPreload');
187
386
  return this.preload;
188
387
  }
189
388
  }
190
389
  // @ts-ignore
191
390
  global['__ELECTRON_WINDOWS_MANAGER__'] = undefined;
192
391
  exports.isInitialized = false;
193
- const initialize = (preload) => {
392
+ const initialize = (preload, loadingViewUrl, errorViewUrl) => {
194
393
  // @ts-ignore
195
394
  if (exports.isInitialized && global['__ELECTRON_WINDOWS_MANAGER__']) {
196
395
  // @ts-ignore
@@ -198,38 +397,45 @@ const initialize = (preload) => {
198
397
  }
199
398
  exports.isInitialized = true;
200
399
  // @ts-ignore
201
- const wm = global['__ELECTRON_WINDOWS_MANAGER__'] = new WindowsManager(preload);
400
+ const wm = global['__ELECTRON_WINDOWS_MANAGER__'] = new WindowsManager(preload, loadingViewUrl, errorViewUrl);
202
401
  eIpc.mainIPC.handleRenderer('__ELECTRON_WINDOW_MANAGER_IPC_CHANNEL__', async (data) => {
203
402
  if (data?.type === 'create') {
204
403
  const opt = data;
205
404
  const findWin = wm.get(opt.data.name);
206
405
  if (findWin) {
207
- findWin.focus();
406
+ // @ts-ignore
407
+ findWin?.focus?.();
408
+ findWin?.webContents.focus?.();
409
+ if (opt.data.url && findWin.webContents.getURL() !== opt.data.url) {
410
+ findWin.webContents.loadURL(opt.data.url);
411
+ /** fix: url hash 无法正常加载 */
412
+ setTimeout(() => {
413
+ findWin.webContents.reload();
414
+ }, 100);
415
+ }
208
416
  return {
209
- winId: findWin?.id,
210
- winName: findWin?._name,
417
+ winId: Number(`${findWin?.id || findWin?._id || -1}`),
418
+ winName: `${findWin?._name || ''}`,
419
+ winType: `${findWin?._type || ''}`,
420
+ winExtraData: `${findWin?._extraData || ''}`,
211
421
  };
212
422
  }
213
423
  const res = wm.create(opt.data);
214
424
  return {
215
- winId: Number(res.id),
216
- winName: res._name,
425
+ winId: Number(`${res.id || res._id || -1}`),
426
+ winName: `${res?._name || ''}`,
427
+ winType: `${res?._type || ''}`,
428
+ winExtraData: `${res?._extraData || ''}`,
217
429
  };
218
430
  }
219
431
  if (data?.type === 'get') {
220
432
  const opt = data;
221
433
  const res = wm.get(opt?.data);
222
434
  return {
223
- winId: res?.id ? Number(res?.id) : -1,
224
- winName: res?._name ? res?._name : '',
225
- };
226
- }
227
- if (data?.type === 'getById') {
228
- const opt = data;
229
- const res = wm.getById(opt?.data);
230
- return {
231
- winId: res?.id ? Number(res?.id) : -1,
232
- winName: res?._name ? res?._name : '',
435
+ winId: Number(`${res?.id || res?._id || -1}`),
436
+ winName: `${res?._name || ''}`,
437
+ winType: `${res?._type || ''}`,
438
+ winExtraData: `${res?._extraData || ''}`,
233
439
  };
234
440
  }
235
441
  if (data?.type === 'getAll') {
@@ -237,9 +443,11 @@ const initialize = (preload) => {
237
443
  const obj = {};
238
444
  res.forEach(i => {
239
445
  // @ts-ignore
240
- obj[i.id] = {
241
- winId: i?.id ? Number(i?.id) : -1,
242
- winName: i?._name ? i?._name : '',
446
+ obj[i.id || i._id] = {
447
+ winId: Number(`${i?.id || i?._id || -1}`),
448
+ winName: `${i?._name || ''}`,
449
+ winType: `${i?._type || ''}`,
450
+ winExtraData: `${i?._extraData || ''}`,
243
451
  };
244
452
  });
245
453
  return obj;
@@ -249,11 +457,37 @@ const initialize = (preload) => {
249
457
  const res = wm.close(opt?.data);
250
458
  return res;
251
459
  }
252
- if (data?.type === 'closeById') {
253
- const opt = data;
254
- const res = wm.closeById(opt?.data);
460
+ if (data?.type === 'closeAll') {
461
+ const res = wm.closeAll();
255
462
  return res;
256
463
  }
464
+ if (data?.type === 'getWindowForWebContentId') {
465
+ const opt = data;
466
+ const targetWebContents = electron.webContents.fromId(opt.data);
467
+ if (targetWebContents) {
468
+ let win = electron.BrowserWindow.fromWebContents(targetWebContents);
469
+ if (!win) {
470
+ // 获取所有的 BrowserWindows
471
+ let allWindows = electron.BrowserWindow.getAllWindows();
472
+ // 遍历所有窗口,检查每个窗口的 BrowserView
473
+ for (let _win of allWindows) {
474
+ let views = _win.getBrowserViews();
475
+ // 遍历窗口的所有 BrowserView
476
+ for (let view of views) {
477
+ if (view.webContents === targetWebContents) {
478
+ win = _win;
479
+ break;
480
+ }
481
+ }
482
+ if (win)
483
+ break;
484
+ }
485
+ }
486
+ // @ts-ignore
487
+ return win?.id || win?._id;
488
+ }
489
+ return undefined;
490
+ }
257
491
  if (data?.type === 'getPreload') {
258
492
  const res = wm.getPreload();
259
493
  return res;
@@ -262,8 +496,18 @@ const initialize = (preload) => {
262
496
  });
263
497
  return wm;
264
498
  };
499
+ const log = (type, ...data) => {
500
+ const key = `[electron-window-manager]: `;
501
+ try {
502
+ console[type](key, ...data);
503
+ }
504
+ catch (error) {
505
+ console.error(key, error);
506
+ }
507
+ };
265
508
 
266
509
  exports.WindowsManager = WindowsManager;
267
510
  exports.enable = enable;
511
+ exports.getCustomSession = getCustomSession;
268
512
  exports.initialize = initialize;
269
513
  //# sourceMappingURL=index.js.map