Electron + SvelteKitの開発環境を整える手順
※本ページはプロモーションが含まれていますElectron + SvelteでクロスOSのデスクトップアプリを作ろうと思ったのですが、開発環境整備に苦労しました。
Electronは、便利な開発パッケージがなく、ホットリロードやTypescript対応、webpackからviteへの変更など、やりたいことがあると開発環境整備はかなり面倒です。
そこで見つけたのがelectron-vite。
Electron開発に必要なモジュールやviteの設定などを一通り整えてくれて便利。
基本CommonJSなElectronもEMSで使えるようにしてくれているのもありがたい。
更に、@quick-start/electronを使うと、vue、react、svelte、solidなどのフレームワークと合わせてセットアップしてくれます。
これのsvelteを使えば一発で開発環境ができるかと思いきや、インストールされるのはsvelteKitではなく純粋なsvelteで、svelteKitへのアップデートがうまくいかず挫折。
色々試行錯誤し、最終的には@quick-start/electronのvanilla-tsを使いTypescript対応のElectron環境を作り、その中のsrc/renderer内にsvelteKitをインストールして使う方法に落ち着きました。
Electronとsvelteを別々に起動する構成です。
構築手順を紹介します。
Electron + svelteKitの構成
プロジェクトを作成したいフォルダに移動し、 @quick-start/electronを実行。my-app部分はアプリの名前。現在居るフォルダにこの名前であたらしいフォルダが作成される。
pnpm create @quick-start/electron my-app --template vanilla-ts
下記質問が表示されるので、とりあえず両方Yesを選択。
√ Add Electron updater plugin? ... No / Yes √ Enable Electron download mirror proxy? ... No / Yes
作成したプロジェクトに移動し、依存関係をインストールします。
cd my-app pnpm install
ElectronサービスとSvelteKitサーバーを同時に起動するためにconcurrentlyを追加します。
pnpm i concurrently
最新バージョンにするためにアップデートを確認
pnpm outdated
複数個別にアップデート場合は下記のように。
pnpm update package-name1 package-name2 --latest
一気に全部アップデートするには下記コマンドを実行
pnpm update --latest
electron-viteのrenderer用サーバーが起動しないように、electron.vite.config.tsのrenderの項目を削除します。(svelteの開発サーバーはsvelteのものを利用する)
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'; export default defineConfig({ main: { plugins: [externalizeDepsPlugin()] }, preload: { plugins: [externalizeDepsPlugin()] } // renderを削除 });
SvelteKitのセットアップ
src/renderer内の内容をすべて削除し、SvelteKitをインストールします。
cd src/renderer pnpm create svelte@latest
Where should we create your project?には「.」を入力してEnterキーを押します(renderer内にsvelteKitのプロジェクトを展開する)。その後、依存関係をインストールします。
インストールを実行
pnpm i
最新バージョンにするためにアップデートを確認
pnpm outdated
複数個別にアップデート場合は下記のように。
pnpm update package-name1 package-name2 --latest
一気に全部アップデートするには下記コマンドを実行
pnpm update --latest
Electronでは、svelteKitのserver関連の機能は使えないので、SSRを無効にしSSGするようにし、svelteKitのビルドファイルをプロジェクトルートのoutディレクトリに出力するように設定を変更します。
src/renderer/svelte.config.js
import adapter from '@sveltejs/adapter-static'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const buildDir = path.join(__dirname, '..', '..', 'out', 'renderer'); const config = { preprocess: [vitePreprocess()], kit: { adapter: adapter({ fallback: 'index.html', pages: buildDir, assets: buildDir }), prerender: { entries: [] } } }; export default config;
他のプロジェクトとポートが被らないよう、固定ポート番号を設定します。
src/renderer/vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vitest/config'; export default defineConfig({ plugins: [sveltekit()], test: { include: ['src/**/*.{test,spec}.{js,ts}'] }, server: { port: 5500 // 固定ポートを設定 } });
Electronのメインプロセスの設定変更
src/main/index.tsを開き、process.env[‘ELECTRON_RENDERER_URL’]をSvelteKitの開発用URLに変更します。
if (is.dev) { mainWindow.loadURL('http://localhost:5500'); } else { mainWindow.loadFile(join(__dirname, '../renderer/index.html')); }
package.jsonでscriptにsvelteサーバーの起動やbuild設定を追加
"scripts": { "format": "prettier --write .", "lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix", "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", "typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false", "typecheck": "pnpm run typecheck:node", "start": "electron-vite preview", "dev:sveltekit": "cd src/renderer && pnpm run dev", "dev:electron": "electron-vite dev", "dev:electronWatch": "electron-vite dev --watch", "dev": "concurrently \"pnpm run dev:sveltekit\" \"pnpm run dev:electron\"", "dev:sveltekit:win": "start cmd /k \"cd src/renderer && pnpm run dev\"", "dev:electron:win": "start cmd /k \"electron-vite dev\"", "dev:win": "pnpm run dev:sveltekit:win && pnpm run dev:electron:win", "devwatch": "concurrently \"pnpm run dev:sveltekit\" \"pnpm run dev:electronWatch\"", "build:sveltekit": "cd src/renderer && pnpm run build", "build:electron": "electron-vite build", "build": "pnpm run typecheck && pnpm run build:sveltekit && pnpm run build:electron", "postinstall": "electron-builder install-app-deps", "build:unpack": "pnpm run build && electron-builder --dir", "build:win": "pnpm run build && electron-builder --win", "build:mac": "pnpm run build && electron-builder --mac", "build:linux": "pnpm run build && electron-builder --linux" }
dev:winは、svelteとelectronのログを分けるためにそれぞれ別のウィンドウで開く場合。
deveatchは、electronのメインプロセスを変更したら自動で再起動する時用。
typecheckは、sveltekitが別になっているので、モジュール関係でtsエラーが出るのでelectron側からは行わないようにしている。
プロジェクトのビルドと実行
プロジェクトルートで開発サーバーを起動します。
pnpm run dev
ビルドの実行
pnpm run build
ビルドされたファイルはdistディレクトリ内に出力されます。
おわりに
Electronの仕組みがよくわかっていなかったので構築までかなり時間がかかった。
electronのmainプロセスとrendererプロセスは別でもOKで、Electronは、rendererプロセスで独自に立ち上げた開発サーバーのurlをmainプロセスのloadURLで読み込んでelectronブラウザで表示させているだけというのに気づいてから構築まで一気に進んだ。
Electronはchromeのようなウェブブラウザで、mainプロセスでOSとやり取りし、preloadでwindowオブジェクトに独自オブジェクトを追加してmainプロセスとrendererプロセスのやり取りをしているんだね。