@mapvx/web-js 3.5.0-dev.2 → 3.5.0-dev.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,7 +14,7 @@ const browser_1 = require("@sentry/browser");
14
14
  // exists only for the type-checker, so in the ES/CJS builds the identifier is
15
15
  // genuinely absent and a direct comparison throws ReferenceError at module load.
16
16
  // `typeof` is the only safe way to probe a possibly-undeclared global.
17
- const SDK_VERSION = typeof VERSION === "undefined" ? "3.5.0-dev.2" : VERSION;
17
+ const SDK_VERSION = typeof VERSION === "undefined" ? "3.5.0-dev.3" : VERSION;
18
18
  const DSN = typeof SENTRY_DSN !== "undefined" && SENTRY_DSN
19
19
  ? SENTRY_DSN
20
20
  : "https://872f598f020e3cd73a0933b562d24c81@sentry.mapvx.app/5";
@@ -1,35 +1,70 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_GLB_LOAD_TIMEOUT_MS = void 0;
4
+ exports.createLazyMeshoptDecoder = createLazyMeshoptDecoder;
4
5
  exports.loadGlbRoot = loadGlbRoot;
5
6
  const draco_1 = require("../config/draco");
6
7
  const three_1 = require("./three");
8
+ /**
9
+ * Builds a stand-in meshopt decoder that defers importing the real module (and instantiating its
10
+ * WASM) until the first `EXT_meshopt_compression` buffer actually needs decoding. GLBs without the
11
+ * extension never trigger the import, so the decoder stays off the critical path of the first 3D
12
+ * frame — it used to be part of the eager three.js import chain, delaying every scene load.
13
+ *
14
+ * `supported` mirrors the real module's own gate — it returns a bare `{ supported: false }` when
15
+ * `typeof WebAssembly !== "object"` — so the answer is reproduced synchronously here without
16
+ * importing anything. Reporting a flat `true` instead would break the platforms it claims to
17
+ * support: `GLTFLoader` reads `supported` before deciding to decode, and on `false` with meshopt
18
+ * merely OPTIONAL it returns `null` and falls back to the GLB's uncompressed buffer
19
+ * (`GLTFLoader.js` `GLTFMeshoptCompression.loadBufferView`). Claiming support on a WASM-less
20
+ * platform discards that fallback and fails the whole asset with a `TypeError` from this shim,
21
+ * since `decodeGltfBufferAsync` does not exist on the real module there.
22
+ *
23
+ * @param load Injectable module loader, for tests. Defaults to the cached {@link loadMeshoptDecoder}.
24
+ * @internal
25
+ */
26
+ function createLazyMeshoptDecoder(load = three_1.loadMeshoptDecoder) {
27
+ return {
28
+ // Same condition the real decoder uses, evaluated without loading it.
29
+ supported: typeof WebAssembly === "object",
30
+ decodeGltfBufferAsync: async (count, size, source, mode, filter) => {
31
+ const decoder = await load();
32
+ await decoder.ready;
33
+ return decoder.decodeGltfBufferAsync(count, size, source, mode, filter);
34
+ },
35
+ };
36
+ }
7
37
  /**
8
38
  * Lazily-initialized, cached GLTF loader configured with Draco + KTX2 support.
9
39
  *
10
40
  * The loaders (and their WebGLRenderer for KTX2 support detection) are heavy and pull in Three.js,
11
41
  * so they are created on first use inside the dynamic-import boundary rather than at module load.
42
+ *
43
+ * Memoized through {@link memoizeImport} for the same reason the loaders in `three.ts` are: a plain
44
+ * `cached ??=` also caches a rejection. Fixing the three loaders was not enough, because this is a
45
+ * SECOND cache wrapped around `loadThree()` — so a transient failure was evicted there and then
46
+ * replayed from here forever, and `loadGlbRoot` awaits both, meaning every GLB kept failing with
47
+ * the stale error long after `loadThree()` had recovered. Not only network: the `.then` below
48
+ * constructs a `WebGLRenderer` for KTX2 support detection, and a failed context creation was
49
+ * cached just the same.
12
50
  */
13
- let gltfLoaderPromise;
14
- function getGltfLoader() {
15
- gltfLoaderPromise !== null && gltfLoaderPromise !== void 0 ? gltfLoaderPromise : (gltfLoaderPromise = (0, three_1.loadThree)().then((mod) => {
16
- const dracoLoader = new mod.DRACOLoader();
17
- dracoLoader.setDecoderPath(draco_1.DEFAULT_DRACO_DECODER_PATH);
18
- const gltfLoader = new mod.GLTFLoader();
19
- gltfLoader.setDRACOLoader(dracoLoader);
20
- const ktx2Loader = new mod.KTX2Loader();
21
- ktx2Loader.setTranscoderPath(draco_1.DEFAULT_KTX2_TRANSCODER_PATH);
22
- gltfLoader.setKTX2Loader(ktx2Loader);
23
- ktx2Loader.detectSupport(new mod.THREE.WebGLRenderer({ antialias: true }));
24
- // Enable EXT_meshopt_compression so meshopt-compressed GLBs decode. The decoder is a WASM
25
- // singleton; GLTFLoader awaits its `.ready` promise internally before parsing. Assets that
26
- // don't use the extension are unaffected. This lets the offline pipeline pick meshopt (often
27
- // smaller than Draco for the scene's meshes) without a runtime change.
28
- gltfLoader.setMeshoptDecoder(mod.MeshoptDecoder);
29
- return gltfLoader;
30
- }));
31
- return gltfLoaderPromise;
32
- }
51
+ const getGltfLoader = (0, three_1.memoizeImport)(() => (0, three_1.loadThree)().then((mod) => {
52
+ const dracoLoader = new mod.DRACOLoader();
53
+ dracoLoader.setDecoderPath(draco_1.DEFAULT_DRACO_DECODER_PATH);
54
+ const gltfLoader = new mod.GLTFLoader();
55
+ gltfLoader.setDRACOLoader(dracoLoader);
56
+ const ktx2Loader = new mod.KTX2Loader();
57
+ ktx2Loader.setTranscoderPath(draco_1.DEFAULT_KTX2_TRANSCODER_PATH);
58
+ gltfLoader.setKTX2Loader(ktx2Loader);
59
+ ktx2Loader.detectSupport(new mod.THREE.WebGLRenderer({ antialias: true }));
60
+ // Enable EXT_meshopt_compression so meshopt-compressed GLBs decode, without paying for the
61
+ // decoder module up front: the lazy stand-in imports it (and instantiates its WASM) only when
62
+ // the first meshopt-compressed buffer is actually decoded. Assets that don't use the extension
63
+ // never load it. The cast is safe — with `decodeGltfBufferAsync` present, GLTFLoader touches
64
+ // only `supported` and `decodeGltfBufferAsync` (see LazyMeshoptDecoder).
65
+ gltfLoader.setMeshoptDecoder(createLazyMeshoptDecoder());
66
+ return gltfLoader;
67
+ }));
33
68
  /**
34
69
  * Default per-asset timeout for {@link loadGlbRoot}.
35
70
  *
@@ -1 +1 @@
1
- {"version":3,"file":"loadGlb.js","sourceRoot":"","sources":["../../../src/utils/loadGlb.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loadGlb.js","sourceRoot":"","sources":["../../../src/utils/loadGlb.ts"],"names":[],"mappings":"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"}
@@ -33,45 +33,81 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.loadThree = loadThree;
37
- exports.loadDeck = loadDeck;
38
- let threePromise;
39
- let deckPromise;
36
+ exports.loadDeck = exports.loadMeshoptDecoder = exports.loadThree = void 0;
37
+ exports.memoizeImport = memoizeImport;
38
+ /**
39
+ * Memoizes a dynamic-import chain, caching only a FULFILLED result.
40
+ *
41
+ * A plain `cached ??= import(...)` also memoizes a *rejection*, so one transient chunk-fetch
42
+ * failure (a dropped connection, a cache-busted deploy mid-session) permanently disables the
43
+ * feature for the rest of the page's life: every retry receives the same rejected promise and
44
+ * fails identically. The 3D scene retries on its own — `reloadScene3DModelsForLod` reloads GLB
45
+ * templates on every zoom-in past the LOD threshold — so a sticky rejection turns a blip into
46
+ * models that never come back until the user reloads.
47
+ *
48
+ * Concurrent callers still share one in-flight import (that is the point of the cache); only the
49
+ * rejected promise is evicted, and the error is re-thrown so every current caller still sees it.
50
+ *
51
+ * Exported only so the eviction behaviour can be tested directly — the loaders below wrap real
52
+ * dynamic `import()` calls, which a unit test cannot fail on demand.
53
+ *
54
+ * @param load Builds the import promise. Called again on the first retry after a failure.
55
+ * @returns An accessor that imports at most once per successful load.
56
+ * @internal
57
+ */
58
+ function memoizeImport(load) {
59
+ let cached;
60
+ return () => {
61
+ cached !== null && cached !== void 0 ? cached : (cached = load().catch((error) => {
62
+ // Evict BEFORE re-throwing so the next call starts a fresh import. Safe to assign here:
63
+ // a promise never settles synchronously, so `cached` is already assigned by now.
64
+ cached = undefined;
65
+ throw error;
66
+ }));
67
+ return cached;
68
+ };
69
+ }
40
70
  /**
41
71
  * Dynamically imports Three.js and the GLTF/DRACO/KTX2 loaders once and caches the result.
42
72
  * Subsequent calls return the same promise, so a single Three.js instance is shared.
73
+ * A failed import is not cached — see {@link memoizeImport}.
43
74
  */
44
- function loadThree() {
45
- threePromise !== null && threePromise !== void 0 ? threePromise : (threePromise = Promise.all([
46
- Promise.resolve().then(() => __importStar(require("three"))),
47
- Promise.resolve().then(() => __importStar(require("three/addons/loaders/GLTFLoader.js"))),
48
- Promise.resolve().then(() => __importStar(require("three/addons/loaders/DRACOLoader.js"))),
49
- Promise.resolve().then(() => __importStar(require("three/addons/loaders/KTX2Loader.js"))),
50
- Promise.resolve().then(() => __importStar(require("three/addons/libs/meshopt_decoder.module.js"))),
51
- ]).then(([three, gltf, draco, ktx2, meshopt]) => ({
52
- THREE: three,
53
- GLTFLoader: gltf.GLTFLoader,
54
- DRACOLoader: draco.DRACOLoader,
55
- KTX2Loader: ktx2.KTX2Loader,
56
- MeshoptDecoder: meshopt.MeshoptDecoder,
57
- })));
58
- return threePromise;
59
- }
75
+ exports.loadThree = memoizeImport(() => Promise.all([
76
+ Promise.resolve().then(() => __importStar(require("three"))),
77
+ Promise.resolve().then(() => __importStar(require("three/addons/loaders/GLTFLoader.js"))),
78
+ Promise.resolve().then(() => __importStar(require("three/addons/loaders/DRACOLoader.js"))),
79
+ Promise.resolve().then(() => __importStar(require("three/addons/loaders/KTX2Loader.js"))),
80
+ ]).then(([three, gltf, draco, ktx2]) => ({
81
+ THREE: three,
82
+ GLTFLoader: gltf.GLTFLoader,
83
+ DRACOLoader: draco.DRACOLoader,
84
+ KTX2Loader: ktx2.KTX2Loader,
85
+ })));
86
+ /**
87
+ * Dynamically imports the singleton meshopt decoder once and caches the result.
88
+ *
89
+ * Deliberately NOT part of {@link loadThree}'s import chain: only GLBs compressed with
90
+ * `EXT_meshopt_compression` need it, so keeping it out of the eager `Promise.all` keeps the
91
+ * decoder module (and its WASM instantiation) off the critical path of the first 3D frame.
92
+ * It is fetched on the first meshopt buffer decode instead — see the lazy wrapper in
93
+ * `loadGlb.ts`. That moves the fetch inside `parse()`, competing with hundreds of MB of GLB
94
+ * downloads, so not caching a failed import (see {@link memoizeImport}) matters more here than
95
+ * for the eager loaders.
96
+ */
97
+ exports.loadMeshoptDecoder = memoizeImport(() => Promise.resolve().then(() => __importStar(require("three/addons/libs/meshopt_decoder.module.js"))).then((meshopt) => meshopt.MeshoptDecoder));
60
98
  /**
61
99
  * Dynamically imports the deck.gl overlay and layer classes once and caches the result.
100
+ * A failed import is not cached — see {@link memoizeImport}.
62
101
  */
63
- function loadDeck() {
64
- deckPromise !== null && deckPromise !== void 0 ? deckPromise : (deckPromise = Promise.all([
65
- Promise.resolve().then(() => __importStar(require("@deck.gl/mapbox"))),
66
- Promise.resolve().then(() => __importStar(require("@deck.gl/geo-layers"))),
67
- Promise.resolve().then(() => __importStar(require("@deck.gl/layers"))),
68
- ]).then(([mapbox, geoLayers, layers]) => ({
69
- MapboxOverlay: mapbox.MapboxOverlay,
70
- MVTLayer: geoLayers.MVTLayer,
71
- IconLayer: layers.IconLayer,
72
- PathLayer: layers.PathLayer,
73
- TextLayer: layers.TextLayer,
74
- })));
75
- return deckPromise;
76
- }
102
+ exports.loadDeck = memoizeImport(() => Promise.all([
103
+ Promise.resolve().then(() => __importStar(require("@deck.gl/mapbox"))),
104
+ Promise.resolve().then(() => __importStar(require("@deck.gl/geo-layers"))),
105
+ Promise.resolve().then(() => __importStar(require("@deck.gl/layers"))),
106
+ ]).then(([mapbox, geoLayers, layers]) => ({
107
+ MapboxOverlay: mapbox.MapboxOverlay,
108
+ MVTLayer: geoLayers.MVTLayer,
109
+ IconLayer: layers.IconLayer,
110
+ PathLayer: layers.PathLayer,
111
+ TextLayer: layers.TextLayer,
112
+ })));
77
113
  //# sourceMappingURL=three.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"three.js","sourceRoot":"","sources":["../../../src/utils/three.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DA,8BAeC;AAKD,4BAaC;AAxCD,IAAI,YAA8C,CAAA;AAClD,IAAI,WAA4C,CAAA;AAEhD;;;GAGG;AACH,SAAgB,SAAS;IACvB,YAAY,aAAZ,YAAY,cAAZ,YAAY,IAAZ,YAAY,GAAK,OAAO,CAAC,GAAG,CAAC;0DACpB,OAAO;0DACP,oCAAoC;0DACpC,qCAAqC;0DACrC,oCAAoC;0DACpC,6CAA6C;KACrD,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QAChD,KAAK,EAAE,KAAK;QACZ,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,cAAc,EAAE,OAAO,CAAC,cAAc;KACvC,CAAC,CAAC,EAAA;IACH,OAAO,YAAY,CAAA;AACrB,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ;IACtB,WAAW,aAAX,WAAW,cAAX,WAAW,IAAX,WAAW,GAAK,OAAO,CAAC,GAAG,CAAC;0DACnB,iBAAiB;0DACjB,qBAAqB;0DACrB,iBAAiB;KACzB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACxC,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC,CAAC,EAAA;IACH,OAAO,WAAW,CAAA;AACpB,CAAC"}
1
+ {"version":3,"file":"three.js","sourceRoot":"","sources":["../../../src/utils/three.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiEA,sCAWC;AA/BD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,SAAgB,aAAa,CAAI,IAAsB;IACrD,IAAI,MAA8B,CAAA;IAClC,OAAO,GAAG,EAAE;QACV,MAAM,aAAN,MAAM,cAAN,MAAM,IAAN,MAAM,GAAK,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACzC,wFAAwF;YACxF,iFAAiF;YACjF,MAAM,GAAG,SAAS,CAAA;YAClB,MAAM,KAAK,CAAA;QACb,CAAC,CAAC,EAAA;QACF,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;AACH,CAAC;AAED;;;;GAIG;AACU,QAAA,SAAS,GAA+B,aAAa,CAAC,GAAG,EAAE,CACtE,OAAO,CAAC,GAAG,CAAC;sDACH,OAAO;sDACP,oCAAoC;sDACpC,qCAAqC;sDACrC,oCAAoC;CAC5C,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IACvC,KAAK,EAAE,KAAK;IACZ,UAAU,EAAE,IAAI,CAAC,UAAU;IAC3B,WAAW,EAAE,KAAK,CAAC,WAAW;IAC9B,UAAU,EAAE,IAAI,CAAC,UAAU;CAC5B,CAAC,CAAC,CACJ,CAAA;AAED;;;;;;;;;;GAUG;AACU,QAAA,kBAAkB,GAAyC,aAAa,CAAC,GAAG,EAAE,CACzF,kDAAO,6CAA6C,IAAE,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAChG,CAAA;AAED;;;GAGG;AACU,QAAA,QAAQ,GAA8B,aAAa,CAAC,GAAG,EAAE,CACpE,OAAO,CAAC,GAAG,CAAC;sDACH,iBAAiB;sDACjB,qBAAqB;sDACrB,iBAAiB;CACzB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IACxC,aAAa,EAAE,MAAM,CAAC,aAAa;IACnC,QAAQ,EAAE,SAAS,CAAC,QAAQ;IAC5B,SAAS,EAAE,MAAM,CAAC,SAAS;IAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;IAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;CAC5B,CAAC,CAAC,CACJ,CAAA"}
@@ -10,7 +10,7 @@ import { BrowserClient, defaultStackParser, getDefaultIntegrations, makeFetchTra
10
10
  // exists only for the type-checker, so in the ES/CJS builds the identifier is
11
11
  // genuinely absent and a direct comparison throws ReferenceError at module load.
12
12
  // `typeof` is the only safe way to probe a possibly-undeclared global.
13
- const SDK_VERSION = typeof VERSION === "undefined" ? "3.5.0-dev.2" : VERSION;
13
+ const SDK_VERSION = typeof VERSION === "undefined" ? "3.5.0-dev.3" : VERSION;
14
14
  const DSN = typeof SENTRY_DSN !== "undefined" && SENTRY_DSN
15
15
  ? SENTRY_DSN
16
16
  : "https://872f598f020e3cd73a0933b562d24c81@sentry.mapvx.app/5";
@@ -1,4 +1,45 @@
1
1
  import type * as THREE from "three";
2
+ import type { MeshoptDecoder } from "three/addons/libs/meshopt_decoder.module.js";
3
+ /**
4
+ * The subset of the meshopt decoder contract `GLTFLoader` actually exercises when
5
+ * `decodeGltfBufferAsync` is present: it checks `supported`, then calls `decodeGltfBufferAsync`
6
+ * for each `EXT_meshopt_compression` buffer view (never touching `ready`/`decodeGltfBuffer`).
7
+ *
8
+ * The signature is derived from the module type again, now that
9
+ * `src/types/three-addons.d.ts` declares the decoder's shape directly instead of forwarding to
10
+ * `@types/three`'s unresolvable `export * from "meshoptimizer/decoder"` — which `skipLibCheck`
11
+ * swallowed, collapsing the lookup to `any`. Deriving keeps this interface and the delegation
12
+ * call in `createLazyMeshoptDecoder` checked against a single definition; hand-writing it here
13
+ * left the delegation itself unchecked, because the value it delegates to was still `any`.
14
+ *
15
+ * That definition is transcribed from three's JS, so it is an assertion about that file rather
16
+ * than a derivation from it: a three.js change needs the `.d.ts` updated by hand. What is
17
+ * compiler-enforced is that this shim and its consumers agree with it.
18
+ * @internal
19
+ */
20
+ export interface LazyMeshoptDecoder {
21
+ supported: boolean;
22
+ decodeGltfBufferAsync: (typeof MeshoptDecoder)["decodeGltfBufferAsync"];
23
+ }
24
+ /**
25
+ * Builds a stand-in meshopt decoder that defers importing the real module (and instantiating its
26
+ * WASM) until the first `EXT_meshopt_compression` buffer actually needs decoding. GLBs without the
27
+ * extension never trigger the import, so the decoder stays off the critical path of the first 3D
28
+ * frame — it used to be part of the eager three.js import chain, delaying every scene load.
29
+ *
30
+ * `supported` mirrors the real module's own gate — it returns a bare `{ supported: false }` when
31
+ * `typeof WebAssembly !== "object"` — so the answer is reproduced synchronously here without
32
+ * importing anything. Reporting a flat `true` instead would break the platforms it claims to
33
+ * support: `GLTFLoader` reads `supported` before deciding to decode, and on `false` with meshopt
34
+ * merely OPTIONAL it returns `null` and falls back to the GLB's uncompressed buffer
35
+ * (`GLTFLoader.js` `GLTFMeshoptCompression.loadBufferView`). Claiming support on a WASM-less
36
+ * platform discards that fallback and fails the whole asset with a `TypeError` from this shim,
37
+ * since `decodeGltfBufferAsync` does not exist on the real module there.
38
+ *
39
+ * @param load Injectable module loader, for tests. Defaults to the cached {@link loadMeshoptDecoder}.
40
+ * @internal
41
+ */
42
+ export declare function createLazyMeshoptDecoder(load?: () => Promise<typeof MeshoptDecoder>): LazyMeshoptDecoder;
2
43
  /**
3
44
  * Default per-asset timeout for {@link loadGlbRoot}.
4
45
  *
@@ -1 +1 @@
1
- {"version":3,"file":"loadGlb.d.ts","sourceRoot":"","sources":["../../../src/utils/loadGlb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAuCnC;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,2BAA2B,SAAU,CAAA;AAkClD,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;CAC5C;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAyEtB"}
1
+ {"version":3,"file":"loadGlb.d.ts","sourceRoot":"","sources":["../../../src/utils/loadGlb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAEnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAA;AAIjF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAA;IAClB,qBAAqB,EAAE,CAAC,OAAO,cAAc,CAAC,CAAC,uBAAuB,CAAC,CAAA;CACxE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,GAAE,MAAM,OAAO,CAAC,OAAO,cAAc,CAAsB,GAC9D,kBAAkB,CAgBpB;AAwCD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,2BAA2B,SAAU,CAAA;AAkClD,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;CAC5C;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAyEtB"}
@@ -1,31 +1,65 @@
1
1
  import { DEFAULT_DRACO_DECODER_PATH, DEFAULT_KTX2_TRANSCODER_PATH } from "../config/draco";
2
- import { loadThree } from "./three";
2
+ import { loadMeshoptDecoder, loadThree, memoizeImport } from "./three";
3
+ /**
4
+ * Builds a stand-in meshopt decoder that defers importing the real module (and instantiating its
5
+ * WASM) until the first `EXT_meshopt_compression` buffer actually needs decoding. GLBs without the
6
+ * extension never trigger the import, so the decoder stays off the critical path of the first 3D
7
+ * frame — it used to be part of the eager three.js import chain, delaying every scene load.
8
+ *
9
+ * `supported` mirrors the real module's own gate — it returns a bare `{ supported: false }` when
10
+ * `typeof WebAssembly !== "object"` — so the answer is reproduced synchronously here without
11
+ * importing anything. Reporting a flat `true` instead would break the platforms it claims to
12
+ * support: `GLTFLoader` reads `supported` before deciding to decode, and on `false` with meshopt
13
+ * merely OPTIONAL it returns `null` and falls back to the GLB's uncompressed buffer
14
+ * (`GLTFLoader.js` `GLTFMeshoptCompression.loadBufferView`). Claiming support on a WASM-less
15
+ * platform discards that fallback and fails the whole asset with a `TypeError` from this shim,
16
+ * since `decodeGltfBufferAsync` does not exist on the real module there.
17
+ *
18
+ * @param load Injectable module loader, for tests. Defaults to the cached {@link loadMeshoptDecoder}.
19
+ * @internal
20
+ */
21
+ export function createLazyMeshoptDecoder(load = loadMeshoptDecoder) {
22
+ return {
23
+ // Same condition the real decoder uses, evaluated without loading it.
24
+ supported: typeof WebAssembly === "object",
25
+ decodeGltfBufferAsync: async (count, size, source, mode, filter) => {
26
+ const decoder = await load();
27
+ await decoder.ready;
28
+ return decoder.decodeGltfBufferAsync(count, size, source, mode, filter);
29
+ },
30
+ };
31
+ }
3
32
  /**
4
33
  * Lazily-initialized, cached GLTF loader configured with Draco + KTX2 support.
5
34
  *
6
35
  * The loaders (and their WebGLRenderer for KTX2 support detection) are heavy and pull in Three.js,
7
36
  * so they are created on first use inside the dynamic-import boundary rather than at module load.
37
+ *
38
+ * Memoized through {@link memoizeImport} for the same reason the loaders in `three.ts` are: a plain
39
+ * `cached ??=` also caches a rejection. Fixing the three loaders was not enough, because this is a
40
+ * SECOND cache wrapped around `loadThree()` — so a transient failure was evicted there and then
41
+ * replayed from here forever, and `loadGlbRoot` awaits both, meaning every GLB kept failing with
42
+ * the stale error long after `loadThree()` had recovered. Not only network: the `.then` below
43
+ * constructs a `WebGLRenderer` for KTX2 support detection, and a failed context creation was
44
+ * cached just the same.
8
45
  */
9
- let gltfLoaderPromise;
10
- function getGltfLoader() {
11
- gltfLoaderPromise !== null && gltfLoaderPromise !== void 0 ? gltfLoaderPromise : (gltfLoaderPromise = loadThree().then((mod) => {
12
- const dracoLoader = new mod.DRACOLoader();
13
- dracoLoader.setDecoderPath(DEFAULT_DRACO_DECODER_PATH);
14
- const gltfLoader = new mod.GLTFLoader();
15
- gltfLoader.setDRACOLoader(dracoLoader);
16
- const ktx2Loader = new mod.KTX2Loader();
17
- ktx2Loader.setTranscoderPath(DEFAULT_KTX2_TRANSCODER_PATH);
18
- gltfLoader.setKTX2Loader(ktx2Loader);
19
- ktx2Loader.detectSupport(new mod.THREE.WebGLRenderer({ antialias: true }));
20
- // Enable EXT_meshopt_compression so meshopt-compressed GLBs decode. The decoder is a WASM
21
- // singleton; GLTFLoader awaits its `.ready` promise internally before parsing. Assets that
22
- // don't use the extension are unaffected. This lets the offline pipeline pick meshopt (often
23
- // smaller than Draco for the scene's meshes) without a runtime change.
24
- gltfLoader.setMeshoptDecoder(mod.MeshoptDecoder);
25
- return gltfLoader;
26
- }));
27
- return gltfLoaderPromise;
28
- }
46
+ const getGltfLoader = memoizeImport(() => loadThree().then((mod) => {
47
+ const dracoLoader = new mod.DRACOLoader();
48
+ dracoLoader.setDecoderPath(DEFAULT_DRACO_DECODER_PATH);
49
+ const gltfLoader = new mod.GLTFLoader();
50
+ gltfLoader.setDRACOLoader(dracoLoader);
51
+ const ktx2Loader = new mod.KTX2Loader();
52
+ ktx2Loader.setTranscoderPath(DEFAULT_KTX2_TRANSCODER_PATH);
53
+ gltfLoader.setKTX2Loader(ktx2Loader);
54
+ ktx2Loader.detectSupport(new mod.THREE.WebGLRenderer({ antialias: true }));
55
+ // Enable EXT_meshopt_compression so meshopt-compressed GLBs decode, without paying for the
56
+ // decoder module up front: the lazy stand-in imports it (and instantiates its WASM) only when
57
+ // the first meshopt-compressed buffer is actually decoded. Assets that don't use the extension
58
+ // never load it. The cast is safe — with `decodeGltfBufferAsync` present, GLTFLoader touches
59
+ // only `supported` and `decodeGltfBufferAsync` (see LazyMeshoptDecoder).
60
+ gltfLoader.setMeshoptDecoder(createLazyMeshoptDecoder());
61
+ return gltfLoader;
62
+ }));
29
63
  /**
30
64
  * Default per-asset timeout for {@link loadGlbRoot}.
31
65
  *
@@ -1 +1 @@
1
- {"version":3,"file":"loadGlb.js","sourceRoot":"","sources":["../../../src/utils/loadGlb.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loadGlb.js","sourceRoot":"","sources":["../../../src/utils/loadGlb.ts"],"names":[],"mappings":"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"}
@@ -31,12 +31,6 @@ export interface ThreeModule {
31
31
  GLTFLoader: typeof GLTFLoader;
32
32
  DRACOLoader: typeof DRACOLoader;
33
33
  KTX2Loader: typeof KTX2Loader;
34
- /**
35
- * The singleton meshopt decoder. Wired into the GLB loader so assets compressed with
36
- * `EXT_meshopt_compression` (a much stronger geometry/vertex compressor than Draco for many
37
- * meshes) decode instead of failing. See {@link getGltfLoader} in `loadGlb.ts`.
38
- */
39
- MeshoptDecoder: typeof MeshoptDecoder;
40
34
  }
41
35
  /** Runtime handle to the deck.gl classes used by the 3D scene. */
42
36
  export interface DeckModule {
@@ -46,13 +40,48 @@ export interface DeckModule {
46
40
  PathLayer: typeof import("@deck.gl/layers").PathLayer;
47
41
  TextLayer: typeof import("@deck.gl/layers").TextLayer;
48
42
  }
43
+ /**
44
+ * Memoizes a dynamic-import chain, caching only a FULFILLED result.
45
+ *
46
+ * A plain `cached ??= import(...)` also memoizes a *rejection*, so one transient chunk-fetch
47
+ * failure (a dropped connection, a cache-busted deploy mid-session) permanently disables the
48
+ * feature for the rest of the page's life: every retry receives the same rejected promise and
49
+ * fails identically. The 3D scene retries on its own — `reloadScene3DModelsForLod` reloads GLB
50
+ * templates on every zoom-in past the LOD threshold — so a sticky rejection turns a blip into
51
+ * models that never come back until the user reloads.
52
+ *
53
+ * Concurrent callers still share one in-flight import (that is the point of the cache); only the
54
+ * rejected promise is evicted, and the error is re-thrown so every current caller still sees it.
55
+ *
56
+ * Exported only so the eviction behaviour can be tested directly — the loaders below wrap real
57
+ * dynamic `import()` calls, which a unit test cannot fail on demand.
58
+ *
59
+ * @param load Builds the import promise. Called again on the first retry after a failure.
60
+ * @returns An accessor that imports at most once per successful load.
61
+ * @internal
62
+ */
63
+ export declare function memoizeImport<T>(load: () => Promise<T>): () => Promise<T>;
49
64
  /**
50
65
  * Dynamically imports Three.js and the GLTF/DRACO/KTX2 loaders once and caches the result.
51
66
  * Subsequent calls return the same promise, so a single Three.js instance is shared.
67
+ * A failed import is not cached — see {@link memoizeImport}.
68
+ */
69
+ export declare const loadThree: () => Promise<ThreeModule>;
70
+ /**
71
+ * Dynamically imports the singleton meshopt decoder once and caches the result.
72
+ *
73
+ * Deliberately NOT part of {@link loadThree}'s import chain: only GLBs compressed with
74
+ * `EXT_meshopt_compression` need it, so keeping it out of the eager `Promise.all` keeps the
75
+ * decoder module (and its WASM instantiation) off the critical path of the first 3D frame.
76
+ * It is fetched on the first meshopt buffer decode instead — see the lazy wrapper in
77
+ * `loadGlb.ts`. That moves the fetch inside `parse()`, competing with hundreds of MB of GLB
78
+ * downloads, so not caching a failed import (see {@link memoizeImport}) matters more here than
79
+ * for the eager loaders.
52
80
  */
53
- export declare function loadThree(): Promise<ThreeModule>;
81
+ export declare const loadMeshoptDecoder: () => Promise<typeof MeshoptDecoder>;
54
82
  /**
55
83
  * Dynamically imports the deck.gl overlay and layer classes once and caches the result.
84
+ * A failed import is not cached — see {@link memoizeImport}.
56
85
  */
57
- export declare function loadDeck(): Promise<DeckModule>;
86
+ export declare const loadDeck: () => Promise<DeckModule>;
58
87
  //# sourceMappingURL=three.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"three.d.ts","sourceRoot":"","sources":["../../../src/utils/three.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAA;AAEjF,+DAA+D;AAC/D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,cAAc,OAAO,CAAC,CAAA;IAC7B,UAAU,EAAE,OAAO,UAAU,CAAA;IAC7B,WAAW,EAAE,OAAO,WAAW,CAAA;IAC/B,UAAU,EAAE,OAAO,UAAU,CAAA;IAC7B;;;;OAIG;IACH,cAAc,EAAE,OAAO,cAAc,CAAA;CACtC;AAED,kEAAkE;AAClE,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,cAAc,iBAAiB,EAAE,aAAa,CAAA;IAC7D,QAAQ,EAAE,cAAc,qBAAqB,EAAE,QAAQ,CAAA;IACvD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAA;IACrD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAA;IACrD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAA;CACtD;AAKD;;;GAGG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC,CAehD;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC,CAa9C"}
1
+ {"version":3,"file":"three.d.ts","sourceRoot":"","sources":["../../../src/utils/three.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAA;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAA;AAEjF,+DAA+D;AAC/D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,cAAc,OAAO,CAAC,CAAA;IAC7B,UAAU,EAAE,OAAO,UAAU,CAAA;IAC7B,WAAW,EAAE,OAAO,WAAW,CAAA;IAC/B,UAAU,EAAE,OAAO,UAAU,CAAA;CAC9B;AAED,kEAAkE;AAClE,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,cAAc,iBAAiB,EAAE,aAAa,CAAA;IAC7D,QAAQ,EAAE,cAAc,qBAAqB,EAAE,QAAQ,CAAA;IACvD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAA;IACrD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAA;IACrD,SAAS,EAAE,cAAc,iBAAiB,EAAE,SAAS,CAAA;CACtD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,CAWzE;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,MAAM,OAAO,CAAC,WAAW,CAYhD,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,OAAO,CAAC,OAAO,cAAc,CAEnE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,OAAO,CAAC,UAAU,CAY9C,CAAA"}
@@ -1,40 +1,76 @@
1
- let threePromise;
2
- let deckPromise;
1
+ /**
2
+ * Memoizes a dynamic-import chain, caching only a FULFILLED result.
3
+ *
4
+ * A plain `cached ??= import(...)` also memoizes a *rejection*, so one transient chunk-fetch
5
+ * failure (a dropped connection, a cache-busted deploy mid-session) permanently disables the
6
+ * feature for the rest of the page's life: every retry receives the same rejected promise and
7
+ * fails identically. The 3D scene retries on its own — `reloadScene3DModelsForLod` reloads GLB
8
+ * templates on every zoom-in past the LOD threshold — so a sticky rejection turns a blip into
9
+ * models that never come back until the user reloads.
10
+ *
11
+ * Concurrent callers still share one in-flight import (that is the point of the cache); only the
12
+ * rejected promise is evicted, and the error is re-thrown so every current caller still sees it.
13
+ *
14
+ * Exported only so the eviction behaviour can be tested directly — the loaders below wrap real
15
+ * dynamic `import()` calls, which a unit test cannot fail on demand.
16
+ *
17
+ * @param load Builds the import promise. Called again on the first retry after a failure.
18
+ * @returns An accessor that imports at most once per successful load.
19
+ * @internal
20
+ */
21
+ export function memoizeImport(load) {
22
+ let cached;
23
+ return () => {
24
+ cached !== null && cached !== void 0 ? cached : (cached = load().catch((error) => {
25
+ // Evict BEFORE re-throwing so the next call starts a fresh import. Safe to assign here:
26
+ // a promise never settles synchronously, so `cached` is already assigned by now.
27
+ cached = undefined;
28
+ throw error;
29
+ }));
30
+ return cached;
31
+ };
32
+ }
3
33
  /**
4
34
  * Dynamically imports Three.js and the GLTF/DRACO/KTX2 loaders once and caches the result.
5
35
  * Subsequent calls return the same promise, so a single Three.js instance is shared.
36
+ * A failed import is not cached — see {@link memoizeImport}.
6
37
  */
7
- export function loadThree() {
8
- threePromise !== null && threePromise !== void 0 ? threePromise : (threePromise = Promise.all([
9
- import("three"),
10
- import("three/addons/loaders/GLTFLoader.js"),
11
- import("three/addons/loaders/DRACOLoader.js"),
12
- import("three/addons/loaders/KTX2Loader.js"),
13
- import("three/addons/libs/meshopt_decoder.module.js"),
14
- ]).then(([three, gltf, draco, ktx2, meshopt]) => ({
15
- THREE: three,
16
- GLTFLoader: gltf.GLTFLoader,
17
- DRACOLoader: draco.DRACOLoader,
18
- KTX2Loader: ktx2.KTX2Loader,
19
- MeshoptDecoder: meshopt.MeshoptDecoder,
20
- })));
21
- return threePromise;
22
- }
38
+ export const loadThree = memoizeImport(() => Promise.all([
39
+ import("three"),
40
+ import("three/addons/loaders/GLTFLoader.js"),
41
+ import("three/addons/loaders/DRACOLoader.js"),
42
+ import("three/addons/loaders/KTX2Loader.js"),
43
+ ]).then(([three, gltf, draco, ktx2]) => ({
44
+ THREE: three,
45
+ GLTFLoader: gltf.GLTFLoader,
46
+ DRACOLoader: draco.DRACOLoader,
47
+ KTX2Loader: ktx2.KTX2Loader,
48
+ })));
49
+ /**
50
+ * Dynamically imports the singleton meshopt decoder once and caches the result.
51
+ *
52
+ * Deliberately NOT part of {@link loadThree}'s import chain: only GLBs compressed with
53
+ * `EXT_meshopt_compression` need it, so keeping it out of the eager `Promise.all` keeps the
54
+ * decoder module (and its WASM instantiation) off the critical path of the first 3D frame.
55
+ * It is fetched on the first meshopt buffer decode instead — see the lazy wrapper in
56
+ * `loadGlb.ts`. That moves the fetch inside `parse()`, competing with hundreds of MB of GLB
57
+ * downloads, so not caching a failed import (see {@link memoizeImport}) matters more here than
58
+ * for the eager loaders.
59
+ */
60
+ export const loadMeshoptDecoder = memoizeImport(() => import("three/addons/libs/meshopt_decoder.module.js").then((meshopt) => meshopt.MeshoptDecoder));
23
61
  /**
24
62
  * Dynamically imports the deck.gl overlay and layer classes once and caches the result.
63
+ * A failed import is not cached — see {@link memoizeImport}.
25
64
  */
26
- export function loadDeck() {
27
- deckPromise !== null && deckPromise !== void 0 ? deckPromise : (deckPromise = Promise.all([
28
- import("@deck.gl/mapbox"),
29
- import("@deck.gl/geo-layers"),
30
- import("@deck.gl/layers"),
31
- ]).then(([mapbox, geoLayers, layers]) => ({
32
- MapboxOverlay: mapbox.MapboxOverlay,
33
- MVTLayer: geoLayers.MVTLayer,
34
- IconLayer: layers.IconLayer,
35
- PathLayer: layers.PathLayer,
36
- TextLayer: layers.TextLayer,
37
- })));
38
- return deckPromise;
39
- }
65
+ export const loadDeck = memoizeImport(() => Promise.all([
66
+ import("@deck.gl/mapbox"),
67
+ import("@deck.gl/geo-layers"),
68
+ import("@deck.gl/layers"),
69
+ ]).then(([mapbox, geoLayers, layers]) => ({
70
+ MapboxOverlay: mapbox.MapboxOverlay,
71
+ MVTLayer: geoLayers.MVTLayer,
72
+ IconLayer: layers.IconLayer,
73
+ PathLayer: layers.PathLayer,
74
+ TextLayer: layers.TextLayer,
75
+ })));
40
76
  //# sourceMappingURL=three.js.map