Intro
This time, I will try using Electron on Windows.
Environments
- Windows 11 Pro Insider Preview ver.22H2
- Node.js ver.18.12.1
package.json
{ "name": "electron-sample", "version": "1.0.0", "description": "", "main": "views/js/main.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "electron-forge start", "package": "electron-forge package", "make": "electron-forge make" }, "author": "Masui Masanori", "license": "MIT", "devDependencies": { "@electron-forge/cli": "^6.0.4", "@electron-forge/maker-deb": "^6.0.4", "@electron-forge/maker-rpm": "^6.0.4", "@electron-forge/maker-squirrel": "^6.0.4", "@electron-forge/maker-zip": "^6.0.4", "@typescript-eslint/eslint-plugin": "^5.46.0", "@typescript-eslint/parser": "^5.46.0", "electron": "^22.0.0", "eslint": "^8.29.0", "ts-loader": "^9.4.2", "typescript": "^4.9.4", "webpack": "^5.75.0", "webpack-cli": "^5.0.1" }, "dependencies": { "electron-log": "^4.4.8", "electron-squirrel-startup": "^1.0.0" } }
Unable to load preload script
First, I wrote an Electron application with these code below.
global.d.ts
declare global { interface Window { myapi: Sandbox }; } export interface Sandbox { logDebug: (callFrom: string, message: string) => void, logError: (callFrom: string, message: string) => void };
[Electron side] main.ts
import { app, BrowserWindow, ipcMain } from 'electron'; import * as log from "electron-log"; import * as path from 'path'; function createWindow () { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), } }); win.loadFile('./views/index.html'); } app.whenReady().then(() => { createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); ipcMain.handle("debugLog", (_, message: string) => { log.debug(message); });
[Electron side] preload.ts
import { ipcRenderer, contextBridge } from 'electron'; import * as log from 'electron-log'; window.addEventListener('DOMContentLoaded', () => { console.log("Loaded"); }); contextBridge.exposeInMainWorld('myapi', { logDebug: async (callFrom: string, message: string) => await ipcRenderer.invoke("debugLog", `[${callFrom}] ${message}`), logError: (callFrom: string, message: string) => log.error(`[${callFrom}] ${message}`) } );
[Client side] main.page.ts
export function init() { window.myapi.logDebug("main.page", "Hello"); window.myapi.logError("main.page", "Hello Error"); }
But I got an exception on client-side.
Unable to load preload script: C:\Users\example\OneDrive\Documents\workspace\ElectronSample\out\electron-sample-win32-x64\resources\app\views\js\preload.js VM4 sandbox_bundle:2 Error: module not found: electron-log at preloadRequire (VM4 sandbox_bundle:2:82516) at <anonymous>:37:26 at runPreloadScript (VM4 sandbox_bundle:2:83356) at VM4 sandbox_bundle:2:83615 at VM4 sandbox_bundle:2:83770 at ___electron_webpack_init__ (VM4 sandbox_bundle:2:83774) at VM4 sandbox_bundle:2:83897 VM4 sandbox_bundle:2 Failed to load resource: net::ERR_FILE_NOT_FOUND main.page.js:1
In this situation、I have to set "nodeIntegration" enabled.
main.ts
... function createWindow () { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, preload: path.join(__dirname, 'preload.js'), } }); win.loadFile('./views/index.html'); } ...
I have to write "nodeIntegration" before "preload".
Otherwise I will get the same error.
This is because I use "electron-log" in "preload.ts".
If I remove it, I also can write like below.
main.ts
... function createWindow () { const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { contextIsolation: true, preload: path.join(__dirname, 'preload.js'), } }); win.loadFile('./views/index.html'); } ...
Adding extra resource files
I can load external files like below.
But the files aren't output by "electron-forge make".
To do this, I should add "extraResource" into forge.config.js.
appSettings.json
{ "message": "Hello world!" }
forge.config.js
module.exports = { packagerConfig: { "extraResource": [ "./appSettings.json" ] }, rebuildConfig: {}, makers: [ { name: '@electron-forge/maker-squirrel', config: { authors: 'Masui Masanori', description: 'WebRTC sample' }, }, { name: '@electron-forge/maker-zip', platforms: ['darwin'], }, { name: '@electron-forge/maker-deb', config: {}, }, { name: '@electron-forge/maker-rpm', config: {}, }, ], };
The file will be output into "{ProjectDirectory}/out/electron-sample-win32-x64/resources".
So I can read it by "process.resourcesPath".
main.ts
... export async function load() { const fileData = await fs.promises.readFile(path.join(process.resourcesPath, "appSettings.json"), { encoding: 'utf-8' }); log.debug(JSON.parse(fileData)); }
Top comments (0)