fix(tiptap): expose EditorOptions as runtime class for wasm-bindgen

EditorOptions was a TS interface (erased at runtime), but the Rust
wasm-bindgen extern uses #[wasm_bindgen(constructor)] which generates
'new EditorOptions()' — requiring a global constructor.

Vite 5/Rollup accidentally leaked the name into IIFE global scope,
masking this. Vite 8/Rolldown strictly erases interfaces, exposing it
as 'EditorOptions is not defined'.

Fix: make EditorOptions a class (retains runtime constructor) and mount
it on window, since the IIFE bundle name is taken by TiptapEditor.
This commit is contained in:
xfy 2026-06-24 10:27:07 +08:00
parent 368a651fa6
commit fb31ecb5ae

View File

@ -9,7 +9,16 @@ import { UploadCoordinator, UPLOAD_COORDINATOR_STORAGE_KEY, type UploadEvent } f
import { UploadImage } from './upload-image'
import './style.css'
export interface EditorOptions {
/**
* class interface使
* Rust wasm-bindgen `#[wasm_bindgen(constructor)]` `new EditorOptions()`
* 访interface TS
* Rust setterset_placeholder/set_on_update/...
*
* export IIFE named export default globalThis
* wasm-bindgen glue `EditorOptions`
*/
class EditorOptions {
content?: string
placeholder?: string
onUpdate?: (markdown: string) => void
@ -24,17 +33,21 @@ export interface EditorOptions {
onUploadEvent?: (event: UploadEvent) => void
}
// wasm-bindgen 生成的 glue 用裸标识符 `new EditorOptions()` 从全局解析,
// IIFE 的 name 只能挂一个全局TiptapEditor这里手动把 EditorOptions 也挂到 window 上。
;(window as unknown as Record<string, unknown>).EditorOptions = EditorOptions
class TiptapEditorInstance {
private editor: Editor | null = null
private container: HTMLElement
private options: EditorOptions
// 源码模式相关状态
private isSourceMode = false
private sourceTextarea: HTMLTextAreaElement | null = null
private toggleButton: HTMLButtonElement | null = null
private coordinator: UploadCoordinator | null = null
constructor(container: HTMLElement, options: EditorOptions = {}) {
constructor(container: HTMLElement, options: EditorOptions = new EditorOptions()) {
this.container = container
this.options = options
this.init()
@ -257,7 +270,7 @@ class TiptapEditorInstance {
const TiptapEditor = {
_instances: new Map<string, TiptapEditorInstance>(),
create(containerId: string, options: EditorOptions = {}): TiptapEditorInstance | null {
create(containerId: string, options: EditorOptions = new EditorOptions()): TiptapEditorInstance | null {
const container = document.getElementById(containerId)
if (!container) {
console.error(`[TiptapEditor] Container not found: #${containerId}`)