From 0328ac317570e5d4b7ec1be268590d6b22bda652 Mon Sep 17 00:00:00 2001 From: GarboMuffin Date: Thu, 29 Jun 2023 23:05:14 -0500 Subject: [PATCH 1/2] Electron preload scaffolding --- src/packager/electron-preload.js | 7 +++++++ src/packager/packager.js | 4 ++++ 2 files changed, 11 insertions(+) create mode 100644 src/packager/electron-preload.js diff --git a/src/packager/electron-preload.js b/src/packager/electron-preload.js new file mode 100644 index 00000000..1afbbb2c --- /dev/null +++ b/src/packager/electron-preload.js @@ -0,0 +1,7 @@ +const {contextBridge} = require('electron') + +contextBridge.exposeInMainWorld('ExampleAPI', { + doSomething: () => { + return 'Hello!'; + } +}); diff --git a/src/packager/packager.js b/src/packager/packager.js index 85a88195..7ef615ea 100644 --- a/src/packager/packager.js +++ b/src/packager/packager.js @@ -11,6 +11,7 @@ import {APP_NAME, WEBSITE, COPYRIGHT_NOTICE, ACCENT_COLOR} from './brand'; import {OutdatedPackagerError} from '../common/errors'; import {darken} from './colors'; import {Adapter} from './adapter'; +import electronPreloadJS from '!raw-loader!./electron-preload.js'; const PROGRESS_LOADED_SCRIPTS = 0.1; @@ -512,6 +513,7 @@ cd "$(dirname "$0")" const contentsPrefix = isMac ? `${rootPrefix}${packageName}.app/Contents/` : rootPrefix; const resourcesPrefix = isMac ? `${contentsPrefix}Resources/app/` : `${contentsPrefix}resources/app/`; const electronMainName = 'electron-main.js'; + const electronPreloadName = 'electron-preload.js'; const iconName = 'icon.png'; const icon = await Adapter.getAppIcon(this.options.app.icon); @@ -558,6 +560,7 @@ const createWindow = (windowOptions) => { sandbox: true, contextIsolation: true, nodeIntegration: false, + preload: path.resolve(__dirname, ${JSON.stringify(electronPreloadName)}), }, show: true, width: 480, @@ -697,6 +700,7 @@ app.whenReady().then(() => { }); `; zip.file(`${resourcesPrefix}${electronMainName}`, mainJS); + zip.file(`${resourcesPrefix}${electronPreloadName}`, electronPreloadJS); for (const [path, data] of Object.entries(projectZip.files)) { setFileFast(zip, `${resourcesPrefix}${path}`, data); From 70154772e2d1cf12d5c2438bf2234836ab0f75b6 Mon Sep 17 00:00:00 2001 From: GarboMuffin Date: Sat, 1 Jul 2023 00:18:33 -0500 Subject: [PATCH 2/2] Actually expose some methods --- src/packager/electron-preload.js | 7 --- src/packager/electron-superpowers.js | 80 ++++++++++++++++++++++++++++ src/packager/packager.js | 14 +++-- 3 files changed, 89 insertions(+), 12 deletions(-) delete mode 100644 src/packager/electron-preload.js create mode 100644 src/packager/electron-superpowers.js diff --git a/src/packager/electron-preload.js b/src/packager/electron-preload.js deleted file mode 100644 index 1afbbb2c..00000000 --- a/src/packager/electron-preload.js +++ /dev/null @@ -1,7 +0,0 @@ -const {contextBridge} = require('electron') - -contextBridge.exposeInMainWorld('ExampleAPI', { - doSomething: () => { - return 'Hello!'; - } -}); diff --git a/src/packager/electron-superpowers.js b/src/packager/electron-superpowers.js new file mode 100644 index 00000000..6578ade2 --- /dev/null +++ b/src/packager/electron-superpowers.js @@ -0,0 +1,80 @@ +const exposeBrowserWindowMethods = [ + // https://www.electronjs.org/docs/latest/api/browser-window + 'focus', + 'blur', + 'isFocused', + 'show', + 'showInactive', + 'hide', + 'isVisible', + 'maximize', + 'unmaximize', + 'isMaximized', + 'minimize', + 'restore', + 'isMinimized', + 'isNormal', + 'setAspectRatio', + 'setBounds', + 'getBounds', + 'setContentBounds', + 'getContentBounds', + 'getNormalBounds', + 'setEnabled', + 'isEnabled', + 'setSize', + 'getSize', + 'setContentSize', + 'getContentSize', + 'setMinimumSize', + 'getMinimumSize', + 'setMaximumSize', + 'getMaximumSize', + 'setResizable', + 'isResizable', + 'setMovable', + 'isMovable', + 'setMinimizable', + 'isMinimizable', + 'setMaximizable', + 'isMaximizable', + 'setClosable', + 'isClosable', + 'setAlwaysOnTop', + 'isAlwaysOnTop', + 'moveTop', + 'center', + 'setPosition', + 'getPosition', + 'setProgressBar', + 'setOpacity', + 'getOpacity', + 'setFocusable', + 'isFocusable' +]; + +const main = ` +const {ipcMain, BrowserWindow} = require('electron'); + +const ALLOWED_METHODS = ${JSON.stringify(exposeBrowserWindowMethods)}; + +ipcMain.handle('superpowers/BrowserWindow', (event, name, ...args) => { + if (!ALLOWED_METHODS.includes(name)) { + throw new Error('Unsupported BrowserWindow method: ' + name); + } + return BrowserWindow.fromWebContents(event.sender)[name](...args); +}); +`.trimStart(); + +const preload = ` +const {contextBridge, ipcRenderer} = require('electron'); + +contextBridge.exposeInMainWorld('PackagerSuperpowers', { + BrowserWindow: (name, ...args) => ipcRenderer.invoke('superpowers/BrowserWindow', name, ...args) +}); +`.trimStart(); + +export default { + main, + preload +}; diff --git a/src/packager/packager.js b/src/packager/packager.js index 7ef615ea..c9ebc3f0 100644 --- a/src/packager/packager.js +++ b/src/packager/packager.js @@ -11,7 +11,7 @@ import {APP_NAME, WEBSITE, COPYRIGHT_NOTICE, ACCENT_COLOR} from './brand'; import {OutdatedPackagerError} from '../common/errors'; import {darken} from './colors'; import {Adapter} from './adapter'; -import electronPreloadJS from '!raw-loader!./electron-preload.js'; +import electronSuperpowerScripts from './electron-superpowers'; const PROGRESS_LOADED_SCRIPTS = 0.1; @@ -513,7 +513,8 @@ cd "$(dirname "$0")" const contentsPrefix = isMac ? `${rootPrefix}${packageName}.app/Contents/` : rootPrefix; const resourcesPrefix = isMac ? `${contentsPrefix}Resources/app/` : `${contentsPrefix}resources/app/`; const electronMainName = 'electron-main.js'; - const electronPreloadName = 'electron-preload.js'; + const electronSuperpowersMainName = 'electron-superpowers.js'; + const electronSuperpowersPreloadName = 'electron-preload.js'; const iconName = 'icon.png'; const icon = await Adapter.getAppIcon(this.options.app.icon); @@ -527,7 +528,7 @@ cd "$(dirname "$0")" zip.file(`${resourcesPrefix}package.json`, JSON.stringify(manifest, null, 4)); const mainJS = `'use strict'; -const {app, BrowserWindow, Menu, shell, screen, dialog} = require('electron'); +const {app, BrowserWindow, Menu, shell, screen, dialog, ipcMain} = require('electron'); const path = require('path'); const isWindows = process.platform === 'win32'; @@ -560,7 +561,7 @@ const createWindow = (windowOptions) => { sandbox: true, contextIsolation: true, nodeIntegration: false, - preload: path.resolve(__dirname, ${JSON.stringify(electronPreloadName)}), + preload: path.resolve(__dirname, ${JSON.stringify(electronSuperpowersPreloadName)}), }, show: true, width: 480, @@ -698,9 +699,12 @@ app.on('window-all-closed', () => { app.whenReady().then(() => { createProjectWindow(defaultProjectURL); }); + +require('./' + ${JSON.stringify(electronSuperpowersMainName)}); `; zip.file(`${resourcesPrefix}${electronMainName}`, mainJS); - zip.file(`${resourcesPrefix}${electronPreloadName}`, electronPreloadJS); + zip.file(`${resourcesPrefix}${electronSuperpowersMainName}`, electronSuperpowerScripts.main) + zip.file(`${resourcesPrefix}${electronSuperpowersPreloadName}`, electronSuperpowerScripts.preload); for (const [path, data] of Object.entries(projectZip.files)) { setFileFast(zip, `${resourcesPrefix}${path}`, data);