From d27b5e2bb6da3463365ec1445ecf0317987eb4dd Mon Sep 17 00:00:00 2001 From: Timon Schelling Date: Thu, 7 Aug 2025 12:44:34 +0000 Subject: [PATCH 1/5] Add a few useful npm scripts for native --- frontend/package.json | 6 ++++-- package.json | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 40d36d4c88..a5424935db 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,16 +11,18 @@ "profiling": "npm run setup && npm run wasm:build-profiling && concurrently -k -n \"VITE,RUST\" \"vite\" \"npm run wasm:watch-profiling\"", "production": "npm run setup && npm run wasm:build-production && concurrently -k -n \"VITE,RUST\" \"vite\" \"npm run wasm:watch-production\"", "---------- BUILDS ----------": "", + "build": "npm run wasm:build-production && vite build", "build-dev": "npm run wasm:build-dev && vite build", - "build-native": "npm run native:build-dev && vite build", + "build-native": "npm run native:build-production && vite build", + "build-native-dev": "npm run native:build-dev && vite build", "build-profiling": "npm run wasm:build-profiling && vite build", - "build": "npm run wasm:build-production && vite build", "---------- UTILITIES ----------": "", "lint": "eslint . && tsc --noEmit", "lint-fix": "eslint . --fix && tsc --noEmit", "---------- INTERNAL ----------": "", "setup": "node package-installer.js", "native:build-dev": "wasm-pack build ./wasm --dev --target=web --features native", + "native:build-production": "wasm-pack build ./wasm --release --target=web --features native", "wasm:build-dev": "wasm-pack build ./wasm --dev --target=web", "wasm:build-profiling": "wasm-pack build ./wasm --profiling --target=web", "wasm:build-production": "wasm-pack build ./wasm --release --target=web", diff --git a/package.json b/package.json index 9bdfdae2e2..7d48b37443 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,15 @@ "scripts": { "---------- DEV SERVER ----------": "", "start": "cd frontend && npm start", - "start-desktop": "cd frontend && npm run build-native && cargo run -p graphite-desktop", + "start-desktop": "cd frontend && npm run build-native-dev && cargo run -p graphite-desktop", "profiling": "cd frontend && npm run profiling", "production": "cd frontend && npm run production", "---------- BUILDS ----------": "", "build-dev": "cd frontend && npm run build-dev", "build-profiling": "cd frontend && npm run build-profiling", "build": "cd frontend && npm run build", + "build-native": "cd frontend && npm run build-native && cargo build -r -p graphite-desktop", + "build-native-dev": "cd frontend && npm run build-native-dev && cargo build -p graphite-desktop", "---------- UTILITIES ----------": "", "lint": "cd frontend && npm run lint", "lint-fix": "cd frontend && npm run lint-fix" From ac39bb847ccae1e60db169e7608c47cb5faf0e6e Mon Sep 17 00:00:00 2001 From: Timon Schelling Date: Thu, 7 Aug 2025 12:45:48 +0000 Subject: [PATCH 2/5] Allow compiler to prune editor from wasm wrapper in native builds --- frontend/wasm/src/editor_api.rs | 23 +++++++++++++++++++++-- frontend/wasm/src/lib.rs | 3 ++- frontend/wasm/src/native_communcation.rs | 6 +++--- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index 823ad0b157..ee23da719e 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -5,8 +5,7 @@ // on the dispatcher messaging system and more complex Rust data types. // use crate::helpers::translate_key; -use crate::{EDITOR, EDITOR_HANDLE, EDITOR_HAS_CRASHED, Error, MESSAGE_BUFFER}; -use editor::application::Editor; +use crate::{EDITOR_HANDLE, EDITOR_HAS_CRASHED, Error, MESSAGE_BUFFER}; use editor::consts::FILE_SAVE_SUFFIX; use editor::messages::input_mapper::utility_types::input_keyboard::ModifierKeys; use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta, ViewportBounds}; @@ -28,6 +27,11 @@ use wasm_bindgen::JsCast; use wasm_bindgen::prelude::*; use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, ImageData, window}; +#[cfg(not(feature = "native"))] +use crate::EDITOR; +#[cfg(not(feature = "native"))] +use editor::application::Editor; + static IMAGE_DATA_HASH: AtomicU64 = AtomicU64::new(0); fn calculate_hash(t: &T) -> u64 { @@ -140,6 +144,7 @@ impl EditorHandle { #[wasm_bindgen] impl EditorHandle { + #[cfg(not(feature = "native"))] #[wasm_bindgen(constructor)] pub fn new(frontend_message_handler_callback: js_sys::Function) -> Self { let editor = Editor::new(); @@ -153,6 +158,16 @@ impl EditorHandle { editor_handle } + #[cfg(feature = "native")] + #[wasm_bindgen(constructor)] + pub fn new(frontend_message_handler_callback: js_sys::Function) -> Self { + let editor_handle = EditorHandle { frontend_message_handler_callback }; + if EDITOR_HANDLE.with(|handle| handle.lock().ok().map(|mut guard| *guard = Some(editor_handle.clone()))).is_none() { + log::error!("Attempted to initialize the editor handle more than once"); + } + editor_handle + } + // Sends a message to the dispatcher in the Editor Backend #[cfg(not(feature = "native"))] fn dispatch>(&self, message: T) { @@ -242,6 +257,7 @@ impl EditorHandle { self.dispatch(PortfolioMessage::Init); // Poll node graph evaluation on `requestAnimationFrame` + #[cfg(not(feature = "native"))] { let f = std::rc::Rc::new(RefCell::new(None)); let g = f.clone(); @@ -929,6 +945,7 @@ fn set_timeout(f: &Closure, delay: Duration) { } /// Provides access to the `Editor` by calling the given closure with it as an argument. +#[cfg(not(feature = "native"))] fn editor(callback: impl FnOnce(&mut editor::application::Editor) -> T) -> T { EDITOR.with(|editor| { let mut guard = editor.try_lock(); @@ -942,6 +959,7 @@ fn editor(callback: impl FnOnce(&mut editor::application::Editor) -> } /// Provides access to the `Editor` and its `EditorHandle` by calling the given closure with them as arguments. +#[cfg(not(feature = "native"))] pub(crate) fn editor_and_handle(callback: impl FnOnce(&mut Editor, &mut EditorHandle)) { handle(|editor_handle| { editor(|editor| { @@ -964,6 +982,7 @@ pub(crate) fn handle(callback: impl FnOnce(&mut EditorHandle)) { }); } +#[cfg(not(feature = "native"))] async fn poll_node_graph_evaluation() { // Process no further messages after a crash to avoid spamming the console if EDITOR_HAS_CRASHED.load(Ordering::SeqCst) { diff --git a/frontend/wasm/src/lib.rs b/frontend/wasm/src/lib.rs index 8ed0d9abe5..d3141288b3 100644 --- a/frontend/wasm/src/lib.rs +++ b/frontend/wasm/src/lib.rs @@ -20,6 +20,7 @@ pub static NODE_GRAPH_ERROR_DISPLAYED: AtomicBool = AtomicBool::new(false); pub static LOGGER: WasmLog = WasmLog; thread_local! { + #[cfg(not(feature = "native"))] pub static EDITOR: Mutex> = const { Mutex::new(None) }; pub static MESSAGE_BUFFER: std::cell::RefCell> = const { std::cell::RefCell::new(Vec::new()) }; pub static EDITOR_HANDLE: Mutex> = const { Mutex::new(None) }; @@ -50,7 +51,7 @@ pub fn panic_hook(info: &panic::PanicHookInfo) { if !NODE_GRAPH_ERROR_DISPLAYED.load(Ordering::SeqCst) { NODE_GRAPH_ERROR_DISPLAYED.store(true, Ordering::SeqCst); - editor_api::editor_and_handle(|_, handle| { + editor_api::handle(|handle| { let error = r#" diff --git a/frontend/wasm/src/native_communcation.rs b/frontend/wasm/src/native_communcation.rs index bdf90b9524..3b84337145 100644 --- a/frontend/wasm/src/native_communcation.rs +++ b/frontend/wasm/src/native_communcation.rs @@ -1,4 +1,4 @@ -use editor::{application::Editor, messages::prelude::FrontendMessage}; +use editor::messages::prelude::FrontendMessage; use js_sys::{ArrayBuffer, Uint8Array}; use wasm_bindgen::prelude::*; @@ -9,12 +9,12 @@ pub fn receive_native_message(buffer: ArrayBuffer) { let buffer = Uint8Array::new(buffer.as_ref()).to_vec(); match ron::from_str::>(str::from_utf8(buffer.as_slice()).unwrap()) { Ok(messages) => { - let callback = move |_: &mut Editor, handle: &mut EditorHandle| { + let callback = move |handle: &mut EditorHandle| { for message in messages { handle.send_frontend_message_to_js_rust_proxy(message); } }; - editor_api::editor_and_handle(callback); + editor_api::handle(callback); } Err(e) => log::error!("Failed to deserialize frontend messages: {e:?}"), } From bfbf85ef2fca8d21aa3cbf8528a49582b0212a0c Mon Sep 17 00:00:00 2001 From: Timon Schelling Date: Thu, 7 Aug 2025 12:56:53 +0000 Subject: [PATCH 3/5] Fix warnings --- frontend/wasm/src/editor_api.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index ee23da719e..c0c56857e2 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -5,7 +5,7 @@ // on the dispatcher messaging system and more complex Rust data types. // use crate::helpers::translate_key; -use crate::{EDITOR_HANDLE, EDITOR_HAS_CRASHED, Error, MESSAGE_BUFFER}; +use crate::{EDITOR_HANDLE, EDITOR_HAS_CRASHED, Error}; use editor::consts::FILE_SAVE_SUFFIX; use editor::messages::input_mapper::utility_types::input_keyboard::ModifierKeys; use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta, ViewportBounds}; @@ -28,7 +28,7 @@ use wasm_bindgen::prelude::*; use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, ImageData, window}; #[cfg(not(feature = "native"))] -use crate::EDITOR; +use crate::{EDITOR, MESSAGE_BUFFER}; #[cfg(not(feature = "native"))] use editor::application::Editor; @@ -928,6 +928,7 @@ pub fn evaluate_math_expression(expression: &str) -> Option { } /// Helper function for calling JS's `requestAnimationFrame` with the given closure +#[cfg(not(feature = "native"))] fn request_animation_frame(f: &Closure) { web_sys::window() .expect("No global `window` exists") From 5d4a62d12f7fcdf9f22776566ad9a7eab2b6ce0b Mon Sep 17 00:00:00 2001 From: Timon Schelling Date: Thu, 7 Aug 2025 15:49:38 +0000 Subject: [PATCH 4/5] Review cleanup --- frontend/wasm/src/editor_api.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index c0c56857e2..2b81d98b95 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -5,7 +5,7 @@ // on the dispatcher messaging system and more complex Rust data types. // use crate::helpers::translate_key; -use crate::{EDITOR_HANDLE, EDITOR_HAS_CRASHED, Error}; +use crate::{EDITOR_HANDLE, EDITOR_HAS_CRASHED, Error, MESSAGE_BUFFER}; use editor::consts::FILE_SAVE_SUFFIX; use editor::messages::input_mapper::utility_types::input_keyboard::ModifierKeys; use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta, ViewportBounds}; @@ -28,7 +28,7 @@ use wasm_bindgen::prelude::*; use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, ImageData, window}; #[cfg(not(feature = "native"))] -use crate::{EDITOR, MESSAGE_BUFFER}; +use crate::EDITOR; #[cfg(not(feature = "native"))] use editor::application::Editor; @@ -257,12 +257,12 @@ impl EditorHandle { self.dispatch(PortfolioMessage::Init); // Poll node graph evaluation on `requestAnimationFrame` - #[cfg(not(feature = "native"))] { let f = std::rc::Rc::new(RefCell::new(None)); let g = f.clone(); *g.borrow_mut() = Some(Closure::new(move |_timestamp| { + #[cfg(not(feature = "native"))] wasm_bindgen_futures::spawn_local(poll_node_graph_evaluation()); if !EDITOR_HAS_CRASHED.load(Ordering::SeqCst) { @@ -928,7 +928,6 @@ pub fn evaluate_math_expression(expression: &str) -> Option { } /// Helper function for calling JS's `requestAnimationFrame` with the given closure -#[cfg(not(feature = "native"))] fn request_animation_frame(f: &Closure) { web_sys::window() .expect("No global `window` exists") From 74bf4c4e0a693de0589e757c960f5eef4b06b929 Mon Sep 17 00:00:00 2001 From: Timon Schelling Date: Thu, 7 Aug 2025 16:08:18 +0000 Subject: [PATCH 5/5] Fix npm desktop build script names --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7d48b37443..8d605249a3 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "build-dev": "cd frontend && npm run build-dev", "build-profiling": "cd frontend && npm run build-profiling", "build": "cd frontend && npm run build", - "build-native": "cd frontend && npm run build-native && cargo build -r -p graphite-desktop", - "build-native-dev": "cd frontend && npm run build-native-dev && cargo build -p graphite-desktop", + "build-desktop": "cd frontend && npm run build-native && cargo build -r -p graphite-desktop", + "build-desktop-dev": "cd frontend && npm run build-native-dev && cargo build -p graphite-desktop", "---------- UTILITIES ----------": "", "lint": "cd frontend && npm run lint", "lint-fix": "cd frontend && npm run lint-fix"