[TypeScript] Try Electron
Tags: typescript, electron
Published: 2021-04-10 14:02:37

## Intro
This time, I will try Electron with TypeScript.

### Environments
* Node.js ver.15.14.0

#### package.json
```json
{
    "main": "./js/main.js",
    "scripts": {
        "start": "electron ."
    },
    "devDependencies": {
        "electron": "^12.0.2",
        "typescript": "^4.2.4"
    }
}
```

## TS5023: Unknown compiler option 'init'
I had installed TypeScript by this command.
```
npm install --save typescript tsc
```

But when I had executed "npx tsc --init", I got an error.
```
error TS5023: Unknown compiler option 'init'.
```

This problem had occurred on my own Surface 6.
But on my PC for work hadn't occurred.

I don't know the reason for their differences.

### Resolve
Using "--save-dev" option and stopping installing tsc individually helped me avoiding the error.
```
npm install --save-dev typescript
```
* [TypeScript: How to set up TypeScript](https://www.typescriptlang.org/id/download)

## Try Electron
I create an Electron application according to "Quick Start Guide".

* [Quick Start - Electron](https://www.electronjs.org/docs/latest/tutorial/quick-start#create-your-application)

### create executable file
I can create executable files and installer according to the document.
* [Quick Start - Electron](https://www.electronjs.org/docs/latest/tutorial/quick-start#package-and-distribute-your-application)

But because I had reset my computer and I hadn't installed some software yet, I got some errors.

#### git
First, when I executed "npx electron-forge import", I got an error.
```
It looks like you are missing some dependencies you need to get Electron running.
...
```

After installing git, the error hadn't been occured.

#### Visual Studio
After that, when I executed "npm run make", I got another error.

```
An unhandled error has occurred inside Forge:
An error occured while making for target: squirrel
Failed with exit code: 1
Output:
Attempting to build package from '.nuspec'.
Id is required.

Error: Failed with exit code: 1
Output:
Attempting to build package from '.nuspec'.
Id is required.
...
```

Although I had installed Visual Studio 2019, I got the same error again.
So I tried executing "npx electron-forge import" again.

After that, After that the error no longer occurred.

I thought some packages hadn't been installed at first time.

## Play with Electron
### Base project
#### main.ts
```ts
import { app, ipcMain, BrowserWindow } from 'electron';
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();
  }
});
```

I just converted into TypeScript and added semicolons.

#### index.html
```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body style="background: white;">
    <h1>Hello World!</h1>
    <p>
        We are using Node.js <span id="node-version"></span>,
        Chromium <span id="chrome-version"></span>,
        and Electron <span id="electron-version"></span>.
    </p>
    <div>
        <button id="sample_button">Click</button>
    </div>
    <script src="../js/clients/main.page.js"></script>
</body>
</html>
```

### Call client-side method
I can call client-side method from electron-side through "BrowserWindow".

#### main.page.ts
```ts
function greet(message: string): string {
    alert(message);
    return 'OK';
}
```
#### main.ts
```ts
...
function createWindow () {
  const win = new BrowserWindow({
...
  });

  win.loadFile('./views/index.html');
  win.webContents.executeJavaScript(`greet('Hello World')`)
    .then((returnValue) => console.log(returnValue))
    .catch(error => console.error(error));
}
...
```
#### Result
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v2h15iqickm2suzngh9k.jpg)

I also can open Developer tool(win.webContents.openDevTools), print(win.webContents.print), or execute commands of the browser through "BrowserWindow".

### Call electron-side methods from client-side
I can't call electron-side methods from client-side.
So if I want to do so, I have to add event listeners into electron-side, and I fire the events from client-side. 

#### main.ts
```ts
...
ipcMain.on('call_from_dom', (args) => console.log('called'));
```

#### client-side js?
```js
const { ipcRenderer } = require('electron');
function clickEvent() {
    ipcRenderer.send('call_from_dom', ['hello electron']);
}
```

Now I have a problem.
I can't add "client-side js?" code into "main.page.ts", because I can't use "require" in client-side.

So I add the code into "preload.ts(preload.js)".

```ts
import { ipcRenderer } from 'electron';
window.addEventListener('DOMContentLoaded', () => {
    const replaceText = (selector: string, text: string|undefined) => {
      const element = document.getElementById(selector)
      if (element != null) {
        element.innerText = text ?? '';
      }
    }  
    for (const type of ['chrome', 'node', 'electron']) {
      replaceText(`${type}-version`, process.versions[type])
    }
    // add the event to call electron-side method.
    const button = document.getElementById('sample_button');
    if(button != null) {
        button.addEventListener('click', (ev) => ipcRenderer.send('call_from_dom', ['hello electron']));
    }
  });
```

Although that code is for client-side, it may be executed in electron-side.

### Get command-line arguments
I can get command-line arguments by "process.argv".

#### main.ts
```ts
...
function createWindow () {
   console.log(process.argv);
... 
}
```

* [app | Electron](https://www.electronjs.org/docs/api/app)
* [ipcRenderer | Electron](https://www.electronjs.org/docs/api/ipc-renderer)
* [How to parse command line arguments | Node.js](https://nodejs.org/en/knowledge/command-line/how-to-parse-command-line-arguments/)
* [ElectronでToDoアプリを開発する - Qiita](https://qiita.com/hoshi_shiitake/items/fb4b33a3602cbed9d567)