デスクトップアプリのビルド手順
概要
MorningStatusApp デスクトップアプリ(Electrobun)のビルドとインストーラ・DMG 作成手順。
インストーラ/アプリバンドルには Next.js standalone サーバーが同梱されており、アプリ起動時に自動的にサーバーが立ち上がります。
前提条件
Windows
- Inno Setup 7 がインストール済みであること
winget install JRSoftware.InnoSetup.7でインストール可能- インストール先:
%LOCALAPPDATA%\Programs\Inno Setup 7\ISCC.exe
.env.local(プロジェクトルート)が存在すること(接続先 Blob URL・API キーを含む)
macOS
- Bun がインストール済みであること(
curl -fsSL https://bun.sh/install | bash) .env.local(プロジェクトルート)が存在すること(接続先 Blob URL・API キーを含む)
Windows ビルド手順(推奨:一括ビルド)
build-installer.ps1 が以下をすべて自動実行します:
DESKTOP_MODE=1で Next.js standalone ビルド- Electrobun アプリビルド
- Inno Setup でインストーラ生成
pwsh -File setup/build-installer.ps1
成果物: setup/Output/MorningStatusApp-Setup-{version}.exe
macOS ビルド手順(推奨:一括ビルド)
build-macos.sh が以下をすべて自動実行します:
DESKTOP_MODE=1で Next.js standalone ビルド- Electrobun アプリビルド(
.appバンドル生成) - Next.js standalone を
.appバンドル内にコピー
bash setup/build-macos.sh
成果物:
.appバンドル:desktop/build/dev-macos-arm64/MorningStatusApp-dev.app(Apple Silicon)- DMG:
desktop/artifacts/(Electrobun が自動生成する場合)
注意: macOS ビルドは macOS 環境で実行すること。
ビルド手順(ステップ別)
1. Next.js standalone ビルド
DESKTOP_MODE=1 bun run next build
DESKTOP_MODE=1 を指定すると next.config.ts が output: 'standalone' を有効化し、
.next/standalone/ に自己完結型サーバーが生成されます。
2. Electrobun アプリのビルド
cd desktop
bunx electrobun build
成果物:
- Windows:
desktop/build/dev-win-x64/MorningStatusApp-dev/ - macOS ARM64:
desktop/build/dev-macos-arm64/MorningStatusApp-dev.app/ - macOS Intel:
desktop/build/dev-macos-x64/MorningStatusApp-dev.app/
3a. インストーラのビルド(Windows)
pwsh -File setup/build-installer.ps1
- バージョンは root の
package.jsonから自動取得する - ISCC.exe が見つからない場合はエラーメッセージが表示される
3b. Next.js を .app バンドルにコピー(macOS)
build-macos.sh が自動実行するが、手動でも実行可能:
APP=desktop/build/dev-macos-arm64/MorningStatusApp-dev.app
RESOURCES=$APP/Contents/Resources
cp -r .next/standalone/. $RESOURCES/nextjs/standalone/
cp -r .next/static $RESOURCES/nextjs/standalone/.next/static
cp -r public $RESOURCES/nextjs/standalone/public
cp .env.local $RESOURCES/nextjs/standalone/.env.local
4. インストール
Windows: 生成した MorningStatusApp-Setup-{version}.exe を実行する。
- インストール先:
%ProgramFiles%\MorningStatusApp(ユーザーが変更可能) - スタートメニュー:
MorningStatusAppグループが作成される - アンインストール: コントロールパネル/設定からアンインストール可能
macOS: MorningStatusApp-dev.app を /Applications にコピーして起動する。
アプリを改修した場合のフロー
1. package.json のバージョンを更新する(必要な場合)
2. (Windows)pwsh -File setup/build-installer.ps1
(macOS) bash setup/build-macos.sh
起動フロー(インストール済みアプリ)
launcher.exe(Windows)/MorningStatusApp(macOS)→ Electrobun ランチャー起動bun/index.jsWorker 起動- Worker が
Resources/nextjs/standalone/server.jsを検出し、同梱のbun(またはbun.exe)で Next.js サーバーを起動 .env.local(standalone ディレクトリに配置)から接続先設定を読み込み- サーバー起動待機後、WebView ウィンドウを
http://localhost:3001で表示
インストーラに含まれるファイル
| 配置先 | 内容 |
|---|---|
{app}/bin/ |
Electrobun バイナリ(bun.exe, launcher.exe 等) |
{app}/Resources/app/bun/ |
Electrobun ワーカー (index.js) |
{app}/Resources/nextjs/standalone/ |
Next.js standalone サーバー |
{app}/Resources/nextjs/standalone/.next/static/ |
静的アセット |
{app}/Resources/nextjs/standalone/public/ |
public ディレクトリ |
{app}/Resources/nextjs/standalone/.env.local |
接続設定(Blob URL・API キー) |
バージョン管理
- Windows インストーラのバージョンは
build-installer.ps1が root のpackage.jsonから読み取り/DAppVersion=X.Y.Zとして Inno Setup に渡す - Electrobun アプリ(macOS)のバージョンは
desktop/electrobun.config.tsとdesktop/package.jsonで管理する - Windows インストーラバージョンを上げる場合: root の
package.jsonを更新 - Electrobun アプリバージョンを上げる場合:
desktop/electrobun.config.tsとdesktop/package.jsonを更新
アイコンの更新手順
アイコン素材は desktop/assets/ に配置する。
desktop/assets/
icons8-コーヒーカップ-100.png # ソース画像(Icons8)
icon.ico # Windows 用(100px PNG から生成)
icon.iconset/ # macOS 用(sharp で各サイズ生成済み)
icon_16x16.png
icon_16x16@2x.png
icon_32x32.png
icon_32x32@2x.png
icon_128x128.png
icon_128x128@2x.png
icon_256x256.png
icon_256x256@2x.png
icon_512x512.png
アイコンを差し替える場合
より高解像度のソース画像(512px 以上推奨)を入手したら、以下のスクリプトで再生成する:
# Windows(Bun): icon.ico を再生成
bun -e "
const pngPath = 'desktop/assets/<新しい画像>.png';
const icoPath = 'desktop/assets/icon.ico';
const pngData = await Bun.file(pngPath).arrayBuffer();
const pngBytes = new Uint8Array(pngData);
const buf = new ArrayBuffer(6 + 16 + pngBytes.length);
const view = new DataView(buf);
view.setUint16(0, 0, true); view.setUint16(2, 1, true); view.setUint16(4, 1, true);
view.setUint8(6, 0); view.setUint8(7, 0); view.setUint8(8, 0); view.setUint8(9, 0);
view.setUint16(10, 1, true); view.setUint16(12, 32, true);
view.setUint32(14, pngBytes.length, true); view.setUint32(18, 22, true);
new Uint8Array(buf, 22).set(pngBytes);
await Bun.write(icoPath, buf);
"
# macOS: iconset を再生成(macOS 環境で実行)
mkdir -p desktop/assets/icon.iconset
sips -z 16 16 <ソース>.png --out desktop/assets/icon.iconset/icon_16x16.png
sips -z 32 32 <ソース>.png --out desktop/assets/icon.iconset/icon_16x16@2x.png
sips -z 32 32 <ソース>.png --out desktop/assets/icon.iconset/icon_32x32.png
sips -z 64 64 <ソース>.png --out desktop/assets/icon.iconset/icon_32x32@2x.png
sips -z 128 128 <ソース>.png --out desktop/assets/icon.iconset/icon_128x128.png
sips -z 256 256 <ソース>.png --out desktop/assets/icon.iconset/icon_128x128@2x.png
sips -z 256 256 <ソース>.png --out desktop/assets/icon.iconset/icon_256x256.png
sips -z 512 512 <ソース>.png --out desktop/assets/icon.iconset/icon_256x256@2x.png
sips -z 512 512 <ソース>.png --out desktop/assets/icon.iconset/icon_512x512.png
iconutil -c icns desktop/assets/icon.iconset # .icns も生成される
注意事項
setup/Output/はリポジトリから除外(.gitignore設定済み)desktop/build//desktop/artifacts/も同様に除外済み.env.local(プロジェクトルート)には API キー等が含まれるため、インストーラに同梱されるファイルを公開しないこと