mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 03:14:00 +00:00
Run the worker prelude ahead of Cesium's own workers script
Cesium's script sets CESIUM_WORKERS itself when it loads, so the panel's combined workers script was never used, and neither was the embedded terrain-heights file: the worker still requested it from the panel page's site. The panel build now writes only the prelude, and the panel puts it ahead of whatever Cesium assigns to CESIUM_WORKERS. The separate esbuild bundle of Cesium's workers is gone.
This commit is contained in:
1 parent
9e5ef78f91
commit
e82ab7440d
6 files changed
+38
-65
No files matched your search
+5
-18
@@ -1,16 +1,16 @@
|
|||||||
/**
|
/**
|
||||||
* The MCP Apps panel build. A panel loads the app through its MCP server,
|
* The MCP Apps panel build. A panel loads the app through its MCP server,
|
||||||
* one tool call per file (see src/tools/globePanel.js), so the app must be
|
* one tool call per file (see src/tools/globePanel.js), so the app must be
|
||||||
* few files: one app script, one stylesheet, Cesium's own script, and
|
* few files: one app script, one stylesheet, and Cesium's own script, which
|
||||||
* Cesium's workers combined into one script that Cesium runs from memory.
|
* carries its workers and starts them from memory. The build is served at
|
||||||
* The build is served at PANEL_BASE next to the app.
|
* PANEL_BASE next to the app.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// The panel loads these paths (src/tools/globePanel.js); a test keeps the
|
// The panel loads these paths (src/tools/globePanel.js); a test keeps the
|
||||||
// two in step.
|
// two in step.
|
||||||
export const PANEL_BASE = '/panel/';
|
export const PANEL_BASE = '/panel/';
|
||||||
/** Cesium's workers as one script, relative to the panel build. */
|
/** The script the panel runs ahead of Cesium's workers (workerFilesPrelude). */
|
||||||
export const PANEL_WORKERS_PATH = 'cesium/workers.js';
|
export const PANEL_WORKER_PRELUDE_PATH = 'cesium/worker-prelude.js';
|
||||||
export const PANEL_OUT_DIR = 'dist/panel';
|
export const PANEL_OUT_DIR = 'dist/panel';
|
||||||
|
|
||||||
/** A browser Vite config changed to produce the panel build. */
|
/** A browser Vite config changed to produce the panel build. */
|
||||||
@@ -32,19 +32,6 @@ export function panelBuildConfig(config) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Source for Cesium's `CESIUM_WORKERS` script: every worker module, each
|
|
||||||
* evaluated only when Cesium starts that worker. `workerNames` are the
|
|
||||||
* module names in Cesium's Workers directory, without `.js`.
|
|
||||||
*/
|
|
||||||
export function workersEntrySource(workerNames, workersDir) {
|
|
||||||
const entries = workerNames.map(
|
|
||||||
(name) =>
|
|
||||||
` ${JSON.stringify(name)}: () => import(${JSON.stringify(`${workersDir}/${name}.js`)}),`,
|
|
||||||
);
|
|
||||||
return `self.CesiumWorkers = {\n${entries.join('\n')}\n};\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CONTENT_TYPES = {
|
const CONTENT_TYPES = {
|
||||||
'.css': 'text/css',
|
'.css': 'text/css',
|
||||||
'.geojsonl': 'application/geo+json-seq',
|
'.geojsonl': 'application/geo+json-seq',
|
||||||
|
|||||||
+4
-2
@@ -133,8 +133,10 @@ provider keys.
|
|||||||
|
|
||||||
The panel loads the app's panel build, which `npm run build:panel` writes to
|
The panel loads the app's panel build, which `npm run build:panel` writes to
|
||||||
`dist/panel` and the servers serve at `/panel/`: one app script, one
|
`dist/panel` and the servers serve at `/panel/`: one app script, one
|
||||||
stylesheet, Cesium's script, and Cesium's workers combined into one script
|
stylesheet, and Cesium's script, which carries its workers and starts them
|
||||||
that Cesium runs from memory (`CESIUM_WORKERS`). Rebuild it after changing
|
from memory (`CESIUM_WORKERS`). Files those workers load themselves are
|
||||||
|
embedded in a prelude the panel runs ahead of them, since a worker's
|
||||||
|
requests reach the panel page's own site. Rebuild it after changing
|
||||||
the app.
|
the app.
|
||||||
|
|
||||||
Hosts differ in ways the panel works around, all inside the panel only:
|
Hosts differ in ways the panel works around, all inside the panel only:
|
||||||
|
|||||||
+6
-22
@@ -4,25 +4,22 @@
|
|||||||
* See build/panel.js.
|
* See build/panel.js.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { readFile, readdir, rename, rm, writeFile } from 'node:fs/promises';
|
import { readFile, rename, rm, writeFile } from 'node:fs/promises';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { build as esbuild } from 'esbuild';
|
|
||||||
import { build } from 'vite';
|
import { build } from 'vite';
|
||||||
import standaloneConfig from '../server/standalone/vite.config.js';
|
import standaloneConfig from '../server/standalone/vite.config.js';
|
||||||
import {
|
import {
|
||||||
PANEL_BASE,
|
PANEL_BASE,
|
||||||
PANEL_OUT_DIR,
|
PANEL_OUT_DIR,
|
||||||
PANEL_WORKER_FILES,
|
PANEL_WORKER_FILES,
|
||||||
PANEL_WORKERS_PATH,
|
PANEL_WORKER_PRELUDE_PATH,
|
||||||
panelBuildConfig,
|
panelBuildConfig,
|
||||||
workerFilesPrelude,
|
workerFilesPrelude,
|
||||||
workersEntrySource,
|
|
||||||
} from '../build/panel.js';
|
} from '../build/panel.js';
|
||||||
|
|
||||||
const root = fileURLToPath(new URL('../', import.meta.url));
|
const root = fileURLToPath(new URL('../', import.meta.url));
|
||||||
const outDir = join(root, PANEL_OUT_DIR);
|
const outDir = join(root, PANEL_OUT_DIR);
|
||||||
const cesiumWorkers = join(root, 'node_modules/cesium/Build/Cesium/Workers');
|
|
||||||
|
|
||||||
const config = standaloneConfig({ command: 'build', mode: 'production' });
|
const config = standaloneConfig({ command: 'build', mode: 'production' });
|
||||||
await build({
|
await build({
|
||||||
@@ -37,26 +34,13 @@ await rm(join(outDir, 'cesium'), { recursive: true, force: true });
|
|||||||
await rename(nested, join(outDir, 'cesium'));
|
await rename(nested, join(outDir, 'cesium'));
|
||||||
await rm(join(outDir, PANEL_BASE.split('/')[1]), { recursive: true });
|
await rm(join(outDir, PANEL_BASE.split('/')[1]), { recursive: true });
|
||||||
|
|
||||||
const names = (await readdir(cesiumWorkers))
|
// Cesium's workers load these files themselves; embed them in a prelude the
|
||||||
.filter((file) => file.endsWith('.js') && !file.startsWith('chunk-'))
|
// panel runs ahead of Cesium's workers script.
|
||||||
.map((file) => file.slice(0, -3));
|
|
||||||
const entry = join(outDir, 'cesium', 'workers-entry.js');
|
|
||||||
await writeFile(entry, workersEntrySource(names, cesiumWorkers));
|
|
||||||
await esbuild({
|
|
||||||
entryPoints: [entry],
|
|
||||||
bundle: true,
|
|
||||||
format: 'iife',
|
|
||||||
minify: true,
|
|
||||||
outfile: join(outDir, PANEL_WORKERS_PATH),
|
|
||||||
logLevel: 'warning',
|
|
||||||
});
|
|
||||||
await rm(entry);
|
|
||||||
const files = {};
|
const files = {};
|
||||||
for (const name of PANEL_WORKER_FILES)
|
for (const name of PANEL_WORKER_FILES)
|
||||||
files[name] = await readFile(join(outDir, 'cesium', name), 'utf8');
|
files[name] = await readFile(join(outDir, 'cesium', name), 'utf8');
|
||||||
const workers = join(outDir, PANEL_WORKERS_PATH);
|
|
||||||
await writeFile(
|
await writeFile(
|
||||||
workers,
|
join(outDir, PANEL_WORKER_PRELUDE_PATH),
|
||||||
workerFilesPrelude(files) + (await readFile(workers, 'utf8')),
|
workerFilesPrelude(files),
|
||||||
);
|
);
|
||||||
console.log(`Panel build written to ${PANEL_OUT_DIR}`);
|
console.log(`Panel build written to ${PANEL_OUT_DIR}`);
|
||||||
@@ -489,14 +489,25 @@ export function panelRuntime(config) {
|
|||||||
'text/html',
|
'text/html',
|
||||||
);
|
);
|
||||||
window.CESIUM_BASE_URL = `${config.panelBase}cesium/`;
|
window.CESIUM_BASE_URL = `${config.panelBase}cesium/`;
|
||||||
const [workers] = await Promise.all([
|
const [prelude] = await Promise.all([
|
||||||
appFetch(config.panelBase + config.workersPath).then((r) => r.text()),
|
appFetch(config.panelBase + config.workerPreludePath).then((r) =>
|
||||||
|
r.text(),
|
||||||
|
),
|
||||||
...[...built.head.querySelectorAll('link[rel="stylesheet"]')].map(
|
...[...built.head.querySelectorAll('link[rel="stylesheet"]')].map(
|
||||||
(link) => addStylesheet(link.getAttribute('href')),
|
(link) => addStylesheet(link.getAttribute('href')),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
// Cesium starts its workers from this script instead of from files.
|
// Cesium's script sets CESIUM_WORKERS, its workers as one script it
|
||||||
window.CESIUM_WORKERS = workers;
|
// starts from memory. Workers request files themselves, which this page
|
||||||
|
// cannot answer, so the prelude, holding those files, runs ahead of it.
|
||||||
|
let workers;
|
||||||
|
Object.defineProperty(window, 'CESIUM_WORKERS', {
|
||||||
|
configurable: true,
|
||||||
|
get: () => workers,
|
||||||
|
set: (script) => {
|
||||||
|
workers = prelude + script;
|
||||||
|
},
|
||||||
|
});
|
||||||
// Images in the markup load their files once added; give them the
|
// Images in the markup load their files once added; give them the
|
||||||
// files instead of letting them request this page's site.
|
// files instead of letting them request this page's site.
|
||||||
const images = [];
|
const images = [];
|
||||||
|
|||||||
@@ -6,16 +6,18 @@ import test from 'node:test';
|
|||||||
import * as PANEL_PATHS from '../tools/globePanel.js';
|
import * as PANEL_PATHS from '../tools/globePanel.js';
|
||||||
import {
|
import {
|
||||||
PANEL_BASE,
|
PANEL_BASE,
|
||||||
PANEL_WORKERS_PATH,
|
PANEL_WORKER_PRELUDE_PATH,
|
||||||
panelBuildConfig,
|
panelBuildConfig,
|
||||||
panelBuildPlugin,
|
panelBuildPlugin,
|
||||||
workerFilesPrelude,
|
workerFilesPrelude,
|
||||||
workersEntrySource,
|
|
||||||
} from '../../build/panel.js';
|
} from '../../build/panel.js';
|
||||||
|
|
||||||
test('the panel loads the paths the panel build writes', () => {
|
test('the panel loads the paths the panel build writes', () => {
|
||||||
assert.equal(PANEL_BASE, PANEL_PATHS.PANEL_BASE);
|
assert.equal(PANEL_BASE, PANEL_PATHS.PANEL_BASE);
|
||||||
assert.equal(PANEL_WORKERS_PATH, PANEL_PATHS.PANEL_WORKERS_PATH);
|
assert.equal(
|
||||||
|
PANEL_WORKER_PRELUDE_PATH,
|
||||||
|
PANEL_PATHS.PANEL_WORKER_PRELUDE_PATH,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('the panel build is one script and one stylesheet under /panel/', () => {
|
test('the panel build is one script and one stylesheet under /panel/', () => {
|
||||||
@@ -30,19 +32,6 @@ test('the panel build is one script and one stylesheet under /panel/', () => {
|
|||||||
assert.equal(config.build.chunkSizeWarningLimit, 1500);
|
assert.equal(config.build.chunkSizeWarningLimit, 1500);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Cesium's workers load lazily from one script", () => {
|
|
||||||
const source = workersEntrySource(['createGeometry', 'decodeDraco'], '/w');
|
|
||||||
assert.match(source, /^self\.CesiumWorkers = \{/);
|
|
||||||
assert.match(
|
|
||||||
source,
|
|
||||||
/"createGeometry": \(\) => import\("\/w\/createGeometry\.js"\)/,
|
|
||||||
);
|
|
||||||
assert.match(
|
|
||||||
source,
|
|
||||||
/"decodeDraco": \(\) => import\("\/w\/decodeDraco\.js"\)/,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('the dev server serves the panel build and nothing outside it', async () => {
|
test('the dev server serves the panel build and nothing outside it', async () => {
|
||||||
const root = await mkdtemp(join(tmpdir(), 'panel-build-'));
|
const root = await mkdtemp(join(tmpdir(), 'panel-build-'));
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
export const GLOBE_PANEL_URI = 'ui://gods-eye-view/globe';
|
export const GLOBE_PANEL_URI = 'ui://gods-eye-view/globe';
|
||||||
/** Where the app's server serves its panel build (see build/panel.js). */
|
/** Where the app's server serves its panel build (see build/panel.js). */
|
||||||
export const PANEL_BASE = '/panel/';
|
export const PANEL_BASE = '/panel/';
|
||||||
/** Cesium's workers as one script, relative to the panel build. */
|
/** The script the panel runs ahead of Cesium's workers, in the build. */
|
||||||
export const PANEL_WORKERS_PATH = 'cesium/workers.js';
|
export const PANEL_WORKER_PRELUDE_PATH = 'cesium/worker-prelude.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sites the app's browser code loads from directly: map imagery, 3D tiles,
|
* Sites the app's browser code loads from directly: map imagery, 3D tiles,
|
||||||
@@ -63,7 +63,7 @@ function panelHtml(runtime) {
|
|||||||
panelHeight: PANEL_HEIGHT_PX,
|
panelHeight: PANEL_HEIGHT_PX,
|
||||||
protocolVersion: MCP_APPS_PROTOCOL_VERSION,
|
protocolVersion: MCP_APPS_PROTOCOL_VERSION,
|
||||||
toolName: PANEL_REQUEST_TOOL,
|
toolName: PANEL_REQUEST_TOOL,
|
||||||
workersPath: PANEL_WORKERS_PATH,
|
workerPreludePath: PANEL_WORKER_PRELUDE_PATH,
|
||||||
};
|
};
|
||||||
const script = `(${runtime})(${JSON.stringify(config)});`.replace(
|
const script = `(${runtime})(${JSON.stringify(config)});`.replace(
|
||||||
/<\/script/gi,
|
/<\/script/gi,
|
||||||
|
|||||||
Reference in new issue
Block a user