feat(electron): walking skeleton for the desktop shell
Phase 1 step 1 of VNCprodbuild: electron/main.ts boots the same Next.js "standalone" server artifact the Dockerfile already produces (next.config.ts's output: "standalone") as a child process on a random localhost port, then opens a BrowserWindow at it. electron/preload.ts is a contextBridge stub (window.vnc.isElectron) for now. scripts/assemble-standalone.mjs copies public/ and .next/static into .next/standalone, mirroring what the Dockerfile does by hand, since `next build` deliberately leaves both out of the standalone output. scripts/build-electron.mjs bundles main.ts/preload.ts to CommonJS via esbuild (already a devDependency). New npm scripts: build:standalone, build:electron, electron:dev. electron-builder.config.js is intentionally minimal - no signing, no platform targets yet, just enough to prove the concept end to end. Also fixes a pre-existing repo-wide lint gap: vnc/plugins/smime is an independent sub-package (own package.json/esbuild build, browser-only globals) that was never added to eslint's ignores alongside repos:: and examples/**, so `npm run lint` - and the husky pre-commit hook - was failing on every commit regardless of what changed. Excluded it the same way those are, and added node globals for scripts/**/*.mjs so the new build helpers above lint cleanly too. Verified manually: npm run build:standalone && npm run build:electron && electron . boots the server and opens a window with no errors.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env node
|
||||
// `next build --webpack` (see next.config.ts's `output: "standalone"`)
|
||||
// emits .next/standalone/server.js but - deliberately, per Next's own docs -
|
||||
// leaves out public/ and .next/static/. The Dockerfile copies both in by
|
||||
// hand for the container image; this does the same thing for local Electron
|
||||
// dev and packaging, so every path boots the exact same artifact.
|
||||
import { cpSync, existsSync, rmSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const rootDir = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
||||
const standaloneDir = path.join(rootDir, ".next", "standalone");
|
||||
|
||||
if (!existsSync(standaloneDir)) {
|
||||
console.error(`Missing ${standaloneDir} - run "next build --webpack" first.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const publicSrc = path.join(rootDir, "public");
|
||||
const publicDest = path.join(standaloneDir, "public");
|
||||
rmSync(publicDest, { recursive: true, force: true });
|
||||
cpSync(publicSrc, publicDest, { recursive: true });
|
||||
|
||||
const staticSrc = path.join(rootDir, ".next", "static");
|
||||
const staticDest = path.join(standaloneDir, ".next", "static");
|
||||
rmSync(staticDest, { recursive: true, force: true });
|
||||
cpSync(staticSrc, staticDest, { recursive: true });
|
||||
|
||||
console.log("Assembled standalone server at", standaloneDir);
|
||||
Reference in New Issue
Block a user