1
0

Use nginx to serve the website
All checks were successful
Build and test project / build-and-test (push) Successful in 1m29s

This commit is contained in:
2026-03-19 19:56:24 +01:00
parent 48ea2c183b
commit 347b4f654a
7 changed files with 96 additions and 11 deletions

View File

@@ -42,16 +42,15 @@ web/
js/
app.js # ES module entry point: step navigation, flow orchestration
kobo-device.js # KoboModels, KoboDevice class
kobo-software-urls.js # KoboSoftwareUrls, getSoftwareUrl, getDevicesForVersion
kobo-software-urls.js # Fetches download URLs from JSON, getSoftwareUrl, getDevicesForVersion
nickelmenu.js # NickelMenuInstaller: downloads/bundles NickelMenu + config
patch-ui.js # PatchUI: loads patches, parses YAML, renders toggle UI
patch-runner.js # KoboPatchRunner: spawns Web Worker per build
patch-worker.js # Web Worker: loads WASM, runs patchFirmware()
wasm_exec.js # Go WASM runtime (generated by build.sh, gitignored)
wasm/
kobopatch.wasm # Compiled WASM binary (generated by build.sh, gitignored)
wasm_exec.js # Go WASM runtime (copied from Go SDK by build.sh, gitignored)
patches/
index.json # Available patch manifest
downloads.json # Firmware download URLs by version/serial (may be auto-generated)
patches_*.zip # Patch files per firmware version
nickelmenu/ # NickelMenu assets (generated by setup.sh, gitignored)
NickelMenu.zip
@@ -85,7 +84,7 @@ tests/
## Adding a new software version
1. Add the patch zip to `web/src/patches/` and update `index.json`
2. Add download URLs to `KoboSoftwareUrls` in `web/src/js/kobo-software-urls.js` (keyed by version then serial prefix)
2. Add download URLs to `web/src/patches/downloads.json` (keyed by version then serial prefix)
3. The Kobo CDN prefix per device family (e.g. `kobo12`, `kobo13`) is stable; the date path segment changes per release
## Building the WASM binary
@@ -138,7 +137,9 @@ You can delete the entire `web/dist/` folder and re-run `serve-locally.sh` to re
The E2E tests cover all major user flows:
- **NickelMenu** — install with config (manual download), install NickelMenu only, remove option disabled without device
- **Custom patches** — full patching pipeline, restore original firmware
- **Custom patches** — full patching pipeline, restore original firmware, build failure with "Go Back" recovery
- **Device detection** — firmware version validation (4.x supported, 5.x incompatible), unknown model warning
- **Back navigation** — verifies every back button returns to the correct previous screen in both auto and manual mode
- **With simulated Kobo Libra Color** — install NickelMenu with config, remove NickelMenu, install custom patches, restore firmware
The simulated device tests mock the File System Access API with an in-memory filesystem that mimics a Kobo Libra Color (serial prefix N428, firmware 4.45.23646).

26
nginx.conf.template Normal file
View File

@@ -0,0 +1,26 @@
worker_processes auto;
error_log stderr;
pid /tmp/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log off;
sendfile on;
gzip on;
gzip_types text/html text/css application/javascript application/json application/wasm;
server {
listen ${PORT} default_server;
root web/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
}

View File

@@ -1,7 +1,7 @@
providers = ["python"]
providers = ["node"]
[phases.setup]
nixPkgs = ["git", "curl", "python3Minimal", "zip", "gnutar", "nodejs_22"]
nixPkgs = ["git", "curl", "zip", "gnutar", "nginx"]
paths = ["/usr/local/go/bin"]
cmds = [
"curl -sSfL https://go.dev/dl/go1.23.12.linux-amd64.tar.gz | tar -xz -C /usr/local",
@@ -16,4 +16,4 @@ cmds = [
]
[start]
cmd = "python3 -m http.server ${PORT:-8080} -d web/dist"
cmd = "./start.sh"

View File

@@ -26,4 +26,11 @@ if [ ! -f "$DIST_DIR/wasm/kobopatch.wasm" ]; then
fi
echo "Serving at http://localhost:8888"
python3 -m http.server -d "$DIST_DIR" 8888
if command -v nginx &>/dev/null; then
export PORT=8888
envsubst '${PORT}' < "$SCRIPT_DIR/nginx.conf.template" > /tmp/kobopatch-nginx.conf
nginx -c /tmp/kobopatch-nginx.conf -g 'daemon off;'
else
echo "(nginx not found, using Node.js server)"
node serve.mjs
fi

11
start.sh Normal file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PORT="${PORT:-8080}"
# Generate nginx config from template
export PORT
envsubst '${PORT}' < "$SCRIPT_DIR/nginx.conf.template" > /tmp/nginx.conf
exec nginx -c /tmp/nginx.conf -g 'daemon off;'

View File

@@ -17,7 +17,7 @@ module.exports = defineConfig({
},
},
webServer: {
command: 'cd ../../web && npm install && node build.mjs && cd ../kobopatch-wasm && bash build.sh && cd ../web && python3 -m http.server -d dist 8889',
command: 'cd ../../web && npm install && node build.mjs && cd ../kobopatch-wasm && bash build.sh && cd ../web && PORT=8889 node serve.mjs',
port: 8889,
reuseExistingServer: true,
},

40
web/serve.mjs Normal file
View File

@@ -0,0 +1,40 @@
import { createServer } from 'node:http';
import { createReadStream, statSync, existsSync } from 'node:fs';
import { join, extname } from 'node:path';
const DIST = join(import.meta.dirname, 'dist');
const PORT = process.env.PORT || 8888;
const MIME = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'application/javascript',
'.json': 'application/json',
'.wasm': 'application/wasm',
'.zip': 'application/zip',
'.tgz': 'application/gzip',
'.svg': 'image/svg+xml',
'.png': 'image/png',
'.ico': 'image/x-icon',
'.webmanifest': 'application/manifest+json',
};
createServer((req, res) => {
const url = new URL(req.url, `http://localhost`);
let filePath = join(DIST, decodeURIComponent(url.pathname));
if (filePath.endsWith('/')) filePath = join(filePath, 'index.html');
if (!extname(filePath) && existsSync(filePath + '/index.html')) filePath += '/index.html';
try {
const stat = statSync(filePath);
if (!stat.isFile()) throw new Error();
res.writeHead(200, { 'Content-Type': MIME[extname(filePath)] || 'application/octet-stream' });
createReadStream(filePath).pipe(res);
} catch {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not found');
}
}).listen(PORT, () => {
console.log(`Serving web/dist on http://localhost:${PORT}`);
});