diff --git a/resources/js/electron-plugin/dist/preload/index.mjs b/resources/js/electron-plugin/dist/preload/index.mjs index 46d3f01a..34bec7c9 100644 --- a/resources/js/electron-plugin/dist/preload/index.mjs +++ b/resources/js/electron-plugin/dist/preload/index.mjs @@ -1,5 +1,5 @@ import remote from "@electron/remote"; -import { ipcRenderer } from "electron"; +import { ipcRenderer, contextBridge } from "electron"; const Native = { on: (event, callback) => { ipcRenderer.on('native-event', (_, data) => { @@ -15,8 +15,7 @@ const Native = { menu.popup({ window: remote.getCurrentWindow() }); } }; -window.Native = Native; -window.remote = remote; +contextBridge.exposeInMainWorld('Native', Native); ipcRenderer.on('log', (event, { level, message, context }) => { if (level === 'error') { console.error(`[${level}] ${message}`, context); @@ -52,3 +51,7 @@ ipcRenderer.on('native-event', (event, data) => { }); } }); +contextBridge.exposeInMainWorld('native:initialized', (function () { + window.dispatchEvent(new CustomEvent('native:init')); + return true; +})()); diff --git a/resources/js/electron-plugin/dist/server/api/menuBar.js b/resources/js/electron-plugin/dist/server/api/menuBar.js index 21ee49d4..a664a2a6 100644 --- a/resources/js/electron-plugin/dist/server/api/menuBar.js +++ b/resources/js/electron-plugin/dist/server/api/menuBar.js @@ -4,8 +4,8 @@ import { compileMenu } from "./helper/index.js"; import state from "../state.js"; import { menubar } from "menubar"; import { notifyLaravel } from "../utils.js"; -import { fileURLToPath } from 'url'; import { enable } from "@electron/remote/main/index.js"; +import mergePreferences from "../webPreferences.js"; const router = express.Router(); router.post("/label", (req, res) => { var _a; @@ -51,7 +51,7 @@ router.post("/create", (req, res) => { state.activeMenuBar.tray.destroy(); shouldSendCreatedEvent = false; } - const { width, height, url, label, alwaysOnTop, vibrancy, backgroundColor, transparency, icon, showDockIcon, onlyShowContextMenu, windowPosition, showOnAllWorkspaces, contextMenu, tooltip, resizable, event, } = req.body; + const { width, height, url, label, alwaysOnTop, vibrancy, backgroundColor, transparency, icon, showDockIcon, onlyShowContextMenu, windowPosition, showOnAllWorkspaces, contextMenu, tooltip, resizable, webPreferences, event, } = req.body; if (onlyShowContextMenu) { const tray = new Tray(icon || state.icon.replace("icon.png", "IconTemplate.png")); tray.setContextMenu(buildMenu(contextMenu)); @@ -81,12 +81,7 @@ router.post("/create", (req, res) => { vibrancy, backgroundColor, transparent: transparency, - webPreferences: { - preload: fileURLToPath(new URL('../../electron-plugin/dist/preload/index.mjs', import.meta.url)), - nodeIntegration: true, - sandbox: false, - contextIsolation: false, - } + webPreferences: mergePreferences(webPreferences) } }); state.activeMenuBar.on("after-create-window", () => { diff --git a/resources/js/electron-plugin/dist/server/api/window.js b/resources/js/electron-plugin/dist/server/api/window.js index 8a75ec74..0d3befe7 100644 --- a/resources/js/electron-plugin/dist/server/api/window.js +++ b/resources/js/electron-plugin/dist/server/api/window.js @@ -1,9 +1,9 @@ import express from 'express'; import { BrowserWindow } from 'electron'; import state from '../state.js'; -import { fileURLToPath } from 'url'; import { notifyLaravel, goToUrl, appendWindowIdToUrl } from '../utils.js'; import windowStateKeeper from 'electron-window-state'; +import mergePreferences from '../webPreferences.js'; import { enable } from "@electron/remote/main/index.js"; const router = express.Router(); router.post('/maximize', (req, res) => { @@ -152,15 +152,6 @@ router.post('/open', (req, res) => { res.sendStatus(200); return; } - let preloadPath = fileURLToPath(new URL('../../electron-plugin/dist/preload/index.mjs', import.meta.url)); - const defaultWebPreferences = { - backgroundThrottling: false, - spellcheck: false, - preload: preloadPath, - sandbox: false, - contextIsolation: false, - nodeIntegration: true, - }; let windowState = undefined; if (req.body.rememberState === true) { windowState = windowStateKeeper({ @@ -187,7 +178,7 @@ router.post('/open', (req, res) => { focusable, skipTaskbar, hiddenInMissionControl, - autoHideMenuBar }, (process.platform === 'linux' ? { icon: state.icon } : {})), { webPreferences: Object.assign(Object.assign({}, webPreferences), defaultWebPreferences), fullscreen, + autoHideMenuBar }, (process.platform === 'linux' ? { icon: state.icon } : {})), { webPreferences: mergePreferences(webPreferences), fullscreen, fullscreenable, kiosk })); if ((process.env.NODE_ENV === 'development' || showDevTools === true) && showDevTools !== false) { diff --git a/resources/js/electron-plugin/dist/server/webPreferences.js b/resources/js/electron-plugin/dist/server/webPreferences.js new file mode 100644 index 00000000..4ab81a1f --- /dev/null +++ b/resources/js/electron-plugin/dist/server/webPreferences.js @@ -0,0 +1,15 @@ +import { fileURLToPath } from 'url'; +let preloadPath = fileURLToPath(new URL('../../electron-plugin/dist/preload/index.mjs', import.meta.url)); +const defaultWebPreferences = { + spellcheck: false, + nodeIntegration: false, + backgroundThrottling: false, +}; +const requiredWebPreferences = { + sandbox: false, + preload: preloadPath, + contextIsolation: true, +}; +export default function (userWebPreferences = {}) { + return Object.assign(Object.assign(Object.assign({}, defaultWebPreferences), userWebPreferences), requiredWebPreferences); +} diff --git a/resources/js/electron-plugin/src/preload/index.mts b/resources/js/electron-plugin/src/preload/index.mts index 031999b6..579961bf 100644 --- a/resources/js/electron-plugin/src/preload/index.mts +++ b/resources/js/electron-plugin/src/preload/index.mts @@ -1,6 +1,9 @@ import remote from "@electron/remote"; -import {ipcRenderer} from "electron"; +import {ipcRenderer, contextBridge} from "electron"; +// ------------------------------------------------------------------- +// The Native helper +// ------------------------------------------------------------------- const Native = { on: (event, callback) => { ipcRenderer.on('native-event', (_, data) => { @@ -19,12 +22,11 @@ const Native = { } }; -// @ts-ignore -window.Native = Native; - -// @ts-ignore -window.remote = remote; +contextBridge.exposeInMainWorld('Native', Native); +// ------------------------------------------------------------------- +// Log events +// ------------------------------------------------------------------- ipcRenderer.on('log', (event, {level, message, context}) => { if (level === 'error') { console.error(`[${level}] ${message}`, context) @@ -35,7 +37,10 @@ ipcRenderer.on('log', (event, {level, message, context}) => { } }); -// Add Livewire event listeners + +// ------------------------------------------------------------------- +// Livewire event listeners +// ------------------------------------------------------------------- ipcRenderer.on('native-event', (event, data) => { // Strip leading slashes @@ -82,3 +87,23 @@ ipcRenderer.on('native-event', (event, data) => { }) } }) + +// ------------------------------------------------------------------- +// Let the client know preload is fully evaluated +// ------------------------------------------------------------------- +contextBridge.exposeInMainWorld('native:initialized', (function() { + // This is admittedly a bit hacky. Due to context isolation + // we don't have direct access to the renderer window object, + // but by assigning a bridge function that executes itself inside + // the renderer context we can hack around it. + + // It's recommended to use window.postMessage & dispatch an + // event from the renderer itself, but we're loading webcontent + // from localhost. We don't have a renderer process we can access. + // Though this is hacky it works well and is the quickest way to do this + // without sprinkling additional logic all over the place. + + window.dispatchEvent(new CustomEvent('native:init')); + + return true; +})()) diff --git a/resources/js/electron-plugin/src/server/api/menuBar.ts b/resources/js/electron-plugin/src/server/api/menuBar.ts index 90b3b48b..97246ad6 100644 --- a/resources/js/electron-plugin/src/server/api/menuBar.ts +++ b/resources/js/electron-plugin/src/server/api/menuBar.ts @@ -6,6 +6,7 @@ import { menubar } from "menubar"; import { notifyLaravel } from "../utils.js"; import { fileURLToPath } from 'url' import { enable } from "@electron/remote/main/index.js"; +import mergePreferences from "../webPreferences.js"; const router = express.Router(); @@ -88,6 +89,7 @@ router.post("/create", (req, res) => { contextMenu, tooltip, resizable, + webPreferences, event, } = req.body; @@ -129,12 +131,7 @@ router.post("/create", (req, res) => { vibrancy, backgroundColor, transparent: transparency, - webPreferences: { - preload: fileURLToPath(new URL('../../electron-plugin/dist/preload/index.mjs', import.meta.url)), - nodeIntegration: true, - sandbox: false, - contextIsolation: false, - } + webPreferences: mergePreferences(webPreferences) } }); diff --git a/resources/js/electron-plugin/src/server/api/window.ts b/resources/js/electron-plugin/src/server/api/window.ts index 3224919a..da891061 100644 --- a/resources/js/electron-plugin/src/server/api/window.ts +++ b/resources/js/electron-plugin/src/server/api/window.ts @@ -4,6 +4,7 @@ import state from '../state.js'; import { fileURLToPath } from 'url' import { notifyLaravel, goToUrl, appendWindowIdToUrl } from '../utils.js'; import windowStateKeeper from 'electron-window-state'; +import mergePreferences from '../webPreferences.js' import {enable} from "@electron/remote/main/index.js"; @@ -247,17 +248,6 @@ router.post('/open', (req, res) => { return; } - let preloadPath = fileURLToPath(new URL('../../electron-plugin/dist/preload/index.mjs', import.meta.url)); - - const defaultWebPreferences = { - backgroundThrottling: false, - spellcheck: false, - preload: preloadPath, - sandbox: false, - contextIsolation: false, - nodeIntegration: true, - }; - let windowState: windowStateKeeper.State | undefined = undefined; if (req.body.rememberState === true) { @@ -301,10 +291,7 @@ router.post('/open', (req, res) => { hiddenInMissionControl, autoHideMenuBar, ...(process.platform === 'linux' ? {icon: state.icon} : {}), - webPreferences: { - ...webPreferences, - ...defaultWebPreferences - }, + webPreferences: mergePreferences(webPreferences), fullscreen, fullscreenable, kiosk, diff --git a/resources/js/electron-plugin/src/server/webPreferences.ts b/resources/js/electron-plugin/src/server/webPreferences.ts new file mode 100644 index 00000000..b53b631f --- /dev/null +++ b/resources/js/electron-plugin/src/server/webPreferences.ts @@ -0,0 +1,24 @@ +import { fileURLToPath } from 'url' + +let preloadPath = fileURLToPath(new URL('../../electron-plugin/dist/preload/index.mjs', import.meta.url)); + +const defaultWebPreferences = { + spellcheck: false, + nodeIntegration: false, + backgroundThrottling: false, +}; + +const requiredWebPreferences = { + sandbox: false, + preload: preloadPath, + contextIsolation: true, +} + +export default function(userWebPreferences: object = {}): object +{ + return { + ...defaultWebPreferences, + ...userWebPreferences, + ...requiredWebPreferences + } +} diff --git a/resources/js/electron.vite.config.mjs b/resources/js/electron.vite.config.mjs index a4d80ed0..4af81f9c 100644 --- a/resources/js/electron.vite.config.mjs +++ b/resources/js/electron.vite.config.mjs @@ -16,8 +16,5 @@ export default defineConfig({ }, }, plugins: [externalizeDepsPlugin()] - }, - preload: { - plugins: [externalizeDepsPlugin()] } }); diff --git a/resources/js/src/preload/index.js b/resources/js/src/preload/index.js deleted file mode 100644 index a085b054..00000000 --- a/resources/js/src/preload/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import { electronAPI } from '@electron-toolkit/preload' -import * as remote from '@electron/remote/index.js' - -window.electron = electronAPI -window.remote = remote;