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)