Skip to content

feat: compile error overlay#78

Open
shruti2522 wants to merge 5 commits into
metacall:masterfrom
shruti2522:feat/overlay
Open

feat: compile error overlay#78
shruti2522 wants to merge 5 commits into
metacall:masterfrom
shruti2522:feat/overlay

Conversation

@shruti2522

@shruti2522 shruti2522 commented Feb 24, 2026

Copy link
Copy Markdown
Contributor

Compile error overlay implementation in browser (like Next.js/Vite)

changes made:

  • resolved the segmentation fault where the sever crashed after encountering a syntax error, to make it possible to show the overlay
  • ensured overlay doesnt disappear on page reload
  • captured syntax error that existed before starting the server, not only the runtime errors
  • stripped the ANSI color codes for a cleaner display of the error messages
  • used Vec in error state to capture all error messages like next js

browser overlay:

Screenshot 2026-02-25 153750 Screenshot 2026-02-25 153758

@hulxv hulxv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fahdfady Need your review

Comment thread crates/metassr-bundler/src/bundle.js Outdated
Comment thread crates/metassr-server/src/scripts/live-reload.js Outdated
Comment thread crates/metassr-server/src/live_reload.rs Outdated
Comment thread tests/web-app/src/pages/home.tsx Outdated
@hulxv

hulxv commented Feb 25, 2026

Copy link
Copy Markdown
Collaborator

Resolve conflicts before making it ready for review

@shruti2522 shruti2522 force-pushed the feat/overlay branch 3 times, most recently from 2612e8d to a949147 Compare February 25, 2026 11:02
@shruti2522 shruti2522 marked this pull request as ready for review February 25, 2026 11:25
@shruti2522

Copy link
Copy Markdown
Contributor Author

ready for review @hulxv

@fahdfady fahdfady requested review from fahdfady and hulxv February 25, 2026 11:48
@shruti2522

Copy link
Copy Markdown
Contributor Author

Hi @fahdfady @hulxv, I am trying to fix the CI, it seems there is some issue with the tests, can I make changes to the tests in the CI to fix it, maybe open a separate PR for this

@fahdfady

fahdfady commented Mar 1, 2026

Copy link
Copy Markdown
Collaborator

Hi @fahdfady @hulxv, I am trying to fix the CI, it seems there is some issue with the tests, can I make changes to the tests in the CI to fix it, maybe open a separate PR for this

Hi @shruti2522 sorry for the late reply. we're working on it via #68 and we're investigating some problems in MetaCall's Windows and MacOS so don't worry.

Comment thread crates/metassr-bundler/src/bundle.js Outdated
@fahdfady fahdfady requested a review from Copilot March 2, 2026 20:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a browser compile-error overlay for dev mode by capturing build failures, broadcasting them over live-reload WebSocket, and persisting the last error across reloads.

Changes:

  • Added BuildError rebuild message + last_errors caching to forward build failures to the browser.
  • Implemented an in-browser overlay in the live-reload script to render build errors.
  • Added an initial build pass + ANSI-stripping to surface pre-existing compile errors more cleanly.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
metassr-cli/src/cli/dev.rs Performs an initial build to capture errors early and logs errors with ANSI cleanup
metassr-cli/Cargo.toml Adds dependencies needed for initial error capture/cleanup (metassr-bundler, regex)
crates/metassr-server/src/scripts/live-reload.js Renders compile-error overlay and reacts to new build_error WS messages
crates/metassr-server/src/rebuilder.rs Introduces BuildError events and caches last errors for overlay persistence
crates/metassr-server/src/live_reload.rs Sends cached errors immediately on WS connect and includes errors in WS payload
crates/metassr-server/src/lib.rs Wires last_errors into the live reload server construction
crates/metassr-server/Cargo.toml Adds regex dependency used for ANSI stripping
crates/metassr-bundler/src/lib.rs Captures bundler errors for consumption by dev server initial build path
crates/metassr-bundler/src/bundle.js Normalizes bundler errors into resolved values so Rust can capture messages
TODO.md Marks the compile error overlay task as complete
Cargo.toml Adds workspace-level regex dependency

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/metassr-server/src/rebuilder.rs Outdated
out_dir: PathBuf,
building_type: BuildingType,
is_rebuilding: Arc<AtomicBool>,
pub last_errors: Arc<std::sync::Mutex<Option<Vec<String>>>>,

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making last_errors a public field exposes internal synchronization details (a Mutex<Option<Vec<String>>>) to consumers and makes it harder to evolve this type safely. Prefer keeping the field private and adding a small API (e.g., last_errors() returning an Arc<Mutex<...>>, or better: get_last_errors()/set_last_errors()/clear_last_errors() methods) so other modules don’t directly lock/mutate internals.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shruti2522 what do you think? any arguments to make for using pub here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was the quickest way to expose the field to LiveReloadServer and dev.rs at the time, replaced it with proper accessor methods as suggested

Comment thread metassr-cli/src/cli/dev.rs Outdated
let rebuilder = Arc::clone(&rebuilder);

async move {
let ansi_regex = regex::Regex::new(r"\\u\{1b\}\[[0-9;]*m").unwrap();

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ANSI-stripping regex is compiled multiple times (and the pattern only targets the literal text \\u{1b} form, not the common raw ESC byte \\x1b). Consider centralizing ANSI stripping into a single helper (compile once) and using a more robust approach (e.g., a crate like strip-ansi-escapes, or a regex that handles both ESC and escaped forms) so logs/overlay consistently display clean messages.

Copilot uses AI. Check for mistakes.
Comment thread metassr-cli/src/cli/dev.rs Outdated
format!("Client build failed: {}", e)
};
// Clean up the error message for the terminal
let ansi_regex = Regex::new(r"\\u\{1b\}\[[0-9;]*m").unwrap();

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ANSI-stripping regex is compiled multiple times (and the pattern only targets the literal text \\u{1b} form, not the common raw ESC byte \\x1b). Consider centralizing ANSI stripping into a single helper (compile once) and using a more robust approach (e.g., a crate like strip-ansi-escapes, or a regex that handles both ESC and escaped forms) so logs/overlay consistently display clean messages.

Copilot uses AI. Check for mistakes.
Comment thread metassr-cli/src/cli/dev.rs Outdated
let stype = self.rebuilder.building_type();
if let Err(e) = ServerSideBuilder::new("", &out_dir, stype)?.build() {
let err_msg = format!("Server build failed: {}", e);
let ansi_regex = Regex::new(r"\\u\{1b\}\[[0-9;]*m").unwrap();

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ANSI-stripping regex is compiled multiple times (and the pattern only targets the literal text \\u{1b} form, not the common raw ESC byte \\x1b). Consider centralizing ANSI stripping into a single helper (compile once) and using a more robust approach (e.g., a crate like strip-ansi-escapes, or a regex that handles both ESC and escaped forms) so logs/overlay consistently display clean messages.

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +39
// remove existing overlay on backdrop click
overlay.addEventListener('click', (e) => {
if (e.target === overlay) dismissErrorOverlay();
});

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hint says the overlay “can only be dismissed by fixing the error”, but the UI currently allows dismissing via backdrop click and the close button. Either remove/disable the dismiss behaviors to match the message, or update the hint text to reflect that users can manually dismiss the overlay.

Suggested change
// remove existing overlay on backdrop click
overlay.addEventListener('click', (e) => {
if (e.target === overlay) dismissErrorOverlay();
});

Copilot uses AI. Check for mistakes.
});

const hint = document.createElement('p');
hint.textContent = 'This error occurred during the build process and can only be dismissed by fixing the error.';

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hint says the overlay “can only be dismissed by fixing the error”, but the UI currently allows dismissing via backdrop click and the close button. Either remove/disable the dismiss behaviors to match the message, or update the hint text to reflect that users can manually dismiss the overlay.

Suggested change
hint.textContent = 'This error occurred during the build process and can only be dismissed by fixing the error.';
hint.textContent = 'This error occurred during the build process. Fix the error to make this overlay disappear automatically, or close it manually to continue.';

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +74
// Add a tiny delay to ensure the browser has attached the onmessage handler
tokio::time::sleep(std::time::Duration::from_millis(100)).await;

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introducing a fixed 100ms delay adds latency to showing the overlay on reload and is generally brittle. Since the client assigns onmessage synchronously right after creating the WebSocket, you can likely remove this sleep; if ordering is still a concern, a more robust pattern is an explicit client “ready” message before the server sends cached errors.

Suggested change
// Add a tiny delay to ensure the browser has attached the onmessage handler
tokio::time::sleep(std::time::Duration::from_millis(100)).await;

Copilot uses AI. Check for mistakes.
Comment thread crates/metassr-bundler/src/lib.rs Outdated
Comment on lines +126 to +128
let msg = res_str.replace("String(\"", "").replace("\")", "");
let msg = msg.replace("\\n", "\n");
*BUNDLING_ERROR.lock().unwrap() = Some(msg);

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bundling error detection/parsing currently depends on format!(\"{:?}\", result) and string surgery (e.g., stripping String(\"...\")), which is fragile and couples behavior to debug formatting. Prefer extracting the returned JS value as a real string/typed value (or returning Result from the bundling call) and propagating the error via the function return rather than a global BUNDLING_ERROR side channel.

Suggested change
let msg = res_str.replace("String(\"", "").replace("\")", "");
let msg = msg.replace("\\n", "\n");
*BUNDLING_ERROR.lock().unwrap() = Some(msg);
*BUNDLING_ERROR.lock().unwrap() = Some(res_str);

Copilot uses AI. Check for mistakes.
Comment on lines +182 to +185
let mut err_guard = BUNDLING_ERROR.lock().unwrap();
if let Some(err_msg) = err_guard.take() {
return Err(anyhow::anyhow!("{}", err_msg));
}

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bundling error detection/parsing currently depends on format!(\"{:?}\", result) and string surgery (e.g., stripping String(\"...\")), which is fragile and couples behavior to debug formatting. Prefer extracting the returned JS value as a real string/typed value (or returning Result from the bundling call) and propagating the error via the function return rather than a global BUNDLING_ERROR side channel.

Copilot uses AI. Check for mistakes.
Comment on lines +114 to +116
// strip ANSI escape codes from terminal output including Rust escaped format like \u{1b}[31m
const cleanMessage = (msg || '').replace(/(\\u(?:\{1b}|001b)|[\u001b\u009b])[[\]()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
pre.textContent = cleanMessage.replace('Client-side build failed: Bundling failed: "ERROR: Compilation errors:\n', '').replace('"\nFix the error and save the file — this overlay will disappear automatically.', '');

Copilot AI Mar 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The overlay output strips very specific hard-coded prefixes/suffixes from the error string. This is brittle (small formatting changes will break it) and risks removing legitimate content that happens to match those substrings. Consider sending structured fields over WS (e.g., { stage: 'client', message: '...' }) or just render cleanMessage as-is and format via UI components rather than string slicing.

Copilot uses AI. Check for mistakes.
@shruti2522

Copy link
Copy Markdown
Contributor Author

Hi @fahdfady, any specific changes you would like me to make, I have resolved the previous reviews

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants