ueberdosis / tiptap

The headless rich text editor framework for web artisans.
https://tiptap.dev
MIT License
27.76k stars 2.31k forks source link

Extensions, Marks and Nodes are using a global instance by default #2694

Open bdbch opened 2 years ago

bdbch commented 2 years ago

What’s the bug you are facing?

The problem we are facing is described in this issue: #2589

Right now it's not clear that doing something like that:

new Editor({
  extensions: [CharacterCount],
});

will not instantiate a new instance but will reuse the global instance created by Extension.create via the extension developer.

While using the following:

new Editor({
  extensions: [CharacterCount.configure()],
});

is a valid way to create multiple instances, it's not really clearly described + creates unnecessary child extension instances for each time it's called.

How can we reproduce the bug on our side?

Create an empty project with two editors at the same time and then use the same extension in both editors without using .configure. This will cause both editors to use one shared instance of the extension which specially leads to problems when extension storages are involved as they are overwritten by the last created editor.

Can you provide a CodeSandbox?

https://codesandbox.io/s/angry-bassi-i3xj5b?file=/src/index.js

What did you expect to happen?

I believe extensions should always be instanciated on the spot when they are needed and not on a global scope. This way concerns (storages and states) are always separated from each other. That means, when ever I use an extension, mark or node in a new Editor - a new instance should always be created.

Anything to add? (optional)

No response

Did you update your dependencies?

Are you sponsoring us?

dodas commented 2 years ago

Yes, please!

The current Extension API design is very unintuitive/unconventional. I, too, would assume that e.g. Node.create() returns a "class"/factory and only when it's passed to extensions in useEditor(), an instance of that class is initialized, instead of a singleton instance being created at the module initialization time.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

dodas commented 2 years ago

Not stale.

github-actions[bot] commented 2 years ago

This issue is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 7 days

dodas commented 2 years ago

not stale

KentoMoriwaki commented 2 years ago

We have encountered problems resulting from this issue. This behavior is unpredictable and undocumented. I hope it will be fixed in version 2.1 as planned!

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 7 days

dodas commented 1 year ago

bump

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 7 days

dodas commented 1 year ago

bump

Southclaws commented 1 month ago

Is it simply not possible to have multiple editors on the same page? We're building a lot of comments feed, style experiences with various plugins that need to know exactly which editor to issue commands to. I also use the "editor" as a read-only render for content not in "editing" state, purely because of all the node views and styling, it's not easy to re-implement that twice for editing and read-only.

At the moment, due to this bug, uploading an image into a comment will insert the image into the first post rather than the one you're editing, very strange bug but it's game-breaking so would love to know if there's a workaround.

nperez0111 commented 1 month ago

@Southclaws Unfortunately, due to a long-standing bug in how Extensions are setup the storage is shared across editor instances even though they probably shouldn't be (as mentioned here).

The workaround to getting different editor instances to have different storage values would be for each editor instance to have it's own set of extensions which have been extended (forcing different storage values) like this:

const editor1 = useEditor({ extensions: [ ExtensionOne.extend(), ExtensionTwo.extend() })
const editor2 = useEditor({ extensions: [ ExtensionOne.extend(), ExtensionTwo.extend() })

This will force ExtensionOne's storage to not be shared globally but be unique to each editor instance.

Southclaws commented 1 month ago

Ah, thanks! I was using .configure() as mentioned elsewhere but that wasn't working, .extend() seems to fix the issue for now.