主编辑区改造准备

This commit is contained in:
lix-2026
2026-04-21 06:26:35 +08:00
parent 1e686bfa3c
commit 5d1c94eb9e
49 changed files with 6730 additions and 2565 deletions
@@ -0,0 +1,101 @@
"use client";
const MANIFEST_URL = "/api/leptos-tiptap-runtime/manifest.json";
type RuntimeManifest = {
bridgeRuntimePath: string | null;
extensionModulePaths: string[];
generatedRootPath: string | null;
entryScriptPath: string | null;
wasmPath: string | null;
};
type BridgeSuccess<T> = {
ok: true;
value: T;
};
type BridgeFailure = {
ok: false;
error: {
kind: string;
message: string;
operation?: string;
};
};
type BridgeResult<T> = BridgeSuccess<T> | BridgeFailure;
type BridgeRuntimeModule = {
init_bridge_runtime: () => void;
create: (
request: unknown,
onReady: (payload: { generation: number }) => void,
onChange: () => void,
onSelectionChange: (selection: Record<string, unknown>) => void,
onError: (error: { kind: string; message: string; operation?: string }) => void,
) => void;
destroy: (id: string) => void;
command: (request: unknown) => BridgeResult<{ kind: "empty" }>;
document: (request: unknown) => BridgeResult<{ kind: "content"; content: { format: "json" | "html"; value: unknown } }>;
};
export type LoadedLeptosTiptapRuntime = {
manifest: RuntimeManifest;
bridge: BridgeRuntimeModule;
};
let runtimePromise: Promise<LoadedLeptosTiptapRuntime> | null = null;
function toRuntimeAssetUrl(relativePath: string): string {
return `/api/leptos-tiptap-runtime/${relativePath}`;
}
async function importRuntimeModule<T>(relativePath: string): Promise<T> {
return import(/* webpackIgnore: true */ toRuntimeAssetUrl(relativePath)) as Promise<T>;
}
function extractRegisterFunction(module: Record<string, unknown>): (() => void) | null {
for (const value of Object.values(module)) {
if (typeof value === "function") {
return value as () => void;
}
}
return null;
}
async function fetchRuntimeManifest(): Promise<RuntimeManifest> {
const response = await fetch(MANIFEST_URL, { cache: "no-store" });
if (!response.ok) {
throw new Error(`读取 leptos-tiptap runtime manifest 失败(${response.status}`);
}
const manifest = (await response.json()) as RuntimeManifest;
if (!manifest.bridgeRuntimePath) {
throw new Error("runtime manifest 缺少 bridgeRuntimePath");
}
return manifest;
}
async function loadRuntimeModules(): Promise<LoadedLeptosTiptapRuntime> {
const manifest = await fetchRuntimeManifest();
const bridge = await importRuntimeModule<BridgeRuntimeModule>(manifest.bridgeRuntimePath!);
bridge.init_bridge_runtime();
for (const modulePath of manifest.extensionModulePaths) {
const extensionModule = await importRuntimeModule<Record<string, unknown>>(modulePath);
const register = extractRegisterFunction(extensionModule);
register?.();
}
return { manifest, bridge };
}
export async function loadLeptosTiptapRuntime(): Promise<LoadedLeptosTiptapRuntime> {
if (!runtimePromise) {
runtimePromise = loadRuntimeModules().catch((error) => {
runtimePromise = null;
throw error;
});
}
return runtimePromise;
}