Next.JSのElectronデスクトップアプリを作る（Nextronを使わず）

この記事は
[Building Desktop Apps with Electron + Next.JS (without Nextron)](https://rbfraphael.medium.com/building-desktop-apps-with-electron-next-js-without-nextron-01bbf1fdd72e)
を抜粋して翻訳したものです。

## Step1: Next.JSのプロジェクトを作る
```
npx create-next-app@latest my-app
```
このコマンドを実行すると、以下プロジェクトの設定が行われる
```
What is your project named? my-app
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the default import alias (@/*)? No / Yes
What import alias would you like configured? @/*
```

## Step2: Electronと依頼パッケージをインストールする
プロジェクトのルートディレクトリに`cd`して、electron、electron-builder、concurrentlyをdev依頼としてインストールする
```
npm install --save-dev electron electron-builder concurrently
```
そして、プロジェクトの依頼パッケージをインストールする
```
npm install electron-serve
```

## Step3: package.jsonを編集する
`package.json`に下記の内容を追加する
```json
{
  ...
  "main": "main.js",
  "description": "Electron + NextJS example project",
  "scripts": {
    "dev": "concurrently -n \"NEXT,ELECTRON\" -c \"yellow,blue\" --kill-others \"next dev\" \"electron .\"",
    "build": "next build && electron-builder",
    ...
  }
  ...
}
```
scriptsをこのように記載することで、`npm run dev`でNext.JSの開発サーバーとElectronの開発サーバーが同時に起動するようになる

## Step4: Next.JSを設定する
プロジェクトのルートディレクトリには`next.config.js`があるはずなので、下記の内容に変更する
```js
const nextConfig = {
  ...
  output: "export",
  images: {
    unoptimized: true
  }
  ...
}
```

## Step5: main.jsを作る
プロジェクトのルートディレクトリで`main.js`を下記の内容で作成する
```js
const { app, BrowserWindow } = require("electron");
const serve = require("electron-serve");
const path = require("path");

const appServe = app.isPackaged ? serve({
  directory: path.join(__dirname, "../out")
}) : null;

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "preload.js")
    }
  });

  if (app.isPackaged) {
    appServe(win).then(() => {
      win.loadURL("app://-");
    });
  } else {
    win.loadURL("http://localhost:3000");
    win.webContents.openDevTools();
    win.webContents.on("did-fail-load", (e, code, desc) => {
      win.webContents.reloadIgnoringCache();
    });
  }
}

app.on("ready", () => {
    createWindow();
});

app.on("window-all-closed", () => {
    if(process.platform !== "darwin"){
        app.quit();
    }
});
```

## Step6: preload.jsを作る
プロジェクトのルートディレクトリで`preload.js`を下記の内容で作成する
```js
const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld("electronAPI", {
    on: (channel, callback) => {
        ipcRenderer.on(channel, callback);
    },
    send: (channel, args) => {
        ipcRenderer.send(channel, args);
    }
});
```

## Step7: 実行してテストする
`npm run dev`を実行して、アプリが起動できることを確認する。

## Step8: ビルドする
プロジェクトのルートディレクトリで`electron-builder.yaml`を作成して、コードビルドの設定を記載する
```yaml
appId: "io.github.rbfraphael.electron-next"
productName: "Electron Next.JS"
copyright: "Copyright (c) 2023 RBFraphael"
win:
  target: ["dir", "portable", "zip"]
  icon: "resources/icon.ico"
linux:
  target: ["dir", "appimage", "zip"]
  icon: "resources/icon.png"
mac:
  target: ["dir", "dmg", "zip"]
  icon: "resources/icon.icns"
```
これにより、`npm run build`でビルドできるようになる。