mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
* fix(serve): serve web UI at root path instead of 404 gitnexus serve returned Cannot GET / because no route handler existed for the root path. Now serves the built gitnexus-web dist at / with SPA fallback for client-side routing. Falls back to a helpful landing page with API links when the web UI hasn't been built yet. Also updates the build script to build and copy gitnexus-web into gitnexus/web/ for the published npm package. * fix(serve): address Copilot review feedback - Use regex SPA fallback that excludes /api paths (avoids serving index.html for unknown API routes) - Add rel="noopener noreferrer" to external link (reverse-tabnabbing) - Move build "done" log after web UI step * fix(build): use npm run build for web UI, add npm install guard The build script ran `npx tsc -b && npx vite build` in gitnexus-web/, but CI only installs node_modules for gitnexus/ — not gitnexus-web/. npx then resolved the wrong `tsc` package (a trojan on npm), causing all CI jobs to fail. Fix: add an npm install guard when node_modules is missing, and use `npm run build` (which runs the local typescript) instead of npx. * feat(serve): styled fallback page, asset 404s, build script safety - Add landingPageHtml() with gitnexus-web design tokens (void bg, surface cards, accent color, terminal-style build command block). - Add resolveWebDistDir() helper with non-ENOENT error logging. - Register express.static with Cache-Control headers (no-cache HTML, immutable assets) and SPA fallback route. - Replace wildcard SPA fallback with regex that excludes /api/* AND asset-like file extensions (.js, .css, .ico, .woff2, .map, etc.). - Add ordering comment warning about SPA fallback route placement. scripts/build.js: - Change npm install to npm ci. - Add timeout: 120_000 to all execSync calls. Test coverage: - 26 new unit tests for design tokens, terminal block, external links, SPA regex acceptance/exclusion, cache headers, and fs.access edge cases. Closes #1048 (review feedback) * fix: format, lint, and add GITNEXUS_WEB_DIST env var - Remove unused fsType import from web-ui-serving.test.ts (lint error) - Run prettier on fallback-page-screenshot.html and test file - Add GITNEXUS_WEB_DIST env var as primary override in resolveWebDistDir - Add tests for env var: prefer when set, fallback when dir missing * fix: use cross-platform path matching in env var tests Path.includes('/env/dist') fails on Windows where path.join produces backslashed paths. Normalize via path.sep replacement before matching. * fix(serve): address PR #1048 review findings - Add uncaughtException/unhandledRejection crash guards to HTTP serve path - Export SPA_FALLBACK_REGEX so tests use the production constant (no drift) - Export staticCacheControlSetHeaders so tests verify the real production function - Add real Express dispatch tests for API 404 and asset 404 isolation - Delete committed debug artifact fallback-page-screenshot.html
93 lines
4 KiB
JavaScript
93 lines
4 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Build script that compiles gitnexus and inlines gitnexus-shared into the dist.
|
|
*
|
|
* Steps:
|
|
* 1. Build gitnexus-shared (tsc)
|
|
* 2. Build gitnexus (tsc)
|
|
* 3. Copy gitnexus-shared/dist → dist/_shared
|
|
* 4. Rewrite bare 'gitnexus-shared' specifiers → relative paths
|
|
*/
|
|
import { execSync } from 'node:child_process';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const ROOT = path.resolve(__dirname, '..');
|
|
const SHARED_ROOT = path.resolve(ROOT, '..', 'gitnexus-shared');
|
|
const DIST = path.join(ROOT, 'dist');
|
|
const SHARED_DEST = path.join(DIST, '_shared');
|
|
|
|
// ── 1. Build gitnexus-shared ───────────────────────────────────────
|
|
console.log('[build] compiling gitnexus-shared…');
|
|
execSync('npx tsc', { cwd: SHARED_ROOT, stdio: 'inherit', timeout: 120_000 });
|
|
|
|
// ── 2. Build gitnexus ──────────────────────────────────────────────
|
|
console.log('[build] compiling gitnexus…');
|
|
execSync('npx tsc', { cwd: ROOT, stdio: 'inherit', timeout: 120_000 });
|
|
|
|
// ── 3. Copy shared dist ────────────────────────────────────────────
|
|
console.log('[build] copying shared module into dist/_shared…');
|
|
fs.cpSync(path.join(SHARED_ROOT, 'dist'), SHARED_DEST, { recursive: true });
|
|
|
|
// ── 4. Rewrite imports ─────────────────────────────────────────────
|
|
console.log('[build] rewriting gitnexus-shared imports…');
|
|
let rewritten = 0;
|
|
|
|
function rewriteFile(filePath) {
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
if (!content.includes('gitnexus-shared')) return;
|
|
|
|
const relDir = path.relative(path.dirname(filePath), SHARED_DEST);
|
|
// Always use posix separators and point to the package index
|
|
const relImport = relDir.split(path.sep).join('/') + '/index.js';
|
|
|
|
const updated = content
|
|
.replace(/from\s+['"]gitnexus-shared['"]/g, `from '${relImport}'`)
|
|
.replace(/import\(\s*['"]gitnexus-shared['"]\s*\)/g, `import('${relImport}')`);
|
|
|
|
if (updated !== content) {
|
|
fs.writeFileSync(filePath, updated);
|
|
rewritten++;
|
|
}
|
|
}
|
|
|
|
function walk(dir, extensions, cb) {
|
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
const full = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
walk(full, extensions, cb);
|
|
} else if (extensions.some((ext) => entry.name.endsWith(ext))) {
|
|
cb(full);
|
|
}
|
|
}
|
|
}
|
|
|
|
walk(DIST, ['.js', '.d.ts'], rewriteFile);
|
|
|
|
// ── 5. Make CLI entry executable ────────────────────────────────────
|
|
const cliEntry = path.join(DIST, 'cli', 'index.js');
|
|
if (fs.existsSync(cliEntry)) fs.chmodSync(cliEntry, 0o755);
|
|
|
|
// ── 6. Build & copy web UI ──────────────────────────────────────────
|
|
const WEB_ROOT = path.resolve(ROOT, '..', 'gitnexus-web');
|
|
const WEB_DEST = path.join(DIST, '..', 'web');
|
|
|
|
if (fs.existsSync(path.join(WEB_ROOT, 'package.json'))) {
|
|
console.log('[build] building gitnexus-web…');
|
|
if (!fs.existsSync(path.join(WEB_ROOT, 'node_modules'))) {
|
|
console.log('[build] installing gitnexus-web dependencies…');
|
|
execSync('npm ci', { cwd: WEB_ROOT, stdio: 'inherit', timeout: 120_000 });
|
|
}
|
|
execSync('npm run build', { cwd: WEB_ROOT, stdio: 'inherit', timeout: 120_000 });
|
|
|
|
// Copy dist → gitnexus/web/ (shipped in the npm package)
|
|
fs.rmSync(WEB_DEST, { recursive: true, force: true });
|
|
fs.cpSync(path.join(WEB_ROOT, 'dist'), WEB_DEST, { recursive: true });
|
|
console.log('[build] copied web UI → gitnexus/web/');
|
|
} else {
|
|
console.log('[build] skipping web UI (gitnexus-web not found)');
|
|
}
|
|
|
|
console.log(`[build] done — rewrote ${rewritten} files.`);
|