# OctoLauncher Build Guide (Windows) End-to-end setup that gets `npm run dev` and `npm run dist` working on a fresh Windows machine. Captured from a working build on Windows 10 / April 2026. ## Changes made to the dev environment The project as checked out does **not** build on a default up-to-date Windows dev machine. These are the deltas applied to get it working, in order: 1. **Added a Node version manager (`fnm`) and installed Node 20** alongside the existing Node 24. Node 24 was the system default and caused `nan` / `dll-inject` compile failures. Node 20 is now the fnm default but Node 24 is still available via `fnm use system`. 2. **Installed Visual Studio 2022 Build Tools** with the `VCTools` workload and Windows 11 SDK. Machine already had VS2026 (v18), but `node-gyp` v10 (shipped with Node 20's npm) doesn't detect it. VS2022 now lives side-by-side under `C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools`. 3. **Unset `ELECTRON_RUN_AS_NODE`** per-shell before launching Electron. This var is set globally by VSCode's integrated terminal (inherited from the extension host) — it is not something we can remove permanently without breaking VSCode. It has to be unset in each shell that runs `npm run dev` / `dist`. 4. **Populated `node_modules`** in both `main/` and `main/server/`. The tree was checked in empty. Nothing in the repo itself was modified — all fixes were environmental. If another developer checks this repo out, they need to apply items 1–4 on their own machine. The sections below are that recipe. --- ## Prerequisites ### 1. Node.js 20 (not 22, not 24) Node 24 breaks the `dll-inject` native module — its `nan` C++ bindings don't compile against V8 in Node 22+. Stick to Node 20 LTS. Install via `fnm` so you can keep your system Node separate: ```bash winget install Schniz.fnm --accept-source-agreements --accept-package-agreements fnm install 20 fnm default 20 ``` Verify: `node -v` should print `v20.x.x`. ### 2. Visual Studio 2022 Build Tools (C++ workload) `dll-inject` and `stormlib-node` compile native addons via `node-gyp`. `node-gyp` v10 (bundled with Node 20's npm) only recognizes VS2017–2022 — newer VS versions (2026 / v18) are not detected. ```bash winget install Microsoft.VisualStudio.2022.BuildTools \ --accept-source-agreements --accept-package-agreements \ --override "--wait --passive --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.22621 --includeRecommended" ``` ~6 GB download, requires admin. Even if you already have VS2026, you need VS2022 side-by-side for node-gyp. ### 3. Python 3 (usually already present) `node-gyp` needs Python on PATH. Any 3.x works. ## Install dependencies From the repo root: ```bash npm install --ignore-scripts node node_modules/electron/install.js node_modules/.bin/electron-builder.cmd install-app-deps ``` Why the three-step approach: `dll-inject` requires ClangCL if compiled against the system Node, but compiles fine against Electron's bundled V8 headers (which `electron-builder install-app-deps` uses). Running plain `npm install` fails if your VS2022 installation doesn't include the LLVM/ClangCL component; `--ignore-scripts` skips that step and lets `install-app-deps` handle it correctly. Or, use the provided build script which downloads a portable Node 20 and handles everything automatically: ```powershell .\Tools\launcher\install.ps1 ``` Then the server (only needed if running a local CDN, see `server/.env.example`): ```bash cd server npm install cd .. ``` ## Critical env var: `ELECTRON_RUN_AS_NODE` **VSCode's integrated terminal sets `ELECTRON_RUN_AS_NODE=1`** (inherited from VSCode's extension host). This makes Electron binaries launch as plain Node, so `require('electron')` returns a path string instead of the API — the app crashes with `TypeError: Cannot read properties of undefined (reading 'isPackaged')`. Before any `npm run dev` / `npm run build` / `npm run dist`: ```bash unset ELECTRON_RUN_AS_NODE ``` ```powershell Remove-Item Env:ELECTRON_RUN_AS_NODE ``` An external terminal (Windows Terminal, cmd, plain PowerShell) doesn't have this problem — the variable is only set inside VSCode. ## Running in dev ```bash npm run dev ``` Starts electron-vite, builds main + preload + renderer, opens an Electron window on `http://localhost:5173` (or `5174` if 5173 is taken). Closing the window ends the session. You'll see benign warnings in the console: - `ERROR:cache_util_win.cc ... Access is denied` — OneDrive sync locking Electron's user-data cache. Cosmetic. To silence, move the project out of OneDrive or set a custom user-data dir. - `Browserslist: caniuse-lite is outdated` — cosmetic. ## Building for distribution The `dist` script runs `tsc && npm run build && npm run pack`: ```bash unset ELECTRON_RUN_AS_NODE npm run dist ``` Outputs land in `dist/`: - `OctoLauncher.exe` — portable single-file build - `OctoLauncher_Installer.exe` — NSIS installer Targets are configured in [electron-builder.yml](electron-builder.yml). ### Before publishing - The build uses `.env.production` (committed) which already points to `https://octowow.st` — no `.env` file needed for production builds. - Code signing is not configured. Unsigned Windows builds trigger SmartScreen warnings. To sign, add a `win.certificateFile` + password (or use env-based signing) to the electron-builder config. ## Troubleshooting | Symptom | Cause | Fix | |---|---|---| | `nan_scriptorigin.h ... cannot convert 'v8::Isolate *'` during `npm install` | Node 22+ breaks `nan` | Switch to Node 20 | | `gyp ERR! find VS Could not find any Visual Studio installation` | Only VS2023+ installed | Install VS2022 Build Tools | | `error MSB8020: The build tools for ClangCL cannot be found` | Missing LLVM component during plain `npm install` | Use `npm install --ignore-scripts` + `electron-builder install-app-deps` (see above) | | `TypeError: Cannot read properties of undefined (reading 'isPackaged')` at launch | `ELECTRON_RUN_AS_NODE=1` set by VSCode | `unset ELECTRON_RUN_AS_NODE` | | `Port 5173 is in use` | Prior dev server didn't exit cleanly | Ignore (vite falls back to 5174) or kill the stale process |