[Windows] Try Electron 2
Tags: electron, typescript
Published: 2022-12-17 13:02:20

## 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
```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
```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
```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
```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
```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
```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
```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');
}
...
```

* [Unable to load preload script #2931 - electron/forge - GitHub](https://github.com/electron/forge/issues/2931)

## Adding extra resource files
I can load external files like below.

* [[Electron][TypeScript] output/input files](https://dev.to/masanori_msl/electron-typescript-output-input-files-315e)

But the files aren't output by "electron-forge make".
To do this, I should add "extraResource" into forge.config.js.

#### appSettings.json
```json
{
    "message": "Hello world!"
}
```

#### forge.config.js
```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
```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));
}
```

* [Optional extraResource - electron-packager](https://electron.github.io/electron-packager/main/interfaces/electronpackager.options.html#extraresource)
* [How to add extra resources files in production in electron using electron-forge - StackOverflow](https://stackoverflow.com/questions/66970293/how-to-add-extra-resources-files-in-production-in-electron-using-electron-forge)