refactor(build): place the views in the page instead of expanding templates

index.html now lists each view's host and the loading screen itself, so
the gev:template expansion plugin, its view list, the loading-screen
template and the ./build/html export are gone. createApplication takes
omitViews for views an application leaves out; their hosts are removed,
and a view an earlier call rendered is unmounted.
This commit is contained in:
Sameh Khamis committed 2026-10-31 17:52:47 -07:00
1 parent f279200af5
commit 5bf797ef71
18 files changed
+176 -174

No files matched your search

+14 -28
View File
@@ -1,41 +1,27 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import {
expandApplicationHtml,
APPLICATION_TEMPLATES,
} from '../../build/application-html.js';
import { APPLICATION_VIEW_NAMES } from '../../build/applicationViews.js';
import { APPLICATION_VIEWS } from '../ui/views/index.js';
import { readApplicationHtml } from '../testSupport/applicationHtml.mjs';
test('the standalone document expands every component once and preserves unique element ids', async () => {
const source = readFileSync(new URL('../../index.html', import.meta.url), 'utf8');
const source = readFileSync(new URL('../../index.html', import.meta.url), 'utf8');
test('the standalone document hosts every view once and keeps element ids unique', async () => {
const hosts = [...source.matchAll(/data-gev-view="([^"]+)"/g)].map((match) => match[1]);
// Order is stacking order for fixed elements that share a z-index.
assert.deepEqual(hosts, ['scene-chrome', 'cockpit', 'display-controls', 'command-dock', 'layer-panels', 'context', 'welcome', 'provider-settings']);
assert.deepEqual([...hosts].sort(), Object.keys(APPLICATION_VIEWS).sort());
const html = await readApplicationHtml();
assert.equal([...source.matchAll(/gev:template /g)].length, APPLICATION_TEMPLATES.length);
assert.doesNotMatch(html, /gev:template/);
const ids = [...html.matchAll(/\sid="([^"]+)"/g)].map(match => match[1]);
const ids = [...html.matchAll(/\sid="([^"]+)"/g)].map((match) => match[1]);
assert.equal(new Set(ids).size, ids.length);
assert.match(html, /id="cesiumContainer"/);
assert.match(html, /type="module" src="\/src\/main.js"/);
});
test('component selection includes only requested markup and refuses filesystem traversal', () => {
const html = expandApplicationHtml('<!-- gev:template hud-loading -->\n');
assert.match(html, /id="loading-screen"/);
assert.doesNotMatch(html, /id="cesiumContainer"/);
assert.throws(() => expandApplicationHtml('<!-- gev:template ../../.env -->'), /Unknown application template/);
});
test('views expand to mount hosts, the loading screen stays static, and every view is registered', () => {
assert.deepEqual(Object.keys(APPLICATION_VIEWS).sort(), [...APPLICATION_VIEW_NAMES].sort());
for (const name of APPLICATION_VIEW_NAMES) {
assert.ok(APPLICATION_TEMPLATES.includes(name), name);
assert.equal(
expandApplicationHtml(`<!-- gev:template ${name} -->\n`),
`<div class="gev-view" data-gev-view="${name}"></div>\n`,
);
}
// It paints before any script runs.
assert.ok(!APPLICATION_VIEW_NAMES.includes('hud-loading'));
test('the loading screen is static markup, so it paints before any script runs', () => {
const loading = source.indexOf('id="loading-screen"');
assert.ok(loading > 0);
assert.ok(loading < source.indexOf('type="module" src="/src/main.js"'));
assert.match(source, /class="loader-status" data-i18n>Initializing photorealistic world\.\.\.</);
assert.doesNotMatch(source, /gev:template/);
});
+4 -4
View File
@@ -29,8 +29,8 @@ test('explicit build inputs preserve browser-only defines, plugin order and loop
assert.equal(config.plugins[0].enforce, 'pre');
assert.equal(config.plugins[1].name, 'host-check');
assert.equal(config.plugins[1].enforce, 'pre');
assert.equal(config.plugins[4].name, 'vite:vue');
assert.equal(config.plugins[5], plugin);
assert.equal(config.plugins[3].name, 'vite:vue');
assert.equal(config.plugins[4], plugin);
assert.equal(config.server.host, 'localhost');
assert.equal(config.server.port, 4173);
assert.deepEqual(config.server.allowedHosts, ['localhost', '127.0.0.1']);
@@ -104,7 +104,7 @@ test('build helper does not discover environment values or construct local provi
undefined,
);
assert.deepEqual(
config.plugins.slice(5).map((plugin) => plugin.name),
config.plugins.slice(4).map((plugin) => plugin.name),
['embed-framing', 'panel-build'],
);
} finally {
@@ -118,7 +118,7 @@ test('root config retains existing named exports and standalone provider order',
assert.equal(compatibility[name], value, name);
const config = standaloneConfig({ mode: 'test' });
const standaloneProviders = config.plugins
.slice(5, -6)
.slice(4, -6)
.map((plugin) => plugin.name);
assert.equal(
standaloneProviders.filter((name) => name === 'gemini-live-proxy').length,