v3 fixes and styling
This commit is contained in:
@@ -28,6 +28,7 @@ const requiredFiles = [
|
||||
'dist/src/js/lib/xterm-addon-fit.min.js',
|
||||
'dist/src/js/lib/xterm-addon-search.min.js',
|
||||
'dist/src/js/lib/xterm-addon-web-links.min.js',
|
||||
'dist/src/js/wails-service.js',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -46,6 +47,14 @@ function copyDirSync(src, dest) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies one file and creates the parent directory if needed.
|
||||
*/
|
||||
function copyFileSync(src, dest) {
|
||||
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
||||
fs.copyFileSync(src, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a directory tree if it exists.
|
||||
*/
|
||||
@@ -55,6 +64,53 @@ function cleanDir(dir) {
|
||||
}
|
||||
}
|
||||
|
||||
function copyWailsRuntimeBindings(srcRoot, destRoot) {
|
||||
const runtimeFiles = [
|
||||
'go/api/Service.js',
|
||||
'runtime/runtime.js',
|
||||
];
|
||||
|
||||
for (const relPath of runtimeFiles) {
|
||||
const src = path.join(srcRoot, relPath);
|
||||
if (fs.existsSync(src)) {
|
||||
copyFileSync(src, path.join(destRoot, relPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function walkFiles(dir, predicate, files = []) {
|
||||
if (!fs.existsSync(dir)) return files;
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const full = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
walkFiles(full, predicate, files);
|
||||
} else if (entry.isFile() && predicate(full)) {
|
||||
files.push(full);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
function cleanupDistAssets() {
|
||||
console.log('[build] Cleaning production frontend assets...');
|
||||
const sourceMapFiles = walkFiles(distDir, (file) => file.endsWith('.js') || file.endsWith('.css'));
|
||||
let mapCommentCount = 0;
|
||||
for (const file of sourceMapFiles) {
|
||||
const input = fs.readFileSync(file, 'utf8');
|
||||
const output = input
|
||||
.replace(/(?:\r?\n)?\/\/# sourceMappingURL=.*?(?=\r?\n|$)/g, '')
|
||||
.replace(/(?:\r?\n)?\/\*# sourceMappingURL=.*?\*\/(?=\r?\n|$)/g, '');
|
||||
if (output !== input) {
|
||||
fs.writeFileSync(file, output);
|
||||
mapCommentCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (mapCommentCount > 0) {
|
||||
console.log(`[build] Removed ${mapCommentCount} source-map reference(s).`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the asset copy script to pull xterm files into src/js/lib/ and
|
||||
* src/css/lib/.
|
||||
@@ -65,6 +121,10 @@ function copyAssets() {
|
||||
cwd: frontendDir,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
execSync('node scripts/bundle-novnc.js', {
|
||||
cwd: frontendDir,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,6 +132,7 @@ function copyAssets() {
|
||||
* dist/index.html
|
||||
* dist/src/css/ (application + lib stylesheets)
|
||||
* dist/src/js/ (application + lib scripts)
|
||||
* dist/wailsjs/ (generated backend bindings, if present)
|
||||
* dist/src/components/ (if present)
|
||||
* dist/src/assets/ (if present)
|
||||
*/
|
||||
@@ -94,6 +155,13 @@ function buildDist() {
|
||||
copyDirSync(srcDir, path.join(distDir, 'src'));
|
||||
}
|
||||
|
||||
// Copy only runtime Wails bindings so embedded production assets do not
|
||||
// carry TypeScript declarations and model files.
|
||||
const wailsjsDir = path.join(frontendDir, 'wailsjs');
|
||||
if (fs.existsSync(wailsjsDir)) {
|
||||
copyWailsRuntimeBindings(wailsjsDir, path.join(distDir, 'wailsjs'));
|
||||
}
|
||||
|
||||
console.log('[build] dist/ assembled.');
|
||||
}
|
||||
|
||||
@@ -151,6 +219,7 @@ try {
|
||||
}
|
||||
|
||||
buildDist();
|
||||
cleanupDistAssets();
|
||||
|
||||
if (!validate()) {
|
||||
console.error('[build] Validation failed — some required files are missing.');
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
// Entry point for esbuild bundling of noVNC.
|
||||
// Assigns RFB to window.noVNC so it's available as a global in the frontend.
|
||||
import RFB from "@novnc/novnc";
|
||||
import { initLogging } from "../node_modules/@novnc/novnc/core/util/logging.js";
|
||||
|
||||
initLogging("error");
|
||||
window.noVNC = { RFB: RFB };
|
||||
|
||||
@@ -23,6 +23,27 @@ function assertNotContains(file, needle, message) {
|
||||
}
|
||||
}
|
||||
|
||||
function assertTreeNotContains(relDir, needle, message) {
|
||||
const dir = path.join(repo, relDir);
|
||||
const offenders = [];
|
||||
const walk = (current) => {
|
||||
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
|
||||
const full = path.join(current, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
walk(full);
|
||||
continue;
|
||||
}
|
||||
if (!entry.isFile() || !entry.name.endsWith(".js")) continue;
|
||||
const rel = path.relative(repo, full);
|
||||
if (read(rel).includes(needle)) offenders.push(rel);
|
||||
}
|
||||
};
|
||||
walk(dir);
|
||||
if (offenders.length) {
|
||||
throw new Error(`${message}\nUnexpected ${JSON.stringify(needle)} in ${offenders.join(", ")}`);
|
||||
}
|
||||
}
|
||||
|
||||
assertContains(
|
||||
"frontend/src/js/terminal.js",
|
||||
"escapeHtml(title)",
|
||||
@@ -163,5 +184,105 @@ assertContains(
|
||||
"github.com/hajimehoshi/go-mp3",
|
||||
"Leviathan spectrogram visualiser must support MP3 decoding",
|
||||
);
|
||||
assertNotContains(
|
||||
"wails.json",
|
||||
"\"obfuscated\": true",
|
||||
"Wails obfuscation must stay disabled because this app embeds frontend/src and uses normal Wails globals",
|
||||
);
|
||||
assertNotContains(
|
||||
"wails.json",
|
||||
"\"garbleargs\"",
|
||||
"garble arguments must not be configured when Wails obfuscation is disabled",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/index.html",
|
||||
"wails-service.js",
|
||||
"frontend must load the Wails service bridge before app code",
|
||||
);
|
||||
assertNotContains(
|
||||
"frontend/index.html",
|
||||
'type="module" src="/src/js/wails-service.js"',
|
||||
"Wails bridge must load as a synchronous classic script before app code",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/js/wails-service.js",
|
||||
'prop === "then"',
|
||||
"Wails service proxy must not masquerade as a Promise thenable",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/js/wails-service.js",
|
||||
"window.go?.api?.Service",
|
||||
"Wails service bridge must use the normal named Wails API",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/scripts/build.js",
|
||||
"sourceMappingURL",
|
||||
"frontend production build must remove source-map references",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/scripts/build.js",
|
||||
"bundle-novnc.js",
|
||||
"frontend production build must regenerate the noVNC bundle",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/scripts/novnc-entry.js",
|
||||
"initLogging(\"error\")",
|
||||
"bundled noVNC logging must default to errors only",
|
||||
);
|
||||
assertNotContains(
|
||||
"frontend/src/js/app.js",
|
||||
"console.debug(\"[session:debug]\"",
|
||||
"release UI must not print telnet negotiation debug events",
|
||||
);
|
||||
assertNotContains(
|
||||
"frontend/src/js/app.js",
|
||||
"console.log(\"Backend is ready\")",
|
||||
"release UI must not print backend-ready lifecycle events",
|
||||
);
|
||||
assertContains(
|
||||
"build.sh",
|
||||
"NEXUS_COMPRESS",
|
||||
"local builds must expose an explicit compression switch",
|
||||
);
|
||||
assertContains(
|
||||
"scripts/build-common.sh",
|
||||
"nexus_use_upx_for_target",
|
||||
"build scripts must share one UPX target-selection helper",
|
||||
);
|
||||
assertContains(
|
||||
"build.sh",
|
||||
"Skipping UPX compression on macOS",
|
||||
"local compressed builds must avoid unsupported macOS UPX by default",
|
||||
);
|
||||
assertContains(
|
||||
"build.sh",
|
||||
"-trimpath",
|
||||
"local production builds should trim file paths from binaries",
|
||||
);
|
||||
assertContains(
|
||||
"scripts/build-common.sh",
|
||||
"-buildid=",
|
||||
"production builds must strip the Go build ID",
|
||||
);
|
||||
assertContains(
|
||||
"scripts/build-common.sh",
|
||||
"-O2 -g0",
|
||||
"production builds must remove cgo debug output by default",
|
||||
);
|
||||
assertContains(
|
||||
"Makefile",
|
||||
"build-compressed",
|
||||
"Makefile must expose an explicit compressed build target",
|
||||
);
|
||||
assertContains(
|
||||
"Makefile",
|
||||
"NEXUS_FORCE_MACOS_UPX",
|
||||
"Makefile compressed builds must make macOS UPX opt-in",
|
||||
);
|
||||
assertTreeNotContains(
|
||||
"frontend/src/js",
|
||||
"window.go.api.Service",
|
||||
"app code must not call named Wails backend methods directly",
|
||||
);
|
||||
|
||||
console.log("frontend regression checks passed");
|
||||
|
||||
Reference in New Issue
Block a user