From a6d30ed5d90ad9d325ff905f8410d6f7687854de Mon Sep 17 00:00:00 2001 From: xfy Date: Tue, 23 Jun 2026 13:32:34 +0800 Subject: [PATCH] refactor(write): address code review feedback - remove duplicate `use dioxus::prelude::*` (keep #[allow] inline with comment) - update write_editor doc comment: callback-driven init, EditorHandle::drop cleanup (no more polling/globals) - restore empty-url check in make_upload_closure (match original JS `success && url`): empty url on success now rejects with clear message instead of inserting broken image - update AGENTS.md tiptap section: write.rs uses tiptap_bridge, no eval/polling --- AGENTS.md | 2 +- src/pages/admin/write.rs | 10 +++++----- src/tiptap_bridge.rs | 9 +++++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 0091512..c4d2019 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -122,7 +122,7 @@ Rich-text editor in `libs/tiptap-editor/`, built as an IIFE library exposing `wi - Output: `public/tiptap/` - `make build` runs `npm install && npx vite build` inside `libs/tiptap-editor` -- `src/pages/admin/write.rs` initializes via `js_sys::eval`, polls `window.__tiptap_ready` +- `src/pages/admin/write.rs` initializes via `src/tiptap_bridge.rs` (wasm-bindgen bindings): injects `Closure` callbacks (`onUpdate`/`onReady`/`onUploadEvent`/`onImageUpload`) into `TiptapEditor.create`, holds the instance + closures in `EditorHandle` (Drop calls `destroy()`). No `js_sys::eval`, no `window` globals, no polling. Do not edit `public/tiptap/` — they are build artifacts. diff --git a/src/pages/admin/write.rs b/src/pages/admin/write.rs index be78dd1..2837fb4 100644 --- a/src/pages/admin/write.rs +++ b/src/pages/admin/write.rs @@ -4,6 +4,9 @@ //! 编辑器通过 [`crate::tiptap_bridge`] 的 wasm-bindgen 绑定在 WASM 前端初始化, //! 并与 `window.TiptapEditor` 实例交互,实现 Markdown 内容回填、图片上传与组件卸载时的清理。 +// prelude 在 WASM 构建里直接使用(use_signal/Signal/Element 等); +// server 构建里 #[component] 宏会重新导出这些符号导致 native 报 unused,故 allow。 +#[allow(unused_imports)] use dioxus::prelude::*; // 仅在 WASM 前端使用的类型转换与文章 API。 @@ -21,9 +24,6 @@ use crate::router::Route; #[cfg(target_arch = "wasm32")] use wasm_bindgen::closure::Closure; -#[allow(unused_imports)] -use dioxus::prelude::*; - /// 新建文章页面组件。 /// /// 内部委托给 `write_editor`,以 `None` 表示新建模式。 @@ -46,10 +46,10 @@ pub fn WriteEdit(id: i32) -> Element { /// /// 负责: /// - 编辑模式下通过 server function 拉取文章数据; -/// - 在 WASM 前端初始化 Tiptap 富文本编辑器并轮询就绪状态; +/// - 在 WASM 前端通过 tiptap_bridge 的 closure 回调初始化 Tiptap 富文本编辑器; /// - 编辑模式下将 Markdown 内容回填到编辑器; /// - 提交时读取编辑器 Markdown、校验并调用 create_post / update_post; -/// - 组件卸载时销毁 Tiptap 实例并清理全局状态。 +/// - 组件卸载时销毁 Tiptap 实例(EditorHandle::drop 自动 destroy + 释放 closure)。 #[allow(unused_mut, unused_variables)] fn write_editor(post_id: Option) -> Element { let is_edit = post_id.is_some(); diff --git a/src/tiptap_bridge.rs b/src/tiptap_bridge.rs index 5b3b674..ea8c07c 100644 --- a/src/tiptap_bridge.rs +++ b/src/tiptap_bridge.rs @@ -281,8 +281,13 @@ pub mod wasm { serde_json::from_str(&text).unwrap_or(serde_json::Value::Null); if data["success"].as_bool() == Some(true) { - let url = data["url"].as_str().unwrap_or("").to_string(); - Ok(js_sys::JsString::from(url).into()) + let url = data["url"].as_str().unwrap_or(""); + if !url.is_empty() { + Ok(js_sys::JsString::from(url).into()) + } else { + // success=true 但 url 为空:服务端契约异常,按失败处理 + Err(js_sys::Error::new("上传成功但未返回图片地址").into()) + } } else { // 失败:优先用服务端中文 error,兜底用状态码 let msg = data["error"]