Skip to content

Commit bff3686

Browse files
committed
garotm - prep for .exe creation.
1 parent b2f28e8 commit bff3686

8 files changed

Lines changed: 396 additions & 95 deletions

File tree

.github/workflows/release.yml

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
name: Release — Windows installer
2+
3+
# Triggers on version tags (e.g. v0.2.0) or manual dispatch for testing.
4+
on:
5+
push:
6+
tags:
7+
- "v[0-9]+.[0-9]+.[0-9]+"
8+
workflow_dispatch:
9+
inputs:
10+
tag:
11+
description: "Version tag (e.g. v0.1.0)"
12+
required: false
13+
default: "dev-build"
14+
15+
concurrency:
16+
group: release-${{ github.ref }}
17+
cancel-in-progress: true
18+
19+
jobs:
20+
build-windows:
21+
name: Build Windows installer
22+
runs-on: windows-latest
23+
24+
steps:
25+
# ── Checkout ────────────────────────────────────────────────────────────
26+
- uses: actions/checkout@v4
27+
28+
# ── Node.js ─────────────────────────────────────────────────────────────
29+
- uses: actions/setup-node@v4
30+
with:
31+
node-version: "18" # pkg targets node18-win-x64; keep in sync
32+
cache: npm
33+
cache-dependency-path: |
34+
package-lock.json
35+
frontend/package-lock.json
36+
backend/package-lock.json
37+
38+
# ── Install all npm deps ─────────────────────────────────────────────────
39+
- name: Install root deps
40+
run: npm ci
41+
42+
- name: Install frontend deps
43+
run: npm ci
44+
working-directory: frontend
45+
46+
- name: Install backend deps
47+
run: npm ci
48+
working-directory: backend
49+
50+
# ── Build frontend ───────────────────────────────────────────────────────
51+
- name: Build frontend
52+
run: npm run build
53+
working-directory: frontend
54+
55+
# ── Bundle backend sidecar with pkg ──────────────────────────────────────
56+
- name: Build backend sidecar
57+
run: npm run package
58+
working-directory: backend
59+
60+
- name: Verify sidecar binary exists
61+
shell: pwsh
62+
run: |
63+
$bin = "src-tauri\binaries\sift-backend-x86_64-pc-windows-msvc.exe"
64+
if (-not (Test-Path $bin)) {
65+
Write-Error "Sidecar binary not found: $bin"
66+
exit 1
67+
}
68+
Write-Host "Sidecar OK: $bin ($([Math]::Round((Get-Item $bin).Length / 1MB, 1)) MB)"
69+
70+
# ── Rust / Tauri ─────────────────────────────────────────────────────────
71+
- uses: dtolnay/rust-toolchain@stable
72+
73+
- uses: Swatinem/rust-cache@v2
74+
with:
75+
workspaces: src-tauri
76+
77+
- name: Build Tauri installer
78+
env:
79+
CI: "false" # prevent Tauri CLI from misreading CI=1
80+
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
81+
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
82+
run: npx tauri build
83+
working-directory: .
84+
85+
# ── Collect artifacts ────────────────────────────────────────────────────
86+
- name: Find installer files
87+
shell: pwsh
88+
run: |
89+
Get-ChildItem -Recurse src-tauri\target\release\bundle `
90+
-Include "*.exe","*.msi" |
91+
Select-Object FullName, Length |
92+
Format-Table
93+
94+
- name: Upload NSIS installer
95+
uses: actions/upload-artifact@v4
96+
with:
97+
name: Sift-Windows-installer-${{ github.ref_name }}
98+
path: |
99+
src-tauri/target/release/bundle/nsis/*.exe
100+
src-tauri/target/release/bundle/msi/*.msi
101+
if-no-files-found: warn
102+
retention-days: 30
103+
104+
# ── GitHub Release (tags only) ───────────────────────────────────────────
105+
- name: Create GitHub Release
106+
if: startsWith(github.ref, 'refs/tags/')
107+
uses: softprops/action-gh-release@v2
108+
with:
109+
files: |
110+
src-tauri/target/release/bundle/nsis/*.exe
111+
src-tauri/target/release/bundle/msi/*.msi
112+
generate_release_notes: true
113+
env:
114+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

backend/package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@
99
"build": "tsc -p tsconfig.build.json",
1010
"test": "jest --coverage --forceExit",
1111
"test:watch": "jest --watch",
12-
"package": "npm run build && pkg package.json --output ../src-tauri/binaries/sift-backend"
12+
"package": "npm run build && pkg package.json --no-bytecode --public --public-packages \"*\" --output ../src-tauri/binaries/sift-backend-x86_64-pc-windows-msvc"
1313
},
1414
"pkg": {
15-
"assets": [],
15+
"assets": [
16+
"node_modules/better-sqlite3/build/Release/*.node",
17+
"node_modules/better-sqlite3/prebuilds/**/*"
18+
],
1619
"targets": [
1720
"node18-win-x64"
1821
],

docs/BUILD-AND-RELEASE.md

Lines changed: 118 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,158 @@
11
# Build and release
22

3-
This document covers **production builds**, **Windows installers**, and optional **bundled sidecars** (`sift-backend`, `llama-server`).
3+
This document covers **production builds**, **Windows installers**, the **Node.js
4+
backend sidecar**, and the **GitHub Actions release workflow**.
45

56
## Development vs production
67

7-
| Mode | UI | Backend | Tauri |
8-
| --------------- | --------------- | -------------------- | ---------------------------------------- |
9-
| `npm run dev` | Vite on :1420 | `ts-node` | `tauri dev` |
10-
| `npm run build` | `frontend/dist` | `backend/dist` (tsc) | `tauri build` release binary + installer |
8+
| Mode | UI | Backend | Tauri |
9+
| ---- | -- | ------- | ----- |
10+
| `node sift.mjs run` | Vite on :1420 | `ts-node` (runs separately) | `tauri dev` — connects to Vite |
11+
| `tauri build` (release) | `frontend/dist` embedded | `sift-backend-*.exe` sidecar | Full native bundle + NSIS installer |
1112

12-
## Root production build
13+
In **development** the backend is a separate process you manage via `npm start`.
14+
In **production** Tauri spawns the pre-bundled backend sidecar automatically on
15+
startup and kills it when the app exits.
16+
17+
---
18+
19+
## Step-by-step: build a Windows installer locally
20+
21+
> You need a **Windows machine** (or `windows-latest` CI runner) for the final
22+
> `tauri build` step. The backend sidecar must be compiled targeting Windows.
23+
24+
### 1. Install all dependencies
25+
26+
```bash
27+
node sift.mjs deps
28+
```
29+
30+
### 2. Bundle the backend sidecar
31+
32+
```bash
33+
node sift.mjs package
34+
# or: cd backend && npm run package
35+
```
36+
37+
This runs `tsc` then `pkg` and writes:
38+
39+
```powershell
40+
src-tauri/binaries/sift-backend-x86_64-pc-windows-msvc.exe
41+
```
42+
43+
Tauri requires the binary to end with the Rust target triple. `pkg` bundles
44+
Node.js 18 + all JS/TS dependencies into a single `.exe`.
45+
46+
> **`better-sqlite3` note:** `pkg` bundles the prebuilt `.node` native addon as
47+
> an asset (configured in `backend/package.json` under `pkg.assets`). If the
48+
> build fails on a native module, make sure `npm ci` ran in `backend/` first so
49+
> the correct Windows prebuilt is present in `node_modules`.
50+
51+
### 3. Build the frontend
1352

1453
```bash
1554
npm run build --prefix frontend
16-
npm run build --prefix backend
55+
```
56+
57+
### 4. Run `tauri build`
58+
59+
```bash
1760
cross-env CI=false npx tauri build
1861
```
1962

20-
The root `npm run build` runs the same steps. **`CI=false`** avoids a known issue where `CI=1` in some environments makes the Tauri CLI reject `--ci` parsing.
63+
Or from the root:
64+
65+
```bash
66+
npm run build
67+
```
68+
69+
The NSIS installer is written to:
70+
71+
```powershell
72+
src-tauri/target/release/bundle/nsis/Sift_<version>_x64-setup.exe
73+
```
2174

22-
Artifacts (paths vary by OS):
75+
---
2376

24-
- **macOS:** `.app`, `.dmg` (if configured)
25-
- **Windows:** `.exe` installer (NSIS per `tauri.conf.json`)
77+
## GitHub Actions — automated Windows release
2678

27-
See `src-tauri/tauri.conf.json``bundle` for targets (`nsis`, icons, etc.).
79+
Workflow: [`.github/workflows/release.yml`](../.github/workflows/release.yml)
2880

29-
## Node sidecar with `pkg`
81+
### Triggering a release
3082

31-
The backend can be compiled to a standalone executable for bundling next to the Tauri app:
83+
Push a version tag:
3284

3385
```bash
34-
cd backend
35-
npm run build
36-
npm run package
86+
git tag v0.2.0
87+
git push origin v0.2.0
3788
```
3889

39-
This uses **`pkg`** and writes output under `src-tauri/binaries/` (see `backend/package.json`). Targets are Windows-oriented by default; adjust `pkg` `targets` for other platforms if needed.
90+
The `release.yml` workflow runs on `windows-latest` and:
91+
92+
1. Installs Node 18 + all npm deps
93+
2. Builds frontend (`vite build`)
94+
3. Bundles backend sidecar with `pkg``src-tauri/binaries/`
95+
4. Verifies the `.exe` exists and prints its size
96+
5. Runs `npx tauri build` (with `CI=false`)
97+
6. Uploads the NSIS `.exe` as a **GitHub Release asset** (auto-generated release notes)
98+
7. Also saves the installer as a workflow **artifact** (30-day retention) for non-tag builds
4099

41-
## `llama-server` and `externalBin`
100+
### Manual test build (no tag needed)
42101

43-
For a fully offline setup, bundle **llama.cpp** `llama-server` (or your chosen inference binary) and register it in Tauri:
102+
Go to **Actions → Release — Windows installer → Run workflow** on GitHub and trigger
103+
it manually. The installer will be available as a downloadable artifact.
44104

45-
1. Place binaries under `src-tauri/binaries/` with names expected by Tauri (see [Tauri external binaries](https://v2.tauri.app/develop/sidecar/)).
46-
2. Set `bundle.externalBin` in `src-tauri/tauri.conf.json`.
47-
3. Match **capabilities** for `shell` / sidecar spawn if you launch them from Rust.
105+
### Optional: code-signing
48106

49-
The repository ships with **`externalBin`: []** so local development does not require those files. Enable them when you are ready to ship Windows installers.
107+
Set these repository secrets to sign the installer:
108+
109+
| Secret | Value |
110+
| ------ | ----- |
111+
| `TAURI_SIGNING_PRIVATE_KEY` | PEM-encoded private key from `tauri signer generate` |
112+
| `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | Key password (can be empty) |
113+
114+
Unsigned builds work fine for internal distribution but Windows Defender SmartScreen
115+
will warn users on first run.
116+
117+
---
118+
119+
## Sidecar lifecycle (production)
120+
121+
The Rust code in `src-tauri/src/lib.rs` handles the backend sidecar automatically:
122+
123+
- **Startup** (`setup()`): spawns `sift-backend` and polls `GET /health` for up to
124+
15 seconds before the UI loads.
125+
- **Tray → Quit**: kills the child process before calling `app.exit(0)`.
126+
- **Dev builds** (`cargo build` / `tauri dev`): sidecar code is compiled out via
127+
`#[cfg(not(debug_assertions))]` — the backend runs separately as usual.
128+
129+
---
50130

51131
## Icons
52132

53-
Icons are generated from `img/sift-icon.svg`:
133+
Regenerate all icon sizes from the master SVG:
54134

55135
```bash
56136
cd src-tauri
57137
npx @tauri-apps/cli icon ../img/sift-icon.svg
58138
```
59139

140+
---
141+
60142
## Version bumps
61143

62-
- **`package.json`** (root, frontend, backend) — semantic version for JS packages.
63-
- **`src-tauri/tauri.conf.json`**`version` for the bundled app.
64-
- **`src-tauri/Cargo.toml`**`version` for the Rust crate (keep in sync with Tauri config for clarity).
144+
Update all three in sync before tagging:
145+
146+
| File | Field |
147+
| ---- | ----- |
148+
| `src-tauri/tauri.conf.json` | `"version"` |
149+
| `src-tauri/Cargo.toml` | `version` |
150+
| Root `package.json` | `"version"` |
151+
152+
---
65153

66154
## Related docs
67155

68156
- [Installation](INSTALLATION.md)
69-
- [Transform summary](Transform-Summary.md)
157+
- [Development](DEVELOPMENT.md)
158+
- [Configuration](CONFIGURATION.md)

0 commit comments

Comments
 (0)