シリアル通信実装でハマった（Nuxt3 + TypeScript + Electron）

# シリアル通信実装でハマった（Nuxt3 + TypeScript + Electron）

## 環境
- PC: Windows(x64) / Mac(arm64)
- Yarn: 1.22.19
- Node.js: 20.5.1
- Nuxt.js: 3.7.0
- TypeScript: 5.2.2
- Electron: 26.1.0
- serialport: 12.0.0

## はじめに
Nuxt3 + TypeScript + Electronで開発中のデスクトップアプリに[serialport](https://www.npmjs.com/package/serialport)を導入しようとした。

> *serialport*
> Access serial ports with JavaScript. Linux, OSX and Windows. Welcome your robotic JavaScript overlords. Better yet, program them!

そこで、`yarn add -D serialport`でをインストールして、mainプロセスでサンプルコードを実行した。
```electron/main.ts
SerialPort.list().then((ports) => {
    ports.forEach((port) => {
      console.log(port.path);
    });
  });
```
```package.json
{
  "name": "nuxt-app",
  "private": true,
  "packageManager": "yarn@1.22.19",
  "main": "dist-electron/main.js",
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev --dotenv ../.env src",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare",
    "format": "prettier --write .",
    "lint": "eslint ./**/*.{vue,ts}"
  },
  "devDependencies": {
    "@mdi/font": "^7.2.96",
    "@nuxt/devtools": "latest",
    "@nuxtjs/eslint-config-typescript": "^12.1.0",
    "electron": "^26.1.0",
    "electron-rebuild": "^3.2.9",
    "eslint": "^8.48.0",
    "eslint-plugin-vue": "^9.17.0",
    "nuxt": "^3.7.0",
    "nuxt-electron": "^0.6.0",
    "prettier": "^3.0.3",
    "sass": "^1.66.1",
    "serialport": "^12.0.0",
    "typescript": "^5.2.2",
    "vite-plugin-electron": "^0.14.0",
    "vite-plugin-vuetify": "^1.0.2",
    "vuetify": "^3.3.15"
  },
  "dependencies": {}
}
```

## エラー内容
```version:windows
Error: No native build was found for platform=win32 arch=x64 runtime=electron abi=116 uv=1 armv=8 libc=glibc node=18.16.1 electron=26.1.0
```
どうやら`platform=win32 arch=x64`用のNative Buildが見つからない...
Windows特有のエラーなのかと思い、Macでも同じ環境で確かめてみた。

```version:mac
Error: No native build was found for platform=darwin arch=arm64 runtime=electron abi=116 uv=1 armv=8 libc=glibc node=18.16.1 electron=26.1.0
```
同一エラーがでている...
以前Python([pyserial](https://pypi.org/project/pyserial/))でシリアル通信を行ったときはこのようなエラーは発生しなかった。

## 試したこと
- Native Moduleをrebuildする
  - Electron公式ドキュメント[using-native-node-modules](https://www.electronjs.org/ja/docs/latest/tutorial/using-native-node-modules)を読み、[@electron/rebuild](https://github.com/electron/rebuild)を導入してみた

- node_modulesからserialportを削除してinstallしなおす
  1. `rm --recursive node_modules/serialport`
  2. `yarn install　--no-save --build-from-source　serialport@12.0.0`

## 解決策
viteのbuild時にserialportをbundleさせず、外部から読み込むように`nuxt.config.ts`に設定した。
```nuxt.config.ts
electron: {
  build: [
    {
      entry: "electron/main.ts",
+     vite: {
+       build: {
+         rollupOptions: {
+           external: ["serialport"],
+         },
+       },
+     },
    },
  ],
},
```
これで無事にbuildできるようになった！

## 何が問題だったのか
まずserialport公式ドキュメント[guide-installation](https://serialport.io/docs/guide-installation)を読むと、serialportはNative Moduleであり、PlatformやArchitectureに依存したコードを含んでいることがわかる。

> This assumes you have everything on your system necessary to compile ANY native module for Node.js. 

例えば、Windowsの場合だと、[node-gyp](https://github.com/nodejs/node-gyp)が必要である。また、node-gypをインストールするためには[Visual C++](https://visualstudio.microsoft.com/ja/downloads/)が必要となる。（結構面倒...）

> Node-Serialport supports Windows 10+. Precompiled binaries are available, but if you want to build it from source you'll need to follow the node-gyp installation instructions. Once you've got things working, you can install Node-Serialport from source with:
`npm install serialport`
Node-gyp's documentation doesn't mention it, but it sometimes helps to create a C++ project in Visual Studio so that it will install any necessary components not already installed during the past two hours of setup. This will solve some instances of `Failed to locate: CL.exe`.

上記のように、環境ごとに必要なツールを用意することで今回のエラーは解決すると考える。
しかし、実行するプラットフォーム/アーキテクチャによって必要なツールを入れることは面倒である。

- 結論：**必要なNative Moduleが少量の場合はbundleさせない**

:::note warn
複数のNative Moduleを利用する場合
Native Moduleのダウンロード/インストールにたくさんの時間を要してbuild時間が長くなるため要検討！
:::

Nuxt3はbuildツールとしてViteを採用しているため、Viteのbuild時にserialportをbundleさせないようにする。そうすることで、build時に必要なNative Moduleを動的にダウンロード/インストールするようになり、プラットフォーム/アーキテクチャに依存せずbuildすることができる。