fuzzyworld

tower / commit

Merge branch 'fix/worker-loading' into 'main'

b53509f4553b7f3c204ea5a7ab59a3ee780ea088 · Pavel Safronov · 2026-09-18 17:27:50 -0700 · parents 51c39d8bb65b 3413c443aa18

Merge branch 'fix/worker-loading' into 'main'

fix(terrain): bundle the terrain worker so builds stop hanging on "Reading the plans"

See merge request PavelSafronov/tower!1
 .gitlab-ci.yml         |  3 +++
 src/terrain/service.ts | 11 ++++++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cd728c4..529dfa6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,6 +18,9 @@ pages:
     # Fail loudly rather than publishing a 404. `mv` silently nests when the
     # destination exists, which is exactly how this broke the first time.
     - test -f public/index.html || (echo "no index.html at artifact root" && exit 1)
+    # The terrain worker must be bundled as its own chunk. When it was not, the build
+    # passed and the site hung forever on "Reading the plans" (service.ts).
+    - ls public/assets/worker-*.js || (echo "terrain worker was not bundled" && exit 1)
   artifacts:
     paths: [public]
   rules:
diff --git a/src/terrain/service.ts b/src/terrain/service.ts
index 94c327a..a6b7196 100644
--- a/src/terrain/service.ts
+++ b/src/terrain/service.ts
@@ -18,6 +18,15 @@ import type { CompiledWorld } from './compile.js'
 import { type Runtime, prepare } from './field.js'
 import type { TileData, TileGrid, TileKey } from './tile.js'
 import type { WorkerApi } from './worker.js'
+/**
+ * The worker, bundled as a worker, and its URL. This must go through Vite's `?worker`
+ * import: a bare `new URL('./worker.ts', import.meta.url)` held in a variable is not
+ * recognised as a worker, so the build copied worker.ts raw as an asset — inlined as a
+ * `data:video/mp2t` URL, since `.ts` is also the MPEG transport stream extension. The
+ * worker failed to start, nothing listened for that, and the first compile call waited
+ * forever on "Reading the plans". Dev served the file transformed, so only builds broke.
+ */
+import workerUrl from './worker.ts?worker&url'
 
 /** The map image, matching v1's raster so the map reads at the same resolution. */
 export const MAP_WIDTH = 2048
@@ -63,7 +72,7 @@ export class TerrainService {
 
   /** The compiled world was read from the cache last time rather than compiled. */
   lastFromCache = false
-  private readonly workerUrl = new URL('./worker.ts', import.meta.url)
+  private readonly workerUrl = new URL(workerUrl, import.meta.url)
   /**
    * Whether the compiled world may be cached. In a build the worker's URL carries a hash
    * of its code, so a new build can never read an old build's world. In dev the URL never