Skip to content

Commit 5a156b7

Browse files
kubeclaude
authored andcommitted
Fix WebWorker compatibility with webpack consumers
@babel/standalone bundles the `debug` package which accesses `window` in its `useColors()` without a typeof guard. This causes a "window is not defined" ReferenceError when the simulation worker initializes in a Web Worker context. Fix by prepending `self.window = self` to worker bundle assets in the Vite lib build plugin, aliasing `window` to the Worker global scope. Also add temporary debug logging to simulation initialization flow to help diagnose an "Initialization cancelled" error when Petrinaut is embedded in HASH frontend. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a8e09f8 commit 5a156b7

4 files changed

Lines changed: 51 additions & 4 deletions

File tree

libs/@hashintel/petrinaut/src/playback/provider.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,13 +414,20 @@ export const PlaybackProvider: React.FC<PlaybackProviderProps> = ({
414414

415415
const play: PlaybackContextValue["play"] = async () => {
416416
const simState = simulationStateRef.current;
417+
console.log(
418+
"[Petrinaut:Debug] PlaybackProvider.play() called, simState:",
419+
simState,
420+
);
417421
const state = stateValuesRef.current;
418422
const { maxFramesAhead, batchSize } = getPlayModeBackpressure(
419423
state.playMode,
420424
);
421425

422426
// Initialize simulation if not run yet
423427
if (simState === "NotRun") {
428+
console.log(
429+
"[Petrinaut:Debug] PlaybackProvider.play() -> calling initialize (simState was NotRun)",
430+
);
424431
await initialize({
425432
seed: Date.now(),
426433
dt: dtRef.current,
@@ -429,6 +436,9 @@ export const PlaybackProvider: React.FC<PlaybackProviderProps> = ({
429436
});
430437
// Initialization complete - start simulation
431438
// The effect will set playbackState to "Playing" when simulation starts running
439+
console.log(
440+
"[Petrinaut:Debug] PlaybackProvider.play() -> initialization complete, calling runSimulation()",
441+
);
432442
runSimulation();
433443
return;
434444
}

libs/@hashintel/petrinaut/src/simulation/provider.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ export const SimulationProvider: React.FC<SimulationProviderProps> = ({
101101

102102
// Reinitialize when petriNetId changes
103103
useEffect(() => {
104+
console.log(
105+
"[Petrinaut:Debug] SimulationProvider: petriNetId changed to",
106+
petriNetId,
107+
"- calling reset()",
108+
);
104109
workerActions.reset();
105110
setStateValues(INITIAL_STATE_VALUES);
106111
}, [petriNetId, workerActions]);
@@ -155,6 +160,9 @@ export const SimulationProvider: React.FC<SimulationProviderProps> = ({
155160

156161
// Delegate to worker (maxTime is immutable once set at initialization)
157162
// Returns a promise that resolves when initialization is complete
163+
console.log(
164+
"[Petrinaut:Debug] SimulationProvider.initialize() called, delegating to worker",
165+
);
158166
return workerActions.initialize({
159167
sdcpn,
160168
initialMarking: currentState.initialMarking,

libs/@hashintel/petrinaut/src/simulation/worker/use-simulation-worker.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ export function useSimulationWorker(): {
137137

138138
switch (message.type) {
139139
case "ready":
140+
console.log(
141+
"[Petrinaut:Debug] Worker sent 'ready' message, resolving pending init",
142+
);
140143
setState((prev) => ({
141144
...prev,
142145
status: prev.status === "initializing" ? "ready" : prev.status,
@@ -177,6 +180,10 @@ export function useSimulationWorker(): {
177180
break;
178181

179182
case "error":
183+
console.error(
184+
"[Petrinaut:Debug] Worker sent 'error' message:",
185+
message.message,
186+
);
180187
setState((prev) => ({
181188
...prev,
182189
status: "error",
@@ -204,6 +211,7 @@ export function useSimulationWorker(): {
204211
workerRef.current = worker;
205212

206213
return () => {
214+
console.log("[Petrinaut:Debug] Worker terminated (useEffect cleanup)");
207215
worker.terminate();
208216
};
209217
}, []);
@@ -226,10 +234,14 @@ export function useSimulationWorker(): {
226234
}) => {
227235
// Cancel any pending initialization
228236
if (pendingInitRef.current) {
237+
console.warn(
238+
"[Petrinaut:Debug] Cancelling pending initialization - new initialize() called before previous resolved",
239+
);
229240
pendingInitRef.current.reject(new Error("Initialization cancelled"));
230241
pendingInitRef.current = null;
231242
}
232243

244+
console.log("[Petrinaut:Debug] useSimulationWorker.initialize() called");
233245
setState({
234246
status: "initializing",
235247
frames: [],
@@ -287,6 +299,7 @@ export function useSimulationWorker(): {
287299
};
288300

289301
const reset: WorkerActions["reset"] = () => {
302+
console.log("[Petrinaut:Debug] useSimulationWorker.reset() called");
290303
postMessage({ type: "stop" });
291304
setState(initialState);
292305
};

libs/@hashintel/petrinaut/vite.config.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,32 @@ export default defineConfig(({ mode }) => {
7171

7272
// Vite lib mode emits worker URLs as `"" + new URL("assets/...", import.meta.url).href`
7373
// wrapped in an outer `new URL(...)`. Simplify to `new URL("assets/...", import.meta.url)`.
74+
// Also shim `window` in worker chunks: @babel/standalone bundles the `debug` package
75+
// which accesses `window` in its `useColors()` without a typeof guard.
7476
isLibMode && {
75-
name: "simplify-worker-url",
77+
name: "fix-worker-bundle",
7678
generateBundle(_, bundle) {
77-
for (const chunk of Object.values(bundle)) {
78-
if (chunk.type === "chunk") {
79-
chunk.code = chunk.code.replace(
79+
for (const [fileName, item] of Object.entries(bundle)) {
80+
if (item.type === "chunk") {
81+
item.code = item.code.replace(
8082
/new URL\(\s*\/\* @vite-ignore \*\/\s*"" \+ new URL\(("assets\/[^"]+"), import\.meta\.url\)\.href,\s*import\.meta\.url\s*\)/g,
8183
"new URL($1, import.meta.url)",
8284
);
8385
}
86+
87+
// Prepend window shim to worker bundles so libraries that
88+
// access `window` (e.g. debug's useColors in @babel/standalone)
89+
// work in Web Workers
90+
if (fileName.includes("worker")) {
91+
if (item.type === "chunk") {
92+
item.code = `self.window = self;\n${item.code}`;
93+
} else if (
94+
item.type === "asset" &&
95+
typeof item.source === "string"
96+
) {
97+
item.source = `self.window = self;\n${item.source}`;
98+
}
99+
}
84100
}
85101
},
86102
},

0 commit comments

Comments
 (0)