diff --git a/packages/core/src/api/exporters/copyExtension.ts b/packages/core/src/api/exporters/copyExtension.ts index e3b29fa421..9aa2ac6779 100644 --- a/packages/core/src/api/exporters/copyExtension.ts +++ b/packages/core/src/api/exporters/copyExtension.ts @@ -5,25 +5,26 @@ import { NodeSelection, Plugin } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import type { BlockNoteEditor } from "../../editor/BlockNoteEditor"; import { BlockSchema, InlineContentSchema, StyleSchema } from "../../schema"; +import { initializeESMDependencies } from "../../util/esmDependencies"; import { createExternalHTMLExporter } from "./html/externalHTMLExporter"; import { createInternalHTMLSerializer } from "./html/internalHTMLSerializer"; import { cleanHTMLToMarkdown } from "./markdown/markdownExporter"; -function selectedFragmentToHTML< +async function selectedFragmentToHTML< BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema >( view: EditorView, editor: BlockNoteEditor -): { +): Promise<{ internalHTML: string; externalHTML: string; plainText: string; -} { +}> { const selectedFragment = view.state.selection.content().content; - const internalHTMLSerializer = createInternalHTMLSerializer( + const internalHTMLSerializer = await createInternalHTMLSerializer( view.state.schema, editor ); @@ -32,6 +33,7 @@ function selectedFragmentToHTML< {} ); + await initializeESMDependencies(); const externalHTMLExporter = createExternalHTMLExporter( view.state.schema, editor @@ -41,7 +43,7 @@ function selectedFragmentToHTML< {} ); - const plainText = cleanHTMLToMarkdown(externalHTML); + const plainText = await cleanHTMLToMarkdown(externalHTML); return { internalHTML, externalHTML, plainText }; } @@ -83,15 +85,16 @@ export const createCopyToClipboardExtension = < ); } - const { internalHTML, externalHTML, plainText } = - selectedFragmentToHTML(view, editor); - - // TODO: Writing to other MIME types not working in Safari for - // some reason. - event.clipboardData!.setData("blocknote/html", internalHTML); - event.clipboardData!.setData("text/html", externalHTML); - event.clipboardData!.setData("text/plain", plainText); + (async () => { + const { internalHTML, externalHTML, plainText } = + await selectedFragmentToHTML(view, editor); + // TODO: Writing to other MIME types not working in Safari for + // some reason. + event.clipboardData!.setData("blocknote/html", internalHTML); + event.clipboardData!.setData("text/html", externalHTML); + event.clipboardData!.setData("text/plain", plainText); + })(); // Prevent default PM handler to be called return true; }, @@ -125,15 +128,16 @@ export const createCopyToClipboardExtension = < event.preventDefault(); event.dataTransfer!.clearData(); - const { internalHTML, externalHTML, plainText } = - selectedFragmentToHTML(view, editor); - - // TODO: Writing to other MIME types not working in Safari for - // some reason. - event.dataTransfer!.setData("blocknote/html", internalHTML); - event.dataTransfer!.setData("text/html", externalHTML); - event.dataTransfer!.setData("text/plain", plainText); + (async () => { + const { internalHTML, externalHTML, plainText } = + await selectedFragmentToHTML(view, editor); + // TODO: Writing to other MIME types not working in Safari for + // some reason. + event.dataTransfer!.setData("blocknote/html", internalHTML); + event.dataTransfer!.setData("text/html", externalHTML); + event.dataTransfer!.setData("text/plain", plainText); + })(); // Prevent default PM handler to be called return true; }, diff --git a/packages/core/src/api/exporters/html/externalHTMLExporter.ts b/packages/core/src/api/exporters/html/externalHTMLExporter.ts index cbeb0a83d6..beb81487c7 100644 --- a/packages/core/src/api/exporters/html/externalHTMLExporter.ts +++ b/packages/core/src/api/exporters/html/externalHTMLExporter.ts @@ -1,11 +1,9 @@ import { DOMSerializer, Fragment, Node, Schema } from "prosemirror-model"; -import rehypeParse from "rehype-parse"; -import rehypeStringify from "rehype-stringify"; -import { unified } from "unified"; import { PartialBlock } from "../../../blocks/defaultBlocks"; import type { BlockNoteEditor } from "../../../editor/BlockNoteEditor"; import { BlockSchema, InlineContentSchema, StyleSchema } from "../../../schema"; +import { esmDependencies } from "../../../util/esmDependencies"; import { blockToNode } from "../../nodeConversions/nodeConversions"; import { serializeNodeInner, @@ -47,6 +45,8 @@ export interface ExternalHTMLExporter< ) => string; } +// Needs to be sync because it's used in drag handler event (SideMenuPlugin) +// Ideally, call `await initializeESMDependencies()` before calling this function export const createExternalHTMLExporter = < BSchema extends BlockSchema, I extends InlineContentSchema, @@ -55,6 +55,14 @@ export const createExternalHTMLExporter = < schema: Schema, editor: BlockNoteEditor ): ExternalHTMLExporter => { + const deps = esmDependencies; + + if (!deps) { + throw new Error( + "External HTML exporter requires ESM dependencies to be initialized" + ); + } + const serializer = DOMSerializer.fromSchema(schema) as DOMSerializer & { serializeNodeInner: ( node: Node, @@ -79,8 +87,9 @@ export const createExternalHTMLExporter = < // but additionally runs it through the `simplifyBlocks` rehype plugin to // convert the internal HTML to external. serializer.exportProseMirrorFragment = (fragment, options) => { - const externalHTML = unified() - .use(rehypeParse, { fragment: true }) + const externalHTML = deps.unified + .unified() + .use(deps.rehypeParse.default, { fragment: true }) .use(simplifyBlocks, { orderedListItemBlockTypes: new Set(["numberedListItem"]), unorderedListItemBlockTypes: new Set([ @@ -88,7 +97,7 @@ export const createExternalHTMLExporter = < "checkListItem", ]), }) - .use(rehypeStringify) + .use(deps.rehypeStringify.default) .processSync(serializeProseMirrorFragment(fragment, serializer, options)); return externalHTML.value as string; diff --git a/packages/core/src/api/exporters/html/htmlConversion.test.ts b/packages/core/src/api/exporters/html/htmlConversion.test.ts index afb8a24bd3..a08367f004 100644 --- a/packages/core/src/api/exporters/html/htmlConversion.test.ts +++ b/packages/core/src/api/exporters/html/htmlConversion.test.ts @@ -7,6 +7,7 @@ import { PartialBlock } from "../../../blocks/defaultBlocks"; import { BlockSchema } from "../../../schema/blocks/types"; import { InlineContentSchema } from "../../../schema/inlineContent/types"; import { StyleSchema } from "../../../schema/styles/types"; +import { initializeESMDependencies } from "../../../util/esmDependencies"; import { customBlocksTestCases } from "../../testUtil/cases/customBlocks"; import { customInlineContentTestCases } from "../../testUtil/cases/customInlineContent"; import { customStylesTestCases } from "../../testUtil/cases/customStyles"; @@ -44,6 +45,7 @@ async function convertToHTMLAndCompareSnapshots< expect(parsed).toStrictEqual(fullBlocks); + await initializeESMDependencies(); // Create the "external" HTML, which is a cleaned up HTML representation, but lossy const exporter = createExternalHTMLExporter(editor.pmSchema, editor); const externalHTML = exporter.exportBlocks(blocks, {}); @@ -175,7 +177,7 @@ describe("Test ProseMirror fragment edge case conversion", () => { editor.replaceBlocks(editor.document, blocks); }); - it("Selection within a block's children", () => { + it("Selection within a block's children", async () => { // Selection starts and ends within the first block's children. editor.dispatch( editor._tiptapEditor.state.tr.setSelection( @@ -186,6 +188,7 @@ describe("Test ProseMirror fragment edge case conversion", () => { const copiedFragment = editor._tiptapEditor.state.selection.content().content; + await initializeESMDependencies(); const exporter = createExternalHTMLExporter(editor.pmSchema, editor); const externalHTML = exporter.exportProseMirrorFragment( copiedFragment, @@ -197,7 +200,7 @@ describe("Test ProseMirror fragment edge case conversion", () => { ); }); - it("Selection leaves a block's children", () => { + it("Selection leaves a block's children", async () => { // Selection starts and ends within the first block's children and ends // outside, at a shallower nesting level in the second block. editor.dispatch( @@ -209,6 +212,7 @@ describe("Test ProseMirror fragment edge case conversion", () => { const copiedFragment = editor._tiptapEditor.state.selection.content().content; + await initializeESMDependencies(); const exporter = createExternalHTMLExporter(editor.pmSchema, editor); const externalHTML = exporter.exportProseMirrorFragment( copiedFragment, @@ -220,7 +224,7 @@ describe("Test ProseMirror fragment edge case conversion", () => { ); }); - it("Selection spans multiple blocks' children", () => { + it("Selection spans multiple blocks' children", async () => { // Selection starts and ends within the first block's children and ends // within the second block's children. editor.dispatch( @@ -231,6 +235,7 @@ describe("Test ProseMirror fragment edge case conversion", () => { const copiedFragment = editor._tiptapEditor.state.selection.content().content; + await initializeESMDependencies(); const exporter = createExternalHTMLExporter(editor.pmSchema, editor); const externalHTML = exporter.exportProseMirrorFragment( copiedFragment, diff --git a/packages/core/src/api/exporters/html/util/simplifyBlocksRehypePlugin.ts b/packages/core/src/api/exporters/html/util/simplifyBlocksRehypePlugin.ts index e42e2ad447..70d2869a12 100644 --- a/packages/core/src/api/exporters/html/util/simplifyBlocksRehypePlugin.ts +++ b/packages/core/src/api/exporters/html/util/simplifyBlocksRehypePlugin.ts @@ -1,5 +1,5 @@ import { Element as HASTElement, Parent as HASTParent } from "hast"; -import { fromDom } from "hast-util-from-dom"; +import { esmDependencies } from "../../../../util/esmDependencies"; type SimplifyBlocksOptions = { orderedListItemBlockTypes: Set; @@ -16,6 +16,14 @@ type SimplifyBlocksOptions = { * @param options Options for specifying which block types represent ordered and unordered list items. */ export function simplifyBlocks(options: SimplifyBlocksOptions) { + const deps = esmDependencies; + + if (!deps) { + throw new Error( + "simplifyBlocks requires ESM dependencies to be initialized" + ); + } + const listItemBlockTypes = new Set([ ...options.orderedListItemBlockTypes, ...options.unorderedListItemBlockTypes, @@ -110,13 +118,13 @@ export function simplifyBlocks(options: SimplifyBlocksOptions) { // type as this was already done earlier. if (!activeList) { // Creates a new list element to represent an active list. - activeList = fromDom( + activeList = deps.hastUtilFromDom.fromDom( document.createElement(listItemBlockType!) ) as HASTElement; } // Creates a new list item element to represent the block. - const listItemElement = fromDom( + const listItemElement = deps.hastUtilFromDom.fromDom( document.createElement("li") ) as HASTElement; diff --git a/packages/core/src/api/exporters/markdown/markdownExporter.ts b/packages/core/src/api/exporters/markdown/markdownExporter.ts index c9ec348c9e..655ac165a3 100644 --- a/packages/core/src/api/exporters/markdown/markdownExporter.ts +++ b/packages/core/src/api/exporters/markdown/markdownExporter.ts @@ -1,30 +1,42 @@ import { Schema } from "prosemirror-model"; -import rehypeParse from "rehype-parse"; -import rehypeRemark from "rehype-remark"; -import remarkGfm from "remark-gfm"; -import remarkStringify from "remark-stringify"; -import { unified } from "unified"; import { PartialBlock } from "../../../blocks/defaultBlocks"; import type { BlockNoteEditor } from "../../../editor/BlockNoteEditor"; import { BlockSchema, InlineContentSchema, StyleSchema } from "../../../schema"; +import { + esmDependencies, + initializeESMDependencies, +} from "../../../util/esmDependencies"; import { createExternalHTMLExporter } from "../html/externalHTMLExporter"; import { removeUnderlines } from "./removeUnderlinesRehypePlugin"; import { addSpacesToCheckboxes } from "./util/addSpacesToCheckboxesRehypePlugin"; +// Needs to be sync because it's used in drag handler event (SideMenuPlugin) +// Ideally, call `await initializeESMDependencies()` before calling this function export function cleanHTMLToMarkdown(cleanHTMLString: string) { - const markdownString = unified() - .use(rehypeParse, { fragment: true }) + const deps = esmDependencies; + + if (!deps) { + throw new Error( + "cleanHTMLToMarkdown requires ESM dependencies to be initialized" + ); + } + + const markdownString = deps.unified + .unified() + .use(deps.rehypeParse.default, { fragment: true }) .use(removeUnderlines) .use(addSpacesToCheckboxes) - .use(rehypeRemark) - .use(remarkGfm) - .use(remarkStringify, { handlers: { text: (node) => node.value } }) + .use(deps.rehypeRemark.default) + .use(deps.remarkGfm.default) + .use(deps.remarkStringify.default, { + handlers: { text: (node) => node.value }, + }) .processSync(cleanHTMLString); return markdownString.value as string; } -export function blocksToMarkdown< +export async function blocksToMarkdown< BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema @@ -33,7 +45,8 @@ export function blocksToMarkdown< schema: Schema, editor: BlockNoteEditor, options: { document?: Document } -): string { +): Promise { + await initializeESMDependencies(); const exporter = createExternalHTMLExporter(schema, editor); const externalHTML = exporter.exportBlocks(blocks, options); diff --git a/packages/core/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts b/packages/core/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts index bdfe2f6704..1c9f5df2ab 100644 --- a/packages/core/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts +++ b/packages/core/src/api/exporters/markdown/util/addSpacesToCheckboxesRehypePlugin.ts @@ -1,5 +1,5 @@ import { Element as HASTElement, Parent as HASTParent } from "hast"; -import { fromDom } from "hast-util-from-dom"; +import { esmDependencies } from "../../../../util/esmDependencies"; /** * Rehype plugin which adds a space after each checkbox input element. This is @@ -7,6 +7,14 @@ import { fromDom } from "hast-util-from-dom"; * itself, but these are needed for correct Markdown syntax. */ export function addSpacesToCheckboxes() { + const deps = esmDependencies; + + if (!deps) { + throw new Error( + "simplifyBlocks requires ESM dependencies to be initialized" + ); + } + const helper = (tree: HASTParent) => { if (tree.children && "length" in tree.children && tree.children.length) { for (let i = tree.children.length - 1; i >= 0; i--) { @@ -29,7 +37,9 @@ export function addSpacesToCheckboxes() { nextChild.children.splice( 0, 0, - fromDom(document.createTextNode(" ")) as HASTElement + deps.hastUtilFromDom.fromDom( + document.createTextNode(" ") + ) as HASTElement ); } else { helper(child as HASTParent); diff --git a/packages/core/src/api/parsers/html/util/nestedLists.test.ts b/packages/core/src/api/parsers/html/util/nestedLists.test.ts index 96b0e1e9d2..52d24ad88d 100644 --- a/packages/core/src/api/parsers/html/util/nestedLists.test.ts +++ b/packages/core/src/api/parsers/html/util/nestedLists.test.ts @@ -1,17 +1,17 @@ -import rehypeFormat from "rehype-format"; -import rehypeParse from "rehype-parse"; -import rehypeStringify from "rehype-stringify"; -import { unified } from "unified"; import { describe, expect, it } from "vitest"; +import { initializeESMDependencies } from "../../../../util/esmDependencies"; import { nestedListsToBlockNoteStructure } from "./nestedLists"; async function testHTML(html: string) { + const deps = await initializeESMDependencies(); + const htmlNode = nestedListsToBlockNoteStructure(html); - const pretty = await unified() - .use(rehypeParse, { fragment: true }) - .use(rehypeFormat) - .use(rehypeStringify) + const pretty = await deps.unified + .unified() + .use(deps.rehypeParse.default, { fragment: true }) + .use(deps.rehypeFormat.default) + .use(deps.rehypeStringify.default) .process(htmlNode.innerHTML); expect(pretty.value).toMatchSnapshot(); diff --git a/packages/core/src/api/parsers/markdown/parseMarkdown.ts b/packages/core/src/api/parsers/markdown/parseMarkdown.ts index c3418fc5e3..868aff0a0a 100644 --- a/packages/core/src/api/parsers/markdown/parseMarkdown.ts +++ b/packages/core/src/api/parsers/markdown/parseMarkdown.ts @@ -1,11 +1,8 @@ import { Schema } from "prosemirror-model"; -import rehypeStringify from "rehype-stringify"; -import remarkGfm from "remark-gfm"; -import remarkParse from "remark-parse"; -import remarkRehype, { defaultHandlers } from "remark-rehype"; -import { unified } from "unified"; + import { Block } from "../../../blocks/defaultBlocks"; import { BlockSchema, InlineContentSchema, StyleSchema } from "../../../schema"; +import { initializeESMDependencies } from "../../../util/esmDependencies"; import { HTMLToBlocks } from "../html/parseHTML"; // modified version of https://github.com/syntax-tree/mdast-util-to-hast/blob/main/lib/handlers/code.js @@ -47,7 +44,7 @@ function code(state: any, node: any) { return result; } -export function markdownToBlocks< +export async function markdownToBlocks< BSchema extends BlockSchema, I extends InlineContentSchema, S extends StyleSchema @@ -58,16 +55,18 @@ export function markdownToBlocks< styleSchema: S, pmSchema: Schema ): Promise[]> { - const htmlString = unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkRehype, { + const deps = await initializeESMDependencies(); + const htmlString = deps.unified + .unified() + .use(deps.remarkParse.default) + .use(deps.remarkGfm.default) + .use(deps.remarkRehype.default, { handlers: { - ...(defaultHandlers as any), + ...(deps.remarkRehype.defaultHandlers as any), code, }, }) - .use(rehypeStringify) + .use(deps.rehypeStringify.default) .processSync(markdown); return HTMLToBlocks( diff --git a/packages/core/src/editor/BlockNoteEditor.ts b/packages/core/src/editor/BlockNoteEditor.ts index 24cdaf8a55..b0780d920c 100644 --- a/packages/core/src/editor/BlockNoteEditor.ts +++ b/packages/core/src/editor/BlockNoteEditor.ts @@ -68,6 +68,7 @@ import { en } from "../i18n/locales"; import { Transaction } from "@tiptap/pm/state"; import { createInternalHTMLSerializer } from "../api/exporters/html/internalHTMLSerializer"; import "../style.css"; +import { initializeESMDependencies } from "../util/esmDependencies"; export type BlockNoteEditorOptions< BSchema extends BlockSchema, @@ -1016,6 +1017,7 @@ export class BlockNoteEditor< public async blocksToHTMLLossy( blocks: PartialBlock[] = this.document ): Promise { + await initializeESMDependencies(); const exporter = createExternalHTMLExporter(this.pmSchema, this); return exporter.exportBlocks(blocks, {}); } diff --git a/packages/core/src/extensions/SideMenu/SideMenuPlugin.ts b/packages/core/src/extensions/SideMenu/SideMenuPlugin.ts index 24c200af1a..da6b91eed3 100644 --- a/packages/core/src/extensions/SideMenu/SideMenuPlugin.ts +++ b/packages/core/src/extensions/SideMenu/SideMenuPlugin.ts @@ -12,6 +12,7 @@ import type { BlockNoteEditor } from "../../editor/BlockNoteEditor"; import { UiElementPosition } from "../../extensions-shared/UiElementPosition"; import { BlockSchema, InlineContentSchema, StyleSchema } from "../../schema"; import { EventEmitter } from "../../util/EventEmitter"; +import { initializeESMDependencies } from "../../util/esmDependencies"; import { MultipleNodeSelection } from "./MultipleNodeSelection"; let dragImageElement: Element | undefined; @@ -302,6 +303,7 @@ export class SideMenuView< "dragover", this.onDragOver as EventListener ); + initializeESMDependencies(); this.pmView.dom.addEventListener("dragstart", this.onDragStart); // Shows or updates menu position whenever the cursor moves, if the menu isn't frozen. diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index cc561c7d62..9f352e54ba 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,16 +1,16 @@ import * as locales from "./i18n/locales"; export * from "./api/exporters/html/externalHTMLExporter"; export * from "./api/exporters/html/internalHTMLSerializer"; -export * from "./api/testUtil"; export * from "./api/getCurrentBlockContentType"; -export * from "./blocks/defaultBlockHelpers"; +export * from "./api/testUtil"; export * from "./blocks/AudioBlockContent/AudioBlockContent"; export * from "./blocks/FileBlockContent/FileBlockContent"; -export * from "./blocks/ImageBlockContent/ImageBlockContent"; -export * from "./blocks/VideoBlockContent/VideoBlockContent"; export * from "./blocks/FileBlockContent/fileBlockHelpers"; export * from "./blocks/FileBlockContent/uploadToTmpFilesDotOrg_DEV_ONLY"; +export * from "./blocks/ImageBlockContent/ImageBlockContent"; export { parseImageElement } from "./blocks/ImageBlockContent/imageBlockHelpers"; +export * from "./blocks/VideoBlockContent/VideoBlockContent"; +export * from "./blocks/defaultBlockHelpers"; export * from "./blocks/defaultBlockTypeGuards"; export * from "./blocks/defaultBlocks"; export * from "./blocks/defaultProps"; @@ -23,15 +23,16 @@ export * from "./extensions/FilePanel/FilePanelPlugin"; export * from "./extensions/FormattingToolbar/FormattingToolbarPlugin"; export * from "./extensions/LinkToolbar/LinkToolbarPlugin"; export * from "./extensions/SideMenu/SideMenuPlugin"; -export * from "./extensions/SuggestionMenu/DefaultSuggestionItem"; export * from "./extensions/SuggestionMenu/DefaultGridSuggestionItem"; +export * from "./extensions/SuggestionMenu/DefaultSuggestionItem"; export * from "./extensions/SuggestionMenu/SuggestionPlugin"; -export * from "./extensions/SuggestionMenu/getDefaultSlashMenuItems"; export * from "./extensions/SuggestionMenu/getDefaultEmojiPickerItems"; +export * from "./extensions/SuggestionMenu/getDefaultSlashMenuItems"; export * from "./extensions/TableHandles/TableHandlesPlugin"; export * from "./i18n/dictionary"; export * from "./schema"; export * from "./util/browser"; +export * from "./util/esmDependencies"; export * from "./util/string"; export * from "./util/typescript"; export { UnreachableCaseError, assertEmpty } from "./util/typescript"; diff --git a/packages/core/src/util/esmDependencies.ts b/packages/core/src/util/esmDependencies.ts new file mode 100644 index 0000000000..ce51497f5a --- /dev/null +++ b/packages/core/src/util/esmDependencies.ts @@ -0,0 +1,51 @@ +// some dependencies only export as ESM modules. This makes them incompatible with Node CJS. +// To work around this, we load these dependencies as dynamic imports in a function that initializes them. + +// (to reproduce this issue, run ts-node on a file that users server-util) +export let esmDependencies: + | undefined + | { + rehypeParse: typeof import("rehype-parse"); + rehypeStringify: typeof import("rehype-stringify"); + unified: typeof import("unified"); + hastUtilFromDom: typeof import("hast-util-from-dom"); + rehypeRemark: typeof import("rehype-remark"); + remarkGfm: typeof import("remark-gfm"); + remarkStringify: typeof import("remark-stringify"); + remarkParse: typeof import("remark-parse"); + remarkRehype: typeof import("remark-rehype"); + rehypeFormat: typeof import("rehype-format"); + }; + +export async function initializeESMDependencies() { + if (esmDependencies) { + return esmDependencies; + } + const vals = await Promise.all([ + import("rehype-parse"), + import("rehype-stringify"), + import("unified"), + import("hast-util-from-dom"), + import("rehype-remark"), + import("remark-gfm"), + import("remark-stringify"), + import("remark-parse"), + import("remark-rehype"), + import("rehype-format"), + ]); + + esmDependencies = { + rehypeParse: vals[0], + rehypeStringify: vals[1], + unified: vals[2], + hastUtilFromDom: vals[3], + rehypeRemark: vals[4], + remarkGfm: vals[5], + remarkStringify: vals[6], + remarkParse: vals[7], + remarkRehype: vals[8], + rehypeFormat: vals[9], + }; + + return esmDependencies; +} diff --git a/packages/react/src/test/htmlConversion.test.tsx b/packages/react/src/test/htmlConversion.test.tsx index 79408bb2dd..918349a237 100644 --- a/packages/react/src/test/htmlConversion.test.tsx +++ b/packages/react/src/test/htmlConversion.test.tsx @@ -9,8 +9,10 @@ import { addIdsToBlocks, createExternalHTMLExporter, createInternalHTMLSerializer, + initializeESMDependencies, partialBlocksToBlocksForTesting, } from "@blocknote/core"; + import { flushSync } from "react-dom"; import { Root, createRoot } from "react-dom/client"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; @@ -54,6 +56,7 @@ async function convertToHTMLAndCompareSnapshots< expect(parsed).toStrictEqual(fullBlocks); // Create the "external" HTML, which is a cleaned up HTML representation, but lossy + await initializeESMDependencies(); const exporter = createExternalHTMLExporter(editor.pmSchema, editor); const externalHTML = exporter.exportBlocks(blocks, {}); const externalHTMLSnapshotPath = diff --git a/packages/server-util/src/context/ServerBlockNoteEditor.ts b/packages/server-util/src/context/ServerBlockNoteEditor.ts index 1308574520..eb3296214e 100644 --- a/packages/server-util/src/context/ServerBlockNoteEditor.ts +++ b/packages/server-util/src/context/ServerBlockNoteEditor.ts @@ -13,8 +13,10 @@ import { blocksToMarkdown, createExternalHTMLExporter, createInternalHTMLSerializer, + initializeESMDependencies, nodeToBlock, } from "@blocknote/core"; + import { BlockNoteViewRaw } from "@blocknote/react"; import { Node } from "@tiptap/pm/model"; import * as jsdom from "jsdom"; @@ -222,6 +224,7 @@ export class ServerBlockNoteEditor< blocks: PartialBlock[] ): Promise { return this._withJSDOM(async () => { + await initializeESMDependencies(); const exporter = createExternalHTMLExporter( this.editor.pmSchema, this.editor