docs: document Windows build and packaging

This commit is contained in:
yonglin
2026-09-17 16:25:55 +08:00
parent b9098ece5c
commit 2697bff24d
2 changed files with 105 additions and 38 deletions
+63 -24
View File
@@ -2,7 +2,7 @@
**English** · [中文](README.zh-CN.md)
A desktop SSH session manager for Linux — connection tree, tabbed terminals,
A desktop SSH session manager for Windows and Linux — connection tree, tabbed terminals,
tunnels, local shell and serial.
Think Xshell's session management with tmux's multiplexing, local-first: your
@@ -28,7 +28,24 @@ Early. Everything below reflects what actually works today.
## Prerequisites
### Build toolchain (for native modules)
### Windows
Node.js 22.12 or newer is required. The dependencies ship Windows x64/ARM64
prebuilds for `better-sqlite3` and `node-pty`, so Visual Studio is normally not
required. If `npm install` still falls back to `node-gyp`, use the verified
no-compile installation path:
```powershell
npm ci --ignore-scripts
node node_modules/electron/install.js
```
With this path, `ssh2` uses its JavaScript crypto implementation. Functionality
is unchanged, but the optional native acceleration is absent. To compile every
optional native module, install Python 3 and Visual Studio Build Tools with the
Desktop development with C++ workload.
### Linux build toolchain (for native modules)
```sh
sudo apt install build-essential python3 pkg-config libudev-dev
@@ -39,7 +56,8 @@ M8, but installing it up front avoids a confusing build failure later.
### Runtime keyring
Credential storage depends on an OS keyring daemon. Verify one is running:
Windows uses DPAPI and needs no additional keyring service. On Linux,
credential storage depends on an OS keyring daemon. Verify one is running:
```sh
ps -e -o comm= | grep -E 'gnome-keyring|kwalletd'
@@ -82,7 +100,8 @@ Other scripts:
npm test # vitest — see "Testing" below
npm run typecheck # main/preload and renderer are checked separately
npm run build # production bundles into out/
npm run dist # AppImage + deb into release/
npm run dist # package for the current platform into release/
npm run dist:win # explicitly build the Windows x64 NSIS installer
npm run rebuild:native # rebuild native modules against Electron's ABI
```
@@ -119,6 +138,12 @@ npm run build
npm run smoke
```
On Windows PowerShell, replace the second line with:
```powershell
.\node_modules\electron\dist\electron.exe --remote-debugging-port=9222 .
```
`scripts/ipc-smoke.mjs` attaches to the running app over the Chrome DevTools
Protocol and calls `window.nexusterm` — the same object the UI calls. That makes
it a real end-to-end check of preload bridge → `ipcRenderer.invoke` → handler →
@@ -127,7 +152,8 @@ UI by hand.
It currently verifies folder and host creation, nesting, rename, moving to the
root layer, refusal of a folder move into its own descendant, rejection of an
invalid payload, and that it cleans up after itself.
invalid payload, opening and closing a local PTY, and that it cleans up after
itself.
### SSH, against a real server
@@ -156,39 +182,49 @@ remote wrote — which is the return path proven separately.
## Packaging
```sh
npm run dist # AppImage + deb into release/
npm run dist # package for the current platform into release/
npm run dist:win # Windows x64 NSIS installer into release/
npm run verify:package # check the result can actually run
```
The Windows installer is written to `release/NexusTerm-<version>-x64.exe`. The
uninstalled layout is kept in `release/win-unpacked/` for quick testing before
running the installer.
`scripts/verify-package.mjs` exists because a package that is broken in the
ways that matter still builds, still installs, and still starts. Native modules
cannot be loaded from inside an asar archive, and when they are left there the
failure appears on a user's machine the first time they open a terminal — not
in CI, and not in `npm test`. So the script extracts the AppImage and asserts
that each native binary really is in `app.asar.unpacked`.
in CI, and not in `npm test`. The script checks a Linux AppImage or the Windows
`win-unpacked` directory and asserts that each current-platform native binary
really is in `app.asar.unpacked`.
Two things it checks that are easy to get wrong:
- **`ssh2` carries a native module.** `sshcrypto.node` is easy to miss because
the library reads as pure JavaScript — and because a failed load falls back
to a JS implementation silently, so nothing would ever report it.
- **`node-pty` must be unpacked whole, not just its `.node` files.** On macOS
and Windows it ships `spawn-helper`, a real executable loaded from disk rather
than `dlopen`ed, which stays trapped in the archive if only `*.node` is
unpacked.
- **`ssh2` carries an optional native module.** `sshcrypto.node` is easy to miss
because the library reads as pure JavaScript. A no-compile Windows install
warns when it is absent and uses the JS implementation.
- **`node-pty` must be unpacked whole, not just its `.node` files.** Windows
also needs `winpty-agent.exe`, `OpenConsole.exe`, and their DLLs; unpacking
only `*.node` produces a terminal that fails after installation.
`npmRebuild` is off: every native module here is built on `node-addon-api`, so
the binaries from `npm install` load unchanged in Electron's Node. Rebuilding
would cost time and risk replacing working binaries for no gain.
Both `.deb` metadata and `desktopName` are set, and the AppImage's
`.desktop` entry is generated from `linux.desktop.entry`.
`.desktop` entry is generated from `linux.desktop.entry`. Windows uses an NSIS
installer with a selectable install directory plus Start menu and desktop
shortcuts.
### Packaging notes for whoever picks this up
- The `author`, `homepage` and `maintainer` fields are **placeholders**
(`ylhan@example.com`, `example.com`). They are required by the deb format and
must be replaced before distributing.
- The Windows installer is currently **not digitally signed**, so SmartScreen
may report an unknown publisher. Configure a code-signing certificate before
public distribution.
- `asarUnpack` lists `node_modules/@serialport/**` for a backend that does not
exist yet. Harmless now; load-bearing once the serial transport lands.
@@ -224,7 +260,8 @@ need a module declaration — `"types": ["vite/client"]` supplies it.
**`better-sqlite3` ships N-API prebuilds.**
`node_modules/better-sqlite3/prebuilds/` contains `linux-x64.node` and friends,
`node_modules/better-sqlite3/prebuilds/` contains `linux-x64.node`,
`win32-x64.node`, and friends,
built with `node-addon-api`. Because N-API is ABI-stable across Node and Electron
versions, this normally removes the need for an `electron-rebuild` step. If a
native load ever fails at runtime, check here first before reaching for a
@@ -232,7 +269,8 @@ rebuild.
**The Electron binary may need a manual download.**
If `npm install` completes but `node_modules/electron/dist/electron` is missing,
If `npm install` completes but `node_modules/electron/dist/electron` (or
`electron.exe` on Windows) is missing,
the package's postinstall was skipped. Run:
```sh
@@ -350,13 +388,14 @@ multi-byte sequences across reads rather than mangling them. Re-encoding with
uniform — everything above speaks bytes.
**node-pty needs no rebuild against Electron.** It is built on `node-addon-api`,
so the binary compiled during `npm install` loads unchanged in Electron's Node —
verified by spawning a real PTY from inside Electron 44. This retired what the
plan had ranked as the project's highest risk.
so the binary selected or compiled during dependency installation loads
unchanged in Electron's Node — verified by spawning a real PTY from inside
Electron 44. This retired what the plan had ranked as the project's highest
risk.
On Linux there is also no `spawn-helper`: that exists only for macOS and
Windows. The `asarUnpack` rule covers the whole package anyway, so the
executable surviving the asar boundary is handled without a special case.
Linux has no additional terminal helper executable. The Windows prebuilds carry
`winpty-agent.exe` and `OpenConsole.exe`; the `asarUnpack` rule covers the whole
package so both survive the asar boundary.
### The sidebar, and where sessions live