fix(web): bundle deps into the server (noExternals) — kill the 47k-file install
apple / swift (push) Successful in 1m0s
ci / rust (push) Successful in 1m18s
ci / web (push) Successful in 43s
ci / docs-site (push) Successful in 1m4s
android / android (push) Successful in 3m26s
deb / build-publish (push) Successful in 2m37s
apple / screenshots (push) Successful in 5m9s
decky / build-publish (push) Successful in 14s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 25s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
windows-host / package (push) Successful in 6m51s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
ci / bench (push) Successful in 4m35s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 47s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 9m3s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 9m8s
docker / deploy-docs (push) Successful in 19s

The Windows installer ballooned to 154 MB and installed forever because the node-server
bundle externalized the WHOLE @unom/ui dependency tree (payload, lexical, date-fns,
prismjs…) to .output/server/node_modules — 47,567 files / 730 MB copied into Program
Files. Set Nitro `noExternals: true` so every dependency is bundled + tree-shaken into the
server output: .output drops to ~75 files / 10 MB, and the bare external imports
(srvx, seroval…) bun couldn't resolve at runtime are gone — so the console runs on bun
(no node, no node_modules), which is the issue we previously worked around with node.

Windows installer now ships bun.exe + the ~75-file .output (was node.exe + a node_modules
forest) and runs `bun .output\server\index.mjs`:
- windows-host.yml: fetch a pinned portable bun (build tool AND shipped runtime); drop the
  node fetch + the .output/server install; smoke-boot under the bundled bun.
- pack-host-installer.ps1 / punktfunk-host.iss: -NodeExe -> -BunExe; stage {app}\bun\bun.exe.
- web-run.cmd / build-web.ps1: run/restart on bun; docs updated.

Net win everywhere: the Linux .deb shrinks (node still runs the self-contained output), and
the docker web image — which already ran `bun run .output/server/index.mjs` with only
.output copied — is fixed (the externals had no node_modules to resolve at runtime).

Validated locally: noExternals build = 75 files / 10 MB; node AND bun both serve /login
(200) + static assets (200) + gate /api (401).

(A true single binary via `bun build --compile` is blocked for now: Nitro serves public
assets from an import.meta-relative path `--compile` doesn't embed (/$bunfs/public); the
75-file payload is the clean result.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-22 21:18:31 +02:00
parent e4e34fdb48
commit de232ec2f7
10 changed files with 77 additions and 87 deletions
+24 -37
View File
@@ -1,7 +1,7 @@
# Build the punktfunk Windows HOST as a signed Inno Setup installer and publish it to Gitea's generic
# package registry, so a Windows GPU box can install the streaming host (SYSTEM service + bundled
# SudoVDA virtual-display driver + the web management console, run by a scheduled task on a bundled
# Node) from one signed setup.exe. Runs on the self-hosted Windows runner
# bun) from one signed setup.exe. Runs on the self-hosted Windows runner
# (host mode; scripts/ci/setup-windows-runner.ps1) — same MSVC/Windows-SDK/LLVM env as windows.yml.
#
# Why an installer and not MSIX (like the client): the host installs a LocalSystem SCM service that
@@ -104,46 +104,36 @@ jobs:
choco install innosetup -y --no-progress
}
- name: Fetch portable Node runtime (bundled to run the console)
- name: Fetch portable bun runtime (build tool + bundled to run the console)
shell: pwsh
run: |
# The installer ships a self-contained node.exe so the web console runs with no system-Node
# prerequisite. Pinned LTS (>= 20, matching the punktfunk-web .deb's `nodejs (>= 20)`); the
# smoke test below validates the .output bundle runs under exactly this node before shipping.
$ver = 'v22.11.0'
$url = "https://nodejs.org/dist/$ver/node-$ver-win-x64.zip"
# ONE pinned bun, used both to BUILD the console and shipped in the installer to RUN it. The
# .output is self-contained (Nitro noExternals — deps bundled + tree-shaken, no node_modules),
# so the installer ships just bun + a ~75-file .output instead of node + a node_modules forest.
$ver = 'bun-v1.3.14'
$url = "https://github.com/oven-sh/bun/releases/download/$ver/bun-windows-x64.zip"
New-Item -ItemType Directory -Force -Path C:\t | Out-Null
$zip = 'C:\t\node.zip'; $dst = 'C:\t\nodedist'
$zip = 'C:\t\bun.zip'; $dst = 'C:\t\bundist'
Invoke-WebRequest -Uri $url -OutFile $zip
if (Test-Path $dst) { Remove-Item $dst -Recurse -Force }
Expand-Archive -Path $zip -DestinationPath $dst -Force
$node = (Get-ChildItem -Path $dst -Recurse -Filter node.exe | Select-Object -First 1).FullName
if (-not $node) { throw "node.exe not found in $url" }
"NODE_EXE=$node" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
& $node --version
$bun = (Get-ChildItem -Path $dst -Recurse -Filter bun.exe | Select-Object -First 1).FullName
if (-not $bun) { throw "bun.exe not found in $url" }
"BUN_EXE=$bun" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
& $bun --version
- name: Build + smoke-boot web console (node-server preset)
- name: Build + smoke-boot web console (bun)
shell: pwsh
env:
# PAT with read access to the unom org packages — the @unom npm registry needs auth.
# PAT with read access to the unom org packages — the @unom npm registry needs auth to BUILD.
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
# Same shape as deb.yml: bun builds the Nitro node-server bundle, node runs it; the installer
# bundles web\.output (handed over via WEB_OUTPUT_DIR) + the portable node above. The runner
# runs as SYSTEM (no dev-user PATH/npmrc), so bootstrap bun if absent and supply the private
# @unom registry token via the SYSTEM home .npmrc kept OUT of the shipped bundle.
# The bun fetched above builds the Nitro server AND runs it. noExternals (vite.config) makes the
# output self-contained, so there's no .output/server install — the installer ships bun + the
# ~75-file .output. The runner is SYSTEM with no ~/.npmrc, so supply the private @unom token in
# the SYSTEM home .npmrc to BUILD (kept OUT of the shipped bundle — web\.npmrc has only the
# registry mapping, and nothing copies it into .output).
run: |
$bun = (Get-Command bun -ErrorAction SilentlyContinue).Source
if (-not $bun) { foreach ($p in @("$env:USERPROFILE\.bun\bin\bun.exe", 'C:\Users\Public\bun\bin\bun.exe')) { if (Test-Path $p) { $bun = $p; break } } }
if (-not $bun) {
Write-Output "bun not found - installing via bun.sh"
Invoke-RestMethod https://bun.sh/install.ps1 | Invoke-Expression
$bun = Join-Path $env:USERPROFILE '.bun\bin\bun.exe'
}
if (-not (Test-Path $bun)) { throw "bun unavailable (install failed?): $bun" }
& $bun --version
# @unom is a private Gitea npm registry. The committed web\.npmrc has only the registry
# mapping; put the mapping + auth token in the SYSTEM home .npmrc so the token never lands in
# the shipped bundle (.output\server\.npmrc stays the clean mapping-only copy).
$bun = $env:BUN_EXE
if ($env:REGISTRY_TOKEN) {
$rc = Join-Path $env:USERPROFILE '.npmrc'
Add-Content -Path $rc -Value '@unom:registry=https://git.unom.io/api/packages/unom/npm/'
@@ -155,19 +145,16 @@ jobs:
if (Select-String -Path .output\server\index.mjs -Pattern 'Bun\.serve' -Quiet) {
throw "web build is a bun bundle (Bun.serve) - need the node-server preset"
}
# Externalized @unom SSR deps must be installed inside .output\server (registry mapping via .npmrc).
Copy-Item .npmrc .output\server\.npmrc -Force
Push-Location .output\server; & $bun install; if ($LASTEXITCODE) { throw ".output/server dep install failed ($LASTEXITCODE)" }; Pop-Location
Pop-Location
# Gate the installer on a real node boot serving /login (the runtime the installer ships).
# Gate the installer on a real boot under the BUNDLED bun (the runtime it ships), serving /login.
$env:PORT = '3009'; $env:HOST = '127.0.0.1'; $env:PUNKTFUNK_UI_PASSWORD = 'ci'
$server = (Resolve-Path 'web\.output\server\index.mjs').Path
$p = Start-Process -FilePath $env:NODE_EXE -ArgumentList $server -PassThru -WindowStyle Hidden
$p = Start-Process -FilePath $bun -ArgumentList $server -PassThru -WindowStyle Hidden
Start-Sleep -Seconds 4
try { $code = (Invoke-WebRequest -Uri 'http://127.0.0.1:3009/login' -UseBasicParsing -TimeoutSec 10).StatusCode } catch { $code = 0 }
Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue
Write-Output "web console smoke: /login -> $code"
if ($code -ne 200) { throw "web console failed to boot under node" }
Write-Output "web console smoke (bun): /login -> $code"
if ($code -ne 200) { throw "web console failed to boot under bun" }
"WEB_OUTPUT_DIR=$((Resolve-Path 'web\.output').Path)" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
- name: Pack + sign installer
+1 -1
View File
@@ -33,7 +33,7 @@ and the CLI `punktfunk-host service install` path) are in
[`packaging/windows`](https://git.unom.io/unom/punktfunk/src/branch/main/packaging/windows/README.md).
The installer also sets up the **web management console** (status, paired devices, the PIN pairing
flow): it bundles the console plus its own Node runtime and runs it as the **`PunktfunkWeb`** service
flow): it bundles the console plus its own bun runtime and runs it as the **`PunktfunkWeb`** service
on **`http://<this-PC>:3000`**, starting at boot. During setup you choose the console **login
password** (pre-filled with a secure random default and shown again on the final page); change it
later in `%ProgramData%\punktfunk\web-password`. Open the console from any browser on the LAN and log
+8 -7
View File
@@ -33,11 +33,12 @@ exe into `C:\Program Files\punktfunk\` and calls that subcommand, elevated.
display without it).
- Runs `punktfunk-host service install` (idempotent; writes a default `host.env` only if absent, so
user config survives upgrades) and, by the *Start service now* task, `service start`.
- **Web management console** (bundled when packed with `-WebDir`/`-NodeExe`, which the CI always is):
lays down the built `.output` server + a portable Node, prompts for a console login password
(pre-filled with a secure random default, shown again on the final page; kept on upgrade), then
`web-setup.ps1` writes the ACL'd `%ProgramData%\punktfunk\web-password`, registers the
**`PunktfunkWeb`** scheduled task (boot, SYSTEM, restart-on-failure → `web-run.cmd``node` on
- **Web management console** (bundled when packed with `-WebDir`/`-BunExe`, which the CI always is):
lays down the built **self-contained** `.output` server (Nitro `noExternals` — deps bundled +
tree-shaken, ~75 files, no `node_modules`) + a portable **bun**, prompts for a console login
password (pre-filled with a secure random default, shown again on the final page; kept on upgrade),
then `web-setup.ps1` writes the ACL'd `%ProgramData%\punktfunk\web-password`, registers the
**`PunktfunkWeb`** scheduled task (boot, SYSTEM, restart-on-failure → `web-run.cmd``bun` on
`:3000`), opens TCP 3000, and starts it. It proxies the host's loopback mgmt API with the host's
own `%ProgramData%\punktfunk\mgmt-token`.
- **Upgrade:** stops a running `PunktfunkHost` service and waits for `STOPPED` before replacing files
@@ -63,10 +64,10 @@ read it from `%ProgramData%\punktfunk\web-password`.
| File | Role |
|------|------|
| `punktfunk-host.iss` | Inno Setup script (the installer definition). |
| `pack-host-installer.ps1` | Orchestrator: cert + sign, stage the driver + FFmpeg + **web console** (`.output` + node) bundles, run ISCC, sign setup.exe, emit registry paths. |
| `pack-host-installer.ps1` | Orchestrator: cert + sign, stage the driver + FFmpeg + **web console** (`.output` + bun) bundles, run ISCC, sign setup.exe, emit registry paths. |
| `stage-sudovda.ps1` | Stage the **vendored** SudoVDA driver + fetch/verify the **pinned** nefcon release into the bundle. |
| `install-sudovda.ps1` | Runs at install time (elevated): trust cert → gated device-node create → `pnputil` install. |
| `../../scripts/windows/web-run.cmd` | The `PunktfunkWeb` task action: loads the mgmt token + login password env, runs the bundled `node` on the Nitro server (`:3000`). |
| `../../scripts/windows/web-run.cmd` | The `PunktfunkWeb` task action: loads the mgmt token + login password env, runs the bundled `bun` on the Nitro server (`:3000`). |
| `../../scripts/windows/web-setup.ps1` | Install-time (elevated): write the ACL'd console password, register the `PunktfunkWeb` task + firewall rule, start it. |
| `sudovda/` | **Vendored** prebuilt SudoVDA driver: `SudoVDA.inf` / `sudovda.cat` / `SudoVDA.dll` / `sudovda.cer`. |
| `nvenc/nvenc.def`, `nvenc/gen-nvenc-importlib.ps1` | Synthesise `nvencodeapi.lib` for the `--features nvenc` link (llvm-dlltool / lib.exe). |
+12 -12
View File
@@ -27,7 +27,7 @@ param(
[string]$PfxPassword = $env:MSIX_CERT_PASSWORD,
[string]$FfmpegDir = $env:FFMPEG_DIR, # bundle its bin\*.dll (amf-qsv build)
[string]$WebDir = $env:WEB_OUTPUT_DIR, # built web .output tree -> bundle the mgmt console
[string]$NodeExe = $env:NODE_EXE, # portable node.exe (>= 20) runtime for the console
[string]$BunExe = $env:BUN_EXE, # portable bun.exe runtime for the console
[switch]$NoDriver, # build without the bundled SudoVDA driver
[switch]$NoSign # skip signing (local debug)
)
@@ -184,30 +184,30 @@ if ($ffmpegBinSrc -and (Test-Path $ffmpegBinSrc)) {
}
else { Write-Host "no FFMPEG_DIR\bin -> installer built WITHOUT FFmpeg DLLs (nvenc/software-only host)" }
# --- stage the web management console (the built .output tree + a portable node + the launcher) ---
# The console runs as the PunktfunkWeb scheduled task (`node {app}\web\.output\server\index.mjs`),
# --- stage the web management console (the self-contained .output tree + a portable bun + launcher) -
# The console runs as the PunktfunkWeb scheduled task (`bun {app}\web\.output\server\index.mjs`),
# auto-wired to the host's loopback mgmt API. Stage everything ISCC reads into $OutDir (the
# non-WOW64-redirected C:\t area, same reason as the .iss/host.env staging above). Built upstream
# (windows-host.yml mirrors deb.yml: bun build -> node-server preset + the .output/server deps);
# omitted when -WebDir/-NodeExe are unset (host-only installer, e.g. a local debug pack).
if ($WebDir -and (Test-Path $WebDir) -and $NodeExe -and (Test-Path $NodeExe)) {
# non-WOW64-redirected C:\t area, same reason as the .iss/host.env staging above). The .output is
# self-contained (Nitro noExternals — deps bundled + tree-shaken, no node_modules), so bun runs it
# directly; omitted when -WebDir/-BunExe are unset (host-only installer, e.g. a local debug pack).
if ($WebDir -and (Test-Path $WebDir) -and $BunExe -and (Test-Path $BunExe)) {
$webStage = Join-Path $OutDir 'web'
if (Test-Path $webStage) { Remove-Item $webStage -Recurse -Force }
New-Item -ItemType Directory -Force -Path $webStage | Out-Null
Copy-Item (Join-Path $WebDir '*') -Destination $webStage -Recurse -Force
$nodeStage = Join-Path $OutDir 'node.exe'
Copy-Item -LiteralPath $NodeExe -Destination $nodeStage -Force
$bunStage = Join-Path $OutDir 'bun.exe'
Copy-Item -LiteralPath $BunExe -Destination $bunStage -Force
$webRun = Join-Path $OutDir 'web-run.cmd'
$webSetup = Join-Path $OutDir 'web-setup.ps1'
Copy-Item (Join-Path $repoRoot 'scripts\windows\web-run.cmd') -Destination $webRun -Force
Copy-Item (Join-Path $repoRoot 'scripts\windows\web-setup.ps1') -Destination $webSetup -Force
$defines += "/DWebDir=$webStage"
$defines += "/DNodeExe=$nodeStage"
$defines += "/DBunExe=$bunStage"
$defines += "/DWebRunCmd=$webRun"
$defines += "/DWebSetup=$webSetup"
Write-Host "bundling the web console from $WebDir (+ node $NodeExe)"
Write-Host "bundling the web console from $WebDir (+ bun $BunExe)"
}
else { Write-Host "no -WebDir/-NodeExe -> installer built WITHOUT the web console" }
else { Write-Host "no -WebDir/-BunExe -> installer built WITHOUT the web console" }
# --- build the installer (from the non-redirected copy under C:\t) -----------------------------
Write-Host "==> ISCC $($defines -join ' ') $issLocal"
+7 -7
View File
@@ -49,10 +49,10 @@
#ifdef FfmpegBin
#define WithFfmpeg
#endif
; WebDir (the built web .output tree) + NodeExe (a portable node.exe) are passed together by
; WebDir (the built web .output tree) + BunExe (a portable bun.exe) are passed together by
; pack-host-installer.ps1 to bundle the management console. Both required → WithWeb.
#ifdef WebDir
#ifdef NodeExe
#ifdef BunExe
#define WithWeb
#endif
#endif
@@ -102,12 +102,12 @@ Source: "{#Readme}"; DestDir: "{app}"; DestName: "README.txt"; Flags: ignorevers
Source: "{#FfmpegBin}\*.dll"; DestDir: "{app}"; Flags: ignoreversion
#endif
#ifdef WithWeb
; The web management console: the built Nitro/Node SSR bundle (.output = server + public assets) →
; {app}\web\.output, a portable Node runtime → {app}\node\node.exe, and the launcher the
; PunktfunkWeb task runs → {app}\web\web-run.cmd. web-setup.ps1 (the provisioner) goes to {tmp} and
; is removed after install.
; The web management console: the self-contained Nitro SSR bundle (.output = server + public; deps
; bundled in, no node_modules) → {app}\web\.output, a portable bun runtime → {app}\bun\bun.exe, and
; the launcher the PunktfunkWeb task runs → {app}\web\web-run.cmd. web-setup.ps1 (the provisioner)
; goes to {tmp} and is removed after install.
Source: "{#WebDir}\*"; DestDir: "{app}\web\.output"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "{#NodeExe}"; DestDir: "{app}\node"; DestName: "node.exe"; Flags: ignoreversion
Source: "{#BunExe}"; DestDir: "{app}\bun"; DestName: "bun.exe"; Flags: ignoreversion
Source: "{#WebRunCmd}"; DestDir: "{app}\web"; DestName: "web-run.cmd"; Flags: ignoreversion
Source: "{#WebSetup}"; DestDir: "{tmp}"; DestName: "web-setup.ps1"; Flags: deleteafterinstall
#endif
+4 -4
View File
@@ -35,10 +35,10 @@ won't start. The service is down only for the build duration.
## Web management console
On an **installed** host (the `setup.exe`) the console is set up automatically — no manual steps.
The installer bundles the built `.output` server + a portable Node and runs
`scripts\windows\web-setup.ps1`, which registers the **`PunktfunkWeb`** scheduled task (at boot, as
SYSTEM, restart-on-failure) running `{app}\web\web-run.cmd` `node …\.output\server\index.mjs` on
`:3000`, opens inbound TCP 3000, and writes the login password to
The installer bundles the built (self-contained, no-`node_modules`) `.output` server + a portable
bun and runs `scripts\windows\web-setup.ps1`, which registers the **`PunktfunkWeb`** scheduled task
(at boot, as SYSTEM, restart-on-failure) running `{app}\web\web-run.cmd`
`bun …\.output\server\index.mjs` on `:3000`, opens inbound TCP 3000, and writes the login password to
`%ProgramData%\punktfunk\web-password` (ACL'd to Administrators + SYSTEM). The mgmt bearer token it
proxies with is the host's own `%ProgramData%\punktfunk\mgmt-token`. Browse `http://<host-ip>:3000`
and log in with the password the installer shows on its final page. To change it, edit
+5 -11
View File
@@ -3,9 +3,9 @@
powershell -ExecutionPolicy Bypass -File scripts\windows\build-web.ps1
bun = build tool, node = runtime (the Nitro bundle externalizes srvx/@unom for SSR, which
bun fails to resolve at runtime). The PunktfunkWeb scheduled task runs web\web-run.cmd ->
node .output\server\index.mjs on :3000.
bun is both the build tool AND the runtime: vite.config's Nitro noExternals bundles every dep
into the self-contained .output (no node_modules, nothing for bun to fail to resolve), so the
PunktfunkWeb task runs web\web-run.cmd -> bun .output\server\index.mjs on :3000.
#>
$ErrorActionPreference = 'Stop'
$repo = Split-Path (Split-Path $PSScriptRoot)
@@ -19,17 +19,11 @@ Write-Host "bun install + build ..."
& $bun install
& $bun run build
if ($LASTEXITCODE -ne 0) { throw "web build failed (exit $LASTEXITCODE)" }
# The Nitro server bundle externalizes its runtime deps - install them in .output/server,
# with the @unom registry .npmrc present (else @unom/* 404s on npmjs).
Write-Host "installing externalized server deps ..."
Copy-Item "$web\.npmrc" "$web\.output\server\.npmrc" -Force
Set-Location "$web\.output\server"
& $bun install
# No .output/server install: noExternals means the output has no externalized deps to resolve.
Write-Host "restarting $task ..."
& schtasks /end /tn $task 2>$null | Out-Null
Get-CimInstance Win32_Process -Filter "Name='node.exe'" -ErrorAction SilentlyContinue |
Get-CimInstance Win32_Process -Filter "Name='bun.exe'" -ErrorAction SilentlyContinue |
Where-Object { $_.CommandLine -match 'index\.mjs' } |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
Start-Sleep 2
+6 -6
View File
@@ -2,10 +2,10 @@
rem punktfunk web console launcher — the action the PunktfunkWeb scheduled task runs at boot.
rem
rem Lays out next to the installed payload: {app}\web\web-run.cmd, {app}\web\.output\... and
rem {app}\node\node.exe (so %~dp0 = {app}\web\). Auto-wires the console the same way the Linux
rem {app}\bun\bun.exe (so %~dp0 = {app}\web\). Auto-wires the console the same way the Linux
rem systemd unit does: it sources the host's mgmt bearer token + the console login password from
rem %ProgramData%\punktfunk\, points the /api proxy at the host's loopback HTTPS mgmt API, and runs
rem the Nitro/Node server on :3000. No env editing on a packaged install.
rem the (self-contained, no-node_modules) Nitro server on :3000 with the bundled bun. No env editing.
setlocal EnableExtensions
set "PFDATA=%ProgramData%\punktfunk"
@@ -31,10 +31,10 @@ set "HOST=0.0.0.0"
set "PUNKTFUNK_MGMT_URL=https://127.0.0.1:47990"
set "NODE_TLS_REJECT_UNAUTHORIZED=0"
set "NODE=%~dp0..\node\node.exe"
set "BUN=%~dp0..\bun\bun.exe"
set "SERVER=%~dp0.output\server\index.mjs"
if not exist "%NODE%" (
echo [punktfunk-web] bundled node runtime missing at "%NODE%".
if not exist "%BUN%" (
echo [punktfunk-web] bundled bun runtime missing at "%BUN%".
exit /b 1
)
"%NODE%" "%SERVER%"
"%BUN%" "%SERVER%"
+2 -2
View File
@@ -1,6 +1,6 @@
<#
Provision the punktfunk web console after the host installer has laid down its payload
({app}\web\.output, {app}\node\node.exe, {app}\web\web-run.cmd). Invoked elevated from the
({app}\web\.output, {app}\bun\bun.exe, {app}\web\web-run.cmd). Invoked elevated from the
installer's [Run] section; idempotent (safe to re-run on upgrade).
1. Sets the console login password file %ProgramData%\punktfunk\web-password
@@ -71,7 +71,7 @@ $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoi
-StartWhenAvailable -RestartInterval (New-TimeSpan -Minutes 1) -RestartCount 10 `
-ExecutionTimeLimit (New-TimeSpan -Seconds 0)
Register-ScheduledTask -TaskName $TaskName -Action $action -Trigger $trigger -Principal $principal `
-Settings $settings -Description 'punktfunk web management console (Nitro/Node SSR on :3000)' `
-Settings $settings -Description 'punktfunk web management console (Nitro SSR on bun, :3000)' `
-Force | Out-Null
Write-Host "registered scheduled task $TaskName -> $cmd"
+8
View File
@@ -46,6 +46,14 @@ export default defineConfig({
// .deb depend on apt-native `nodejs (>= 20)` instead of vendoring bun. CI still BUILDS with
// bun; only the runtime target changes. (dev `vite dev` is unaffected.)
preset: 'node-server',
// BUNDLE every dependency into the server output (no externalized node_modules). Three wins:
// (1) the .output tree drops from ~47k files / 730 MB (the whole untree-shaken @unom/ui dep
// tree — payload, lexical, date-fns…) to a handful of tree-shaken chunks; (2) it makes the
// output a self-contained graph `bun build --compile` can fold into ONE native binary (the
// Windows installer ships that instead of node + a node_modules forest); (3) it removes the
// bare external imports (`srvx`, `seroval`…) bun couldn't resolve at runtime — the reason we
// used to need node. node still runs the same self-contained output for the Linux .deb.
noExternals: true,
compatibilityDate: '2026-06-10',
// Scan server/{middleware,routes} for the auth gate + the /api proxy.
scanDirs: [serverDir],