🙆

Vue3+ElectronでのWindowsアプリ開発

2022/11/18に公開

はじめに

前回の記事で作成したToDoアプリをWindows上で実行できるようにします。Quasar上でも開発できるのですが、バージョンが古かったため、直接Electronを利用しています。

Electronとは

公式サイトからの引用です。
Electron は、JavaScript、HTML、CSS によるデスクトップアプリケーションを構築するフレームワークです。 Electron は Chromium と Node.js をバイナリに組み込むことで、単一の JavaScript コードベースを維持しつつ、ネイテイブ開発経験無しでも Windows、macOS、Linux で動作するクロスプラットフォームアプリを作成できます。

Windowsアプリ作成

基本的は公式サイトを参考にしていますが、WSL上で開発するためにいくつか手順を追加しています。MacOS版は端末を持っていないので、設定を省略しています。各自で追加してください。

  1. Electronをインストールします。その際、WSL上で必要なライブラリも追加します。
sudo apt-get install libatk1.0-0 libcups2-dev libatk-bridge2.0-0 libgtk-3.0 libgbm-dev
npm install --platform=win32 electron electron-builder concurrently --save-dev
  1. Electronのクイックスタートを参考にTypescriptでmain.ts、preload.tsを作成する。
src/electron/main.ts
import { join } from "path";
import { app, BrowserWindow } from "electron";

const isDev = process.env.npm_lifecycle_event === "app:dev" ? true : false;

function createWindow() {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: join(__dirname, "../preload.js"),
    },
  });

  if (isDev) {
    mainWindow.loadURL("http://localhost:5173");
    mainWindow.webContents.openDevTools();
  } else {
    mainWindow.loadFile(join(__dirname, "../index.html"));
  }
}

// WSLでデバックする際に必要
app.commandLine.appendSwitch("no-sandbox");

// 開いたウインドウがない場合にウインドウを開く (macOS)
app.whenReady().then(() => {
  createWindow();
  app.on("activate", function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

// 全ウインドウを閉じた時にアプリを終了する (Windows & Linux)
app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});
src/electron/main.ts
// プリロードスクリプトを使ってレンダラーから Node.js にアクセスする
window.addEventListener("DOMContentLoaded", () => {
  const replaceText = (selector: any, text: any) => {
    const element = document.getElementById(selector);
    if (element) element.innerText = text;
  };

  for (const dependency of ["chrome", "node", "electron"]) {
    replaceText(`${dependency}-version`, process.versions[dependency]);
  }
});

※WSL(Ubuntu)上でデバックする際に、以下のエラーが発生したため、本記事も参考にしている。

...
[1] [4788:1118/040907.612:ERROR:gpu_process_host.cc(969)] GPU process launch failed: error_code=18
[1] [4788:1118/040907.612:FATAL:gpu_data_manager_impl_private.cc(441)] GPU process isn't usable. Goodbye.
  1. 作成したelectronのtsファイルをtscでコンパイルできるように、tsconfig.jsonを修正する。
tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "commonjs",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "isolatedModules": false,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "skipLibCheck": true,
    "outDir": "dist/electron"
  },
  "include": ["src/electron/*"],
  "references": [
    {
      "path": "./tsconfig.config.json"
    }
  ]
}
  1. vite.config.tsにbaseを追加する。これを設定しないと動かない。
vite.config.ts
...
export default defineConfig({
  plugins: [vue()],
  base: "./",
  ...
  1. electronでデバックやビルドができるようにpackage.jsonに以下のコードを追加する。
    NSIS(Nullsoft Scriptable Install System)の設定内容は、ここを参考のこと。ワンクリックインストールの解除、インストール先を変更できるようにしている。
package.json
{
  ...
  "main": "dist/electron/main.js",
  "scripts": {
    ...
    "app:dev": "tsc && concurrently vite \" electron .\" \"tsc -w\"",
    "app:build": "npm run build && tsc && electron-builder --win --x64",
    "app:preview": "npm run build && tsc && electron ."
  },
  "build": {
    "asar": true,
    "directories": {
      "buildResources": "assets",
      "output": "release/${version}"
    },
    "files": [
      "dist"
    ],
    "win": {
      "target": "nsis",
      "artifactName": "${productName}_${version}.${ext}"
    },
    "nsis": {
      "oneClick": false,
      "allowToChangeInstallationDirectory": true
    }
  },
  ...
  1. デバック実行、ビルドを行ってみる。ビルドは私の端末で3分かかました。ビルド後はreleaseフォルダにインストーラが作成され、win-uppacked内のexeでも直接実行できます。
$ npm run app:dev
$ npm run app:build

おわりに

Quaserを通じて、Electronの存在を最近知りました。Vueで作ったアプリがWebサーバやブラウザがなくても、オフラインで動くのは魅力的ですね。

Discussion