mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-09 08:21:50 +00:00
A packaged desktop app launches to a blank page with a bare ERR_FILE_NOT_FOUND when dist/index.html isn't in the bundle (#39484). This happens when the build step fails (e.g. a stale checkout that fails typecheck) but electron-builder packages anyway, shipping an empty dist/. - build-time: scripts/assert-dist-built.cjs runs at the tail of the `build` script and aborts before electron-builder if dist/index.html or the vite JS bundle is missing/empty. Every packaging path (pack, dist*) inherits it via `npm run build &&`. - runtime: resolveRendererIndex() now logs a clear 'packaged without a renderer bundle — rebuild with hermes desktop --force-build' message when no index.html exists, instead of silently loading a missing path. - runtime: resolveWebDist() logs when it falls back to an asar-internal dist that isn't a real directory (the dashboard 404 class, #41327/#39472), rather than returning an unservable path silently. Adds scripts/assert-dist-built.test.cjs (node:test) covering the guard.
84 lines
2.9 KiB
JavaScript
84 lines
2.9 KiB
JavaScript
const assert = require('node:assert/strict')
|
|
const fs = require('node:fs')
|
|
const os = require('node:os')
|
|
const path = require('node:path')
|
|
const test = require('node:test')
|
|
|
|
const { checkDistBuilt } = require('../scripts/assert-dist-built.cjs')
|
|
|
|
function makeDist(extra) {
|
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'hermes-assert-dist-'))
|
|
const distDir = path.join(tempRoot, 'dist')
|
|
fs.mkdirSync(distDir, { recursive: true })
|
|
if (extra) extra(distDir)
|
|
return { tempRoot, distDir }
|
|
}
|
|
|
|
test('checkDistBuilt passes when index.html + an assets JS bundle exist', () => {
|
|
const { tempRoot, distDir } = makeDist(d => {
|
|
fs.writeFileSync(path.join(d, 'index.html'), '<!doctype html><div id=root></div>', 'utf8')
|
|
fs.mkdirSync(path.join(d, 'assets'))
|
|
fs.writeFileSync(path.join(d, 'assets', 'index-abc123.js'), 'console.log(1)', 'utf8')
|
|
})
|
|
try {
|
|
assert.deepEqual(checkDistBuilt(distDir), { ok: true })
|
|
} finally {
|
|
fs.rmSync(tempRoot, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('checkDistBuilt fails when the dist directory is absent', () => {
|
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'hermes-assert-dist-'))
|
|
try {
|
|
const result = checkDistBuilt(path.join(tempRoot, 'dist'))
|
|
assert.equal(result.ok, false)
|
|
assert.match(result.error, /no dist directory/)
|
|
} finally {
|
|
fs.rmSync(tempRoot, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('checkDistBuilt fails when index.html is missing', () => {
|
|
const { tempRoot, distDir } = makeDist(d => {
|
|
fs.mkdirSync(path.join(d, 'assets'))
|
|
fs.writeFileSync(path.join(d, 'assets', 'index-abc123.js'), 'console.log(1)', 'utf8')
|
|
})
|
|
try {
|
|
const result = checkDistBuilt(distDir)
|
|
assert.equal(result.ok, false)
|
|
assert.match(result.error, /index\.html is missing/)
|
|
} finally {
|
|
fs.rmSync(tempRoot, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('checkDistBuilt fails when index.html is empty', () => {
|
|
const { tempRoot, distDir } = makeDist(d => {
|
|
fs.writeFileSync(path.join(d, 'index.html'), '', 'utf8')
|
|
fs.mkdirSync(path.join(d, 'assets'))
|
|
fs.writeFileSync(path.join(d, 'assets', 'index-abc123.js'), 'console.log(1)', 'utf8')
|
|
})
|
|
try {
|
|
const result = checkDistBuilt(distDir)
|
|
assert.equal(result.ok, false)
|
|
assert.match(result.error, /index\.html is empty/)
|
|
} finally {
|
|
fs.rmSync(tempRoot, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('checkDistBuilt fails when assets/ has no JS bundle', () => {
|
|
const { tempRoot, distDir } = makeDist(d => {
|
|
fs.writeFileSync(path.join(d, 'index.html'), '<!doctype html>', 'utf8')
|
|
fs.mkdirSync(path.join(d, 'assets'))
|
|
// CSS only, no JS — still a blank page at runtime.
|
|
fs.writeFileSync(path.join(d, 'assets', 'index-abc123.css'), 'body{}', 'utf8')
|
|
})
|
|
try {
|
|
const result = checkDistBuilt(distDir)
|
|
assert.equal(result.ok, false)
|
|
assert.match(result.error, /no built JS bundle/)
|
|
} finally {
|
|
fs.rmSync(tempRoot, { recursive: true, force: true })
|
|
}
|
|
})
|