diff --git a/ElectronNET.Host/api/browserWindows.js b/ElectronNET.Host/api/browserWindows.js index ea42094e..83792339 100644 --- a/ElectronNET.Host/api/browserWindows.js +++ b/ElectronNET.Host/api/browserWindows.js @@ -4,7 +4,7 @@ const path = require('path'); const windows = []; let readyToShowWindowsIds = []; let window, lastOptions, electronSocket; -let mainWindowId; +let mainWindowURL; module.exports = (socket, app) => { electronSocket = socket; socket.on('register-browserWindow-ready-to-show', (id) => { @@ -169,22 +169,16 @@ module.exports = (socket, app) => { else if (!options.webPreferences) { options = { ...options, webPreferences: { nodeIntegration: true } }; } - // lets not recreate the same window if its already open - let nWindow = null; - if (app.commandLine.hasSwitch('watch')) { - app.on('hot-reload', (id) => { - mainWindowId = id; - nWindow = getWindowById(mainWindowId); - if (nWindow) { - nWindow.reload(); - if (loadUrl) { - nWindow.loadURL(loadUrl); - } - return; - } - }); + // we dont want to recreate the window when watch is ready. + if (app.commandLine.hasSwitch('watch') && app['mainWindowURL'] === loadUrl) { + window = app['mainWindow']; + if (window) { + window.reload(); + } + } + else { + window = new electron_1.BrowserWindow(options); } - window = new electron_1.BrowserWindow(options); window.on('ready-to-show', () => { if (readyToShowWindowsIds.includes(window.id)) { readyToShowWindowsIds = readyToShowWindowsIds.filter(value => value !== window.id); @@ -225,10 +219,10 @@ module.exports = (socket, app) => { window.webContents.session.clearCache(); console.log('auto clear-cache active for new window.'); } - // set main window id - if (mainWindowId == undefined) { - mainWindowId = window.id; - app.emit("mainWindow", mainWindowId); + // set main window url + if (app['mainWindowURL'] == undefined || app['mainWindowURL'] == "") { + app['mainWindowURL'] = loadUrl; + app['mainWindow'] = window; } windows.push(window); electronSocket.emit('BrowserWindowCreated', window.id); diff --git a/ElectronNET.Host/api/browserWindows.ts b/ElectronNET.Host/api/browserWindows.ts index 12fda600..fe32b7ae 100644 --- a/ElectronNET.Host/api/browserWindows.ts +++ b/ElectronNET.Host/api/browserWindows.ts @@ -3,8 +3,7 @@ const path = require('path'); const windows: Electron.BrowserWindow[] = []; let readyToShowWindowsIds: number[] = []; let window, lastOptions, electronSocket; -let mainWindowId; - +let mainWindowURL; export = (socket: SocketIO.Socket, app: Electron.App) => { electronSocket = socket; socket.on('register-browserWindow-ready-to-show', (id) => { @@ -200,24 +199,16 @@ export = (socket: SocketIO.Socket, app: Electron.App) => { options = { ...options, webPreferences: { nodeIntegration: true } }; } - // lets not recreate the same window if its already open - let nWindow = null; - - if (app.commandLine.hasSwitch('watch')) { - (app as any).on('hot-reload', (id) => { - mainWindowId = id; - nWindow = getWindowById(mainWindowId); - if (nWindow) { - nWindow.reload(); - if (loadUrl) { - nWindow.loadURL(loadUrl); - } - return; - } - }) + // we dont want to recreate the window when watch is ready. + if (app.commandLine.hasSwitch('watch') && app['mainWindowURL'] === loadUrl) { + window = app['mainWindow']; + if (window) { + window.reload(); + } + } else { + window = new BrowserWindow(options); } - window = new BrowserWindow(options); window.on('ready-to-show', () => { if (readyToShowWindowsIds.includes(window.id)) { readyToShowWindowsIds = readyToShowWindowsIds.filter(value => value !== window.id); @@ -263,10 +254,10 @@ export = (socket: SocketIO.Socket, app: Electron.App) => { console.log('auto clear-cache active for new window.'); } - // set main window id - if (mainWindowId == undefined) { - mainWindowId = window.id; - app.emit("mainWindow", mainWindowId); + // set main window url + if (app['mainWindowURL'] == undefined || app['mainWindowURL'] == "") { + app['mainWindowURL'] = loadUrl; + app['mainWindow'] = window; } windows.push(window); @@ -768,6 +759,7 @@ export = (socket: SocketIO.Socket, app: Electron.App) => { getWindowById(id).setBrowserView(browserView); }); + function getWindowById(id: number): Electron.BrowserWindow { for (let index = 0; index < windows.length; index++) { const element = windows[index]; diff --git a/ElectronNET.Host/main.js b/ElectronNET.Host/main.js index aa976e2e..a399e9a2 100644 --- a/ElectronNET.Host/main.js +++ b/ElectronNET.Host/main.js @@ -4,6 +4,7 @@ const path = require('path'); const cProcess = require('child_process').spawn; const portscanner = require('portscanner'); const imageSize = require('image-size'); +const chalk = require('chalk'); let io, server, browserWindows, ipc, apiProcess, loadURL; let appApi, menu, dialogApi, notification, tray, webContents; let globalShortcut, shellApi, screen, clipboard, autoUpdater; @@ -55,17 +56,12 @@ app.on('ready', () => { // hostname needs to belocalhost, otherwise Windows Firewall will be triggered. portscanner.findAPortNotInUse(8000, 65535, 'localhost', function (error, port) { - console.log('Electron Socket IO Port: ' + port); + console.log(chalk.blue('Electron Socket IO Port: ' + port)); startSocketApiBridge(port); }); }); -app.on("mainWindow", id => { - mainWindowId = id; - console.log(` Main Window ID = ${id}`); -}) - function isSplashScreenEnabled() { if (manifestJsonFile.hasOwnProperty('splashscreen')) { if (manifestJsonFile.splashscreen.hasOwnProperty('imageFile')) { @@ -80,8 +76,8 @@ function startSplashScreen() { let imageFile = path.join(currentBinPath, manifestJsonFile.splashscreen.imageFile); imageSize(imageFile, (error, dimensions) => { if (error) { - console.log(`load splashscreen error:`); - console.log(error); + console.log(chalk.bold.red(`load splashscreen error:`)); + console.log(chalk.bold.red(error)); throw new Error(error.message); } @@ -122,7 +118,7 @@ function startSocketApiBridge(port) { server.listen(port, 'localhost'); server.on('listening', function () { - console.log('Electron Socket started on port %s at %s', server.address().port, server.address().address); + console.log(chalk.bgGreenBright('Electron Socket started on port %s at %s', server.address().port, server.address().address)); // Now that socket connection is established, we can guarantee port will not be open for portscanner if (watchable) { startAspCoreBackendWithWatch(port); @@ -131,15 +127,37 @@ function startSocketApiBridge(port) { } }); + // prototype + app['mainWindowURL'] = ""; + app['mainWindow'] = null; + io.on('connection', (socket) => { + + // we need to remove previously cache instances + // otherwise it will fire the same event multiple depends how many time + // live reload watch happen. + socket.on('disconnect', function () { + console.log(chalk.bold.red('Got disconnect!')); + delete require.cache[require.resolve('./api/app')]; + delete require.cache[require.resolve('./api/browserWindows')]; + delete require.cache[require.resolve('./api/commandLine')]; + delete require.cache[require.resolve('./api/autoUpdater')]; + delete require.cache[require.resolve('./api/ipc')]; + delete require.cache[require.resolve('./api/menu')]; + delete require.cache[require.resolve('./api/dialog')]; + delete require.cache[require.resolve('./api/notification')]; + delete require.cache[require.resolve('./api/tray')]; + delete require.cache[require.resolve('./api/webContents')]; + delete require.cache[require.resolve('./api/globalShortcut')]; + delete require.cache[require.resolve('./api/shell')]; + delete require.cache[require.resolve('./api/screen')]; + delete require.cache[require.resolve('./api/clipboard')]; + delete require.cache[require.resolve('./api/browserView')]; + }); + global['electronsocket'] = socket; global['electronsocket'].setMaxListeners(0); - console.log('ASP.NET Core Application connected...', 'global.electronsocket', global['electronsocket'].id, new Date()); - - // send signal to reload - if (mainWindowId != undefined) { - app.emit("hot-reload", mainWindowId); - } + console.log(chalk.bold.bgCyan('ASP.NET Core Application connected...', 'global.electronsocket', global['electronsocket'].id, new Date())); appApi = require('./api/app')(socket, app); browserWindows = require('./api/browserWindows')(socket, app); @@ -157,6 +175,8 @@ function startSocketApiBridge(port) { clipboard = require('./api/clipboard')(socket); browserView = require('./api/browserView')(socket); + + try { const hostHookScriptFilePath = path.join(__dirname, 'ElectronHostHook', 'index.js'); @@ -166,7 +186,7 @@ function startSocketApiBridge(port) { hostHook.onHostReady(); } } catch (error) { - console.log(error.message); + console.log(chalk.bold.red(error.message)); } }); } @@ -225,7 +245,6 @@ function startAspCoreBackendWithWatch(electronPort) { loadURL = `http://localhost:${aspCoreBackendPort}`; const parameters = ['watch', 'run', `/electronPort=${electronPort}`, `/electronWebPort=${aspCoreBackendPort}`]; - console.log(currentBinPath); var options = { cwd: currentBinPath, env: process.env, @@ -233,7 +252,7 @@ function startAspCoreBackendWithWatch(electronPort) { apiProcess = cProcess('dotnet', parameters, options); apiProcess.stdout.on('data', (data) => { - console.log(`stdout: ${data.toString()}`); + console.log(chalk.bold.blue(`${data.toString()}`)); }); } } \ No newline at end of file diff --git a/ElectronNET.Host/package-lock.json b/ElectronNET.Host/package-lock.json index 76727cb7..d29731f5 100644 --- a/ElectronNET.Host/package-lock.json +++ b/ElectronNET.Host/package-lock.json @@ -28,6 +28,64 @@ "@babel/helper-validator-identifier": "^7.9.0", "chalk": "^2.0.0", "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@electron/get": { @@ -62,6 +120,11 @@ "defer-to-connect": "^1.0.1" } }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, "@types/node": { "version": "10.17.20", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.20.tgz", @@ -107,12 +170,12 @@ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "requires": { - "color-convert": "^1.9.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, "argparse": { @@ -257,22 +320,12 @@ "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - } + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "clone-response": { @@ -285,19 +338,17 @@ } }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "commander": { "version": "2.20.3", @@ -380,6 +431,14 @@ "ms": "^2.1.1" } }, + "decache": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/decache/-/decache-4.5.1.tgz", + "integrity": "sha512-5J37nATc6FmOTLbcsr9qx7Nm28qQyg1SK4xyEHqM0IBkNhWFp0Sm+vKoWYHD8wq+OUEb9jLyaKFfzzd1A9hcoA==", + "requires": { + "callsite": "^1.0.0" + } + }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -706,10 +765,9 @@ "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "http-cache-semantics": { "version": "4.1.0", @@ -1238,12 +1296,11 @@ } }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } }, "to-array": { @@ -1293,11 +1350,67 @@ "tsutils": "^2.29.0" }, "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, diff --git a/ElectronNET.Host/package.json b/ElectronNET.Host/package.json index afb0e805..6c1d95bf 100644 --- a/ElectronNET.Host/package.json +++ b/ElectronNET.Host/package.json @@ -12,6 +12,7 @@ "start": "tsc -p ." }, "dependencies": { + "chalk": "^4.0.0", "dasherize": "^2.0.0", "electron-updater": "^4.2.5", "image-size": "^0.7.4", diff --git a/ElectronNET.WebApp/Controllers/MenusController.cs b/ElectronNET.WebApp/Controllers/MenusController.cs index 4e9d8ec0..09f0b895 100644 --- a/ElectronNET.WebApp/Controllers/MenusController.cs +++ b/ElectronNET.WebApp/Controllers/MenusController.cs @@ -112,7 +112,9 @@ private void CreateContextMenu() new MenuItem { Label = "Electron.NET", Type = MenuType.checkbox, Checked = true } }; - var mainWindow = Electron.WindowManager.BrowserWindows.First(); + var mainWindow = Electron.WindowManager.BrowserWindows.FirstOrDefault(); + if (mainWindow == null) return; + Electron.Menu.SetContextMenu(mainWindow, menu); Electron.IpcMain.On("show-context-menu", (args) =>