mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
Load the Cesium SDK and its widget styles only when a Cesium globe or a feature that needs it first runs
index.html no longer loads /cesium/Cesium.js and widgets.css: the Cesium scene loads both before it builds its viewer. A cold Navara start requests nothing of the Cesium library again, and qa-strict-cold-chunks asserts that without the known-gap allowance. The strict harness puts an accessor in place of the Cesium global on every page and fails a scenario that reads it before Cesium.js has run; GEV_QA_CESIUM_TRAP=record lists every such read site instead.
This commit is contained in:
1 parent
b8305de14b
commit
f89aee1eac
4 files changed
+93
-26
No files matched your search
+3
-1
@@ -186,7 +186,9 @@ export function createBrowserViteConfig({
|
|||||||
apiResponseHeadersPlugin(),
|
apiResponseHeadersPlugin(),
|
||||||
// Next, so no provider route answers a Host the server does not allow.
|
// Next, so no provider route answers a Host the server does not allow.
|
||||||
hostCheckPlugin(),
|
hostCheckPlugin(),
|
||||||
cesium(),
|
// Keep the SDK asset serving/copying and external imports, but let the
|
||||||
|
// scene load the script and stylesheet only when Cesium is requested.
|
||||||
|
{ ...cesium(), transformIndexHtml: undefined },
|
||||||
// Application views are Vue single-file components.
|
// Application views are Vue single-file components.
|
||||||
vue(VUE_PLUGIN_OPTIONS),
|
vue(VUE_PLUGIN_OPTIONS),
|
||||||
...plugins,
|
...plugins,
|
||||||
|
|||||||
@@ -7,13 +7,6 @@
|
|||||||
// Control: after a pick to the other engine, its code is requested, so the
|
// Control: after a pick to the other engine, its code is requested, so the
|
||||||
// detection sees what it is looking for.
|
// detection sees what it is looking for.
|
||||||
//
|
//
|
||||||
// Known gap: the production build externalizes Cesium to the global its
|
|
||||||
// index.html script defines, and engine-neutral modules still read that
|
|
||||||
// global when they load, so a cold Navara start loads Cesium.js and its
|
|
||||||
// widget styles too. That row is reported as a known gap (its control is
|
|
||||||
// that the detection does see Cesium.js) instead of failing the run; any
|
|
||||||
// other Cesium request at a cold Navara start still fails it.
|
|
||||||
//
|
|
||||||
// node scripts/qa-strict-cold-chunks.mjs http://127.0.0.1:4208
|
// node scripts/qa-strict-cold-chunks.mjs http://127.0.0.1:4208
|
||||||
|
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
@@ -46,10 +39,6 @@ const navaraCode = async (url) => {
|
|||||||
if (!pathname.endsWith('.js') || pathname.startsWith('/cesium/')) return [];
|
if (!pathname.endsWith('.js') || pathname.startsWith('/cesium/')) return [];
|
||||||
return markersOf(url);
|
return markersOf(url);
|
||||||
};
|
};
|
||||||
const KNOWN_COLD_NAVARA_CESIUM = new Set([
|
|
||||||
'/cesium/Cesium.js',
|
|
||||||
'/cesium/Widgets/widgets.css',
|
|
||||||
]);
|
|
||||||
const results = [];
|
const results = [];
|
||||||
strict.extra.contracts = results;
|
strict.extra.contracts = results;
|
||||||
await strict.run({ args: ['--use-angle=metal', '--enable-gpu'] }, async (b) => {
|
await strict.run({ args: ['--use-angle=metal', '--enable-gpu'] }, async (b) => {
|
||||||
@@ -80,33 +69,23 @@ await strict.run({ args: ['--use-angle=metal', '--enable-gpu'] }, async (b) => {
|
|||||||
found.push(new URL(url).pathname);
|
found.push(new URL(url).pathname);
|
||||||
return [...new Set(found)];
|
return [...new Set(found)];
|
||||||
};
|
};
|
||||||
const loaded = await otherCode(before);
|
|
||||||
const known =
|
|
||||||
start === 'navara'
|
|
||||||
? loaded.filter((path) => KNOWN_COLD_NAVARA_CESIUM.has(path))
|
|
||||||
: [];
|
|
||||||
const row = {
|
const row = {
|
||||||
start,
|
start,
|
||||||
otherEngine: other,
|
otherEngine: other,
|
||||||
loadedAtColdStart: loaded.filter((path) => !known.includes(path)),
|
loadedAtColdStart: await otherCode(before),
|
||||||
knownGap: known,
|
|
||||||
loadedAfterPick: (await otherCode(after)).length,
|
loadedAfterPick: (await otherCode(after)).length,
|
||||||
};
|
};
|
||||||
results.push(row);
|
results.push(row);
|
||||||
console.log(
|
console.log(
|
||||||
row.loadedAtColdStart.length
|
row.loadedAtColdStart.length ? 'FAIL' : 'PASS',
|
||||||
? 'FAIL'
|
|
||||||
: row.knownGap.length
|
|
||||||
? 'KNOWN GAP'
|
|
||||||
: 'PASS',
|
|
||||||
JSON.stringify(row),
|
JSON.stringify(row),
|
||||||
);
|
);
|
||||||
await p.close();
|
await p.close();
|
||||||
}
|
}
|
||||||
for (const row of results)
|
for (const row of results)
|
||||||
assert.ok(
|
assert.ok(
|
||||||
row.loadedAfterPick > 0 || row.knownGap.includes('/cesium/Cesium.js'),
|
row.loadedAfterPick > 0,
|
||||||
`control: ${row.otherEngine} code is detected when it loads`,
|
`control: picking ${row.otherEngine} loads its code`,
|
||||||
);
|
);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
results.filter((row) => row.loadedAtColdStart.length),
|
results.filter((row) => row.loadedAtColdStart.length),
|
||||||
|
|||||||
@@ -281,6 +281,7 @@ export async function installStrictNetwork(
|
|||||||
// requests, and a live answer would still show up as a violation.
|
// requests, and a live answer would still show up as a violation.
|
||||||
if (type === 'page' || type === 'iframe')
|
if (type === 'page' || type === 'iframe')
|
||||||
steps.push(intercept(session, type));
|
steps.push(intercept(session, type));
|
||||||
|
if (type === 'page') steps.push(trapCesiumGlobal(session, ledger));
|
||||||
await Promise.all(steps);
|
await Promise.all(steps);
|
||||||
};
|
};
|
||||||
const attach = async (sessionId, info, waiting) => {
|
const attach = async (sessionId, info, waiting) => {
|
||||||
@@ -317,6 +318,78 @@ export async function installStrictNetwork(
|
|||||||
return ledger;
|
return ledger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The production build reads every `cesium` import from the global that
|
||||||
|
* /cesium/Cesium.js defines, and the page loads that script only when a
|
||||||
|
* Cesium globe first starts. A read of the global before then throws in the
|
||||||
|
* app (a Navara page has no Cesium at all), wherever the app catches it, so
|
||||||
|
* each page gets an accessor in place of the global: reads before the script
|
||||||
|
* has assigned it are logged with their stack in `ledger.cesiumBeforeLoad`
|
||||||
|
* and answer `undefined`, as production would.
|
||||||
|
*
|
||||||
|
* GEV_QA_CESIUM_TRAP=record (a survey, not a check) answers such a read with
|
||||||
|
* the SDK instead, loaded synchronously on the first one, and logs every
|
||||||
|
* distinct read site until the page itself loads Cesium.js, so one run lists
|
||||||
|
* all the Navara paths that still need Cesium.
|
||||||
|
*/
|
||||||
|
async function trapCesiumGlobal(session, ledger) {
|
||||||
|
const binding = '__gevStrictCesiumRead';
|
||||||
|
const record = process.env.GEV_QA_CESIUM_TRAP === 'record';
|
||||||
|
session.on('Runtime.bindingCalled', (event) => {
|
||||||
|
if (event.name !== binding) return;
|
||||||
|
const stack = String(event.payload).slice(0, 1500);
|
||||||
|
const known = ledger.cesiumBeforeLoad.find((read) => read.stack === stack);
|
||||||
|
if (known) known.count++;
|
||||||
|
else if (ledger.cesiumBeforeLoad.length < (record ? 2000 : 50))
|
||||||
|
ledger.cesiumBeforeLoad.push({ stack, count: 1 });
|
||||||
|
});
|
||||||
|
await session.send('Runtime.enable');
|
||||||
|
await session.send('Runtime.addBinding', { name: binding });
|
||||||
|
await session.send('Page.enable');
|
||||||
|
await session.send('Page.addScriptToEvaluateOnNewDocument', {
|
||||||
|
source: `(() => {
|
||||||
|
if (window.top !== window) return;
|
||||||
|
const record = ${record};
|
||||||
|
const seen = new Set();
|
||||||
|
let sdk;
|
||||||
|
let pageLoaded = false;
|
||||||
|
const report = () => {
|
||||||
|
const limit = Error.stackTraceLimit;
|
||||||
|
Error.stackTraceLimit = 12;
|
||||||
|
const stack = String(new Error('Cesium read before it loaded').stack);
|
||||||
|
Error.stackTraceLimit = limit;
|
||||||
|
const site = stack.split('\\n').slice(2, 6).join('\\n');
|
||||||
|
if (seen.has(site)) return;
|
||||||
|
seen.add(site);
|
||||||
|
window.${binding}?.(stack);
|
||||||
|
};
|
||||||
|
Object.defineProperty(window, 'Cesium', {
|
||||||
|
configurable: true,
|
||||||
|
get() {
|
||||||
|
if (!record) {
|
||||||
|
if (sdk === undefined) report();
|
||||||
|
return sdk;
|
||||||
|
}
|
||||||
|
if (!pageLoaded) {
|
||||||
|
pageLoaded = !!document.querySelector('script[src$="/Cesium.js"]');
|
||||||
|
if (!pageLoaded) report();
|
||||||
|
}
|
||||||
|
if (sdk === undefined) {
|
||||||
|
const request = new XMLHttpRequest();
|
||||||
|
request.open('GET', '/cesium/Cesium.js', false);
|
||||||
|
request.send();
|
||||||
|
(0, eval)(request.responseText);
|
||||||
|
}
|
||||||
|
return sdk;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
sdk = value;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})();`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** A new, empty network ledger. */
|
/** A new, empty network ledger. */
|
||||||
export function networkLedger() {
|
export function networkLedger() {
|
||||||
return {
|
return {
|
||||||
@@ -336,6 +409,7 @@ export function networkLedger() {
|
|||||||
},
|
},
|
||||||
violations: [],
|
violations: [],
|
||||||
setupErrors: [],
|
setupErrors: [],
|
||||||
|
cesiumBeforeLoad: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -681,6 +755,7 @@ export function createStrict({
|
|||||||
tileCache: ledger.tileCache,
|
tileCache: ledger.tileCache,
|
||||||
violations: ledger.violations,
|
violations: ledger.violations,
|
||||||
setupErrors: ledger.setupErrors,
|
setupErrors: ledger.setupErrors,
|
||||||
|
cesiumBeforeLoad: ledger.cesiumBeforeLoad,
|
||||||
fixtures,
|
fixtures,
|
||||||
tileHosts: [...tileHosts],
|
tileHosts: [...tileHosts],
|
||||||
};
|
};
|
||||||
@@ -714,10 +789,13 @@ export function createStrict({
|
|||||||
picks: picks.length,
|
picks: picks.length,
|
||||||
requests: ledger.requests,
|
requests: ledger.requests,
|
||||||
violations: ledger.violations.length,
|
violations: ledger.violations.length,
|
||||||
|
cesiumBeforeLoad: ledger.cesiumBeforeLoad.length,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
for (const v of ledger.violations.slice(0, 20))
|
for (const v of ledger.violations.slice(0, 20))
|
||||||
console.log('NETWORK VIOLATION', JSON.stringify(v));
|
console.log('NETWORK VIOLATION', JSON.stringify(v));
|
||||||
|
for (const read of ledger.cesiumBeforeLoad.slice(0, 10))
|
||||||
|
console.log('CESIUM BEFORE LOAD', JSON.stringify(read));
|
||||||
if (failed) return;
|
if (failed) return;
|
||||||
assert.equal(
|
assert.equal(
|
||||||
ledger.violations.length,
|
ledger.violations.length,
|
||||||
@@ -725,6 +803,11 @@ export function createStrict({
|
|||||||
'network policy violations: ' +
|
'network policy violations: ' +
|
||||||
JSON.stringify(ledger.violations.slice(0, 5)),
|
JSON.stringify(ledger.violations.slice(0, 5)),
|
||||||
);
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
ledger.cesiumBeforeLoad,
|
||||||
|
[],
|
||||||
|
'the page read the Cesium global before Cesium.js loaded',
|
||||||
|
);
|
||||||
assert.deepEqual(missing, [], 'layers without an assertion');
|
assert.deepEqual(missing, [], 'layers without an assertion');
|
||||||
assert.ok(
|
assert.ok(
|
||||||
picks.some((pick) => pick.via === 'pointer+keyboard'),
|
picks.some((pick) => pick.via === 'pointer+keyboard'),
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
import { describeError } from './errors.js';
|
import { describeError } from './errors.js';
|
||||||
import { createSceneEngine } from './globeEngine.js';
|
import { createSceneEngine } from './globeEngine.js';
|
||||||
import { onLocaleChange, t } from '../i18n/index.js';
|
import { onLocaleChange, t } from '../i18n/index.js';
|
||||||
|
import { loadCesium } from './loadCesium.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct the application globe using the caller's local configuration.
|
* Construct the application globe using the caller's local configuration.
|
||||||
@@ -139,6 +140,8 @@ async function createRenderer({
|
|||||||
}
|
}
|
||||||
if (engineKind !== 'cesium')
|
if (engineKind !== 'cesium')
|
||||||
throw new TypeError(`Unknown globe engine: ${engineKind}`);
|
throw new TypeError(`Unknown globe engine: ${engineKind}`);
|
||||||
|
await loadCesium();
|
||||||
|
signal.throwIfAborted();
|
||||||
loaderStatus.textContent = t('Configuring viewer...');
|
loaderStatus.textContent = t('Configuring viewer...');
|
||||||
// Provider attribution stays visible, including clean-view and recording.
|
// Provider attribution stays visible, including clean-view and recording.
|
||||||
const creditContainer = document.createElement('div');
|
const creditContainer = document.createElement('div');
|
||||||
|
|||||||
Reference in new issue
Block a user