fix(js): return module eval on completion, not loop idle (Vite mount) (#380)
load_module and load_inline_module drove run_event_loop to full idle before reading the module's mod_evaluate result. A page timer keeps the loop busy forever (Vite's HMR / React-Refresh client installs a setInterval), so the preamble inline module burned the entire budget waiting for an idle that never came, and the later module that mounts the app was skipped, leaving #root empty while the production preview rendered fine (issue #374). Drive the event loop and the mod_evaluate result together and return as soon as the module finishes evaluating, so a busy background timer no longer starves the remaining modules. Post-eval async work is still drained by the normal post-load settle. Fixes #374.
This commit is contained in:
1 parent
68234970b1
commit
d3a8b9a482
1 file changed
+48
-30
@@ -664,25 +664,33 @@ impl ObscuraJsRuntime {
|
||||
};
|
||||
|
||||
let result = self.runtime.mod_evaluate(module_id);
|
||||
tokio::pin!(result);
|
||||
|
||||
let timeout = tokio::time::timeout(
|
||||
budget,
|
||||
self.runtime.run_event_loop(deno_core::PollEventLoopOptions::default()),
|
||||
).await;
|
||||
// Return as soon as the module finishes evaluating instead of waiting
|
||||
// for the event loop to go fully idle: a page timer (setInterval) keeps
|
||||
// the loop busy forever and would otherwise burn the whole budget, so a
|
||||
// module that had already evaluated got abandoned (issue #374).
|
||||
let outcome = tokio::time::timeout(budget, async {
|
||||
let event_loop = self
|
||||
.runtime
|
||||
.run_event_loop(deno_core::PollEventLoopOptions::default());
|
||||
tokio::pin!(event_loop);
|
||||
tokio::select! {
|
||||
biased;
|
||||
r = &mut result => r,
|
||||
e = &mut event_loop => { e?; (&mut result).await }
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
match timeout {
|
||||
Ok(Ok(())) => {}
|
||||
Ok(Err(e)) => return Err(format!("Module event loop error: {}", e)),
|
||||
match outcome {
|
||||
Ok(Ok(())) => Ok(()),
|
||||
Ok(Err(e)) => {
|
||||
tracing::warn!("Module eval error: {}", e);
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::warn!("Module evaluation timed out after {}ms: {}", budget_ms, url);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
match result.await {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => {
|
||||
tracing::warn!("Module eval error: {}", e);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -713,25 +721,35 @@ impl ObscuraJsRuntime {
|
||||
};
|
||||
|
||||
let result = self.runtime.mod_evaluate(module_id);
|
||||
tokio::pin!(result);
|
||||
|
||||
let timeout = tokio::time::timeout(
|
||||
budget,
|
||||
self.runtime.run_event_loop(deno_core::PollEventLoopOptions::default()),
|
||||
).await;
|
||||
// Drive the event loop, but return as soon as the module finishes
|
||||
// evaluating rather than waiting for the loop to go fully idle. A page
|
||||
// timer (Vite's HMR / React-Refresh client installs a setInterval) keeps
|
||||
// the loop busy forever; waiting for idle burned the whole budget on this
|
||||
// preamble module and starved the later module that mounts the app,
|
||||
// leaving #root empty (issue #374).
|
||||
let outcome = tokio::time::timeout(budget, async {
|
||||
let event_loop = self
|
||||
.runtime
|
||||
.run_event_loop(deno_core::PollEventLoopOptions::default());
|
||||
tokio::pin!(event_loop);
|
||||
tokio::select! {
|
||||
biased;
|
||||
r = &mut result => r,
|
||||
e = &mut event_loop => { e?; (&mut result).await }
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
match timeout {
|
||||
Ok(Ok(())) => {}
|
||||
Ok(Err(e)) => return Err(format!("Module event loop error: {}", e)),
|
||||
match outcome {
|
||||
Ok(Ok(())) => Ok(()),
|
||||
Ok(Err(e)) => {
|
||||
tracing::warn!("Inline module eval error: {}", e);
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::warn!("Inline module timed out after {}ms", budget_ms);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
match result.await {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => {
|
||||
tracing::warn!("Inline module eval error: {}", e);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user