DEV Community

Masui Masanori
Masui Masanori

Posted on

[Windows] Try Electron 2

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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
};
Enter fullscreen mode Exit fullscreen mode

[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);
});
Enter fullscreen mode Exit fullscreen mode

[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}`)
  }
);
Enter fullscreen mode Exit fullscreen mode

[Client side] main.page.ts

export function init() {
    window.myapi.logDebug("main.page", "Hello");
    window.myapi.logError("main.page", "Hello Error");
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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');
}
...
Enter fullscreen mode Exit fullscreen mode

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');
}
...
Enter fullscreen mode Exit fullscreen mode

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!"
}
Enter fullscreen mode Exit fullscreen mode

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: {},
    },
  ],
};
Enter fullscreen mode Exit fullscreen mode

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));
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)