1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 23:00:04 -04:00

eframe web: Better panic handling (#2942)

* Refactor: remove extra store of events

* Remove unnecessary extra function

* Refactor: simplify event registering

* Store panic summary

* egui_demo_app: move web-part to own module

* index.html: await

* Properly unsubscribe from events on panic

* Better error handling

* Demo app html: hide the wasm canvas and show an error message on panic

* egui_demo_app: add panic button to test panic response on web

* fix typo

* Use a constructor to create WebHandle

* Refactor: less use of locks in the interfaces

* More consistent naming
This commit is contained in:
Emil Ernerfeldt
2023-04-21 08:33:01 +02:00
committed by GitHub
parent 7f2de426d2
commit ac50fa0d94
10 changed files with 703 additions and 650 deletions

View File

@@ -108,11 +108,10 @@ impl BackendPanel {
ui.ctx().set_debug_on_hover(debug_on_hover);
}
ui.separator();
#[cfg(target_arch = "wasm32")]
#[cfg(feature = "web_screen-reader")]
{
ui.separator();
let mut screen_reader = ui.ctx().options(|o| o.screen_reader);
ui.checkbox(&mut screen_reader, "🔈 Screen reader").on_hover_text("Experimental feature: checking this will turn on the screen reader on supported platforms");
ui.ctx().options_mut(|o| o.screen_reader = screen_reader);
@@ -125,6 +124,15 @@ impl BackendPanel {
frame.close();
}
}
if cfg!(debug_assertions) && cfg!(target_arch = "wasm32") {
ui.separator();
// For testing panic handling on web:
#[allow(clippy::manual_assert)]
if ui.button("panic!()").clicked() {
panic!("intentional panic!");
}
}
}
fn integration_ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {

View File

@@ -3,12 +3,9 @@
mod apps;
mod backend_panel;
pub(crate) mod frame_history;
mod frame_history;
mod wrap_app;
#[cfg(target_arch = "wasm32")]
use eframe::web::AppRunnerRef;
pub use wrap_app::WrapApp;
/// Time of day as seconds since midnight. Used for clock in demo app.
@@ -21,60 +18,7 @@ pub(crate) fn seconds_since_midnight() -> f64 {
// ----------------------------------------------------------------------------
#[cfg(target_arch = "wasm32")]
use eframe::wasm_bindgen::{self, prelude::*};
mod web;
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub struct WebHandle {
handle: AppRunnerRef,
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
impl WebHandle {
#[wasm_bindgen]
pub fn stop_web(&self) -> Result<(), wasm_bindgen::JsValue> {
let mut app = self.handle.lock();
app.destroy()
}
#[wasm_bindgen]
pub fn set_some_content_from_javascript(&mut self, _some_data: &str) {
let _app = self.handle.lock().app_mut::<WrapApp>();
// _app.data = some_data;
}
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn init_wasm_hooks() {
// Make sure panics are logged using `console.error`.
console_error_panic_hook::set_once();
// Redirect tracing to console.log and friends:
eframe::web::WebLogger::init(log::LevelFilter::Debug).ok();
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub async fn start_separate(canvas_id: &str) -> Result<WebHandle, wasm_bindgen::JsValue> {
let web_options = eframe::WebOptions::default();
eframe::start_web(
canvas_id,
web_options,
Box::new(|cc| Box::new(WrapApp::new(cc))),
)
.await
.map(|handle| WebHandle { handle })
}
/// This is the entry-point for all the web-assembly.
/// This is called once from the HTML.
/// It loads the app, installs some callbacks, then returns.
/// You can add more callbacks like this if you want to call in to your code.
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub async fn start(canvas_id: &str) -> Result<WebHandle, wasm_bindgen::JsValue> {
init_wasm_hooks();
start_separate(canvas_id).await
}
pub use web::*;

View File

@@ -0,0 +1,57 @@
use eframe::{
wasm_bindgen::{self, prelude::*},
web::AppRunnerRef,
};
use crate::WrapApp;
#[wasm_bindgen]
pub struct WebHandle {
runner: AppRunnerRef,
}
#[wasm_bindgen]
impl WebHandle {
/// This is the entry-point for all the web-assembly.
///
/// This is called once from the HTML.
/// It loads the app, installs some callbacks, then returns.
#[wasm_bindgen(constructor)]
pub async fn new(canvas_id: &str) -> Result<WebHandle, wasm_bindgen::JsValue> {
// Redirect tracing to console.log and friends:
eframe::web::WebLogger::init(log::LevelFilter::Debug).ok();
// Make sure panics are logged using `console.error`.
console_error_panic_hook::set_once();
let web_options = eframe::WebOptions::default();
let runner = eframe::start_web(
canvas_id,
web_options,
Box::new(|cc| Box::new(WrapApp::new(cc))),
)
.await?;
Ok(WebHandle { runner })
}
#[wasm_bindgen]
pub fn destroy(&self) {
self.runner.destroy();
}
#[wasm_bindgen]
pub fn has_panicked(&self) -> bool {
self.runner.panic_summary().is_some()
}
#[wasm_bindgen]
pub fn panic_message(&self) -> Option<String> {
self.runner.panic_summary().map(|s| s.message())
}
#[wasm_bindgen]
pub fn panic_callstack(&self) -> Option<String> {
self.runner.panic_summary().map(|s| s.callstack())
}
}