Prosemirror: EditorState::reconfigure with a different schema instance can leave the document in a broken state

Created on 17 Jan 2018  路  2Comments  路  Source: ProseMirror/prosemirror

Issue details

I'm currently working on supporting switching between different "appearances" around a PM editor in React. i.e. going from a short-form editor to a full page width editor.

It's gone pretty well, and I've taken a bit of inspiration from the various React-PM approaches.

Since we're leaning into react, we're trying to make everything as stateless and prop-dependent as we can - the way we're currently doing this is:

  1. Generate the schema from an list of PluginAbstractions (they declare the Plugins & what nodes/marks they require), e.g. for image it provides both the image plugin & the nodes for image
  2. Create the editor state from the schema and the list of Plugins

This doesn't work as expected when doing:

const state = new EditorState({ schema: oldSchema, doc, plugins });
const newState = state.reconfigure({ schema: newSchema, plugins });

newState.doc will end up still holding a reference to the original schema

Steps to reproduce

  1. open https://fascinated-heart.glitch.me/
  2. try and edit any of the lines and see that they'll blank out

(code is available here: https://glitch.com/edit/#!/fascinated-heart )

ProseMirror version

Latest / ^1.0.0

Affected platforms

All

Screenshots / Screencast (Optional)

Gif of this here

Suspected Why?

Because the nodes between the Schemas are not the same object reference, when transforms/transactions are applied it doesn't know how to handle the type of the document.

Most helpful comment

馃憤 at the least, it's now been flagged so future folks will understand what's going on if they come across a similar issue around this.

The workaround is fairly simple - it's not as performant as it could be, though it's not a big issue given how rarely such a change should occur:

const editorState = prevState.editorState.reconfigure({ schema, plugins });
editorState.doc = schema.nodeFromJSON(editorState.doc.toJSON());

I'd be happy to raise a PR to extend the current docs for reconfigure to include a disclaimer around this, i.e.

Create a new state based on this one, but with an adjusted set of active plugins. State fields that exist in both sets of plugins are kept unchanged. Those that no longer exist are dropped, and those that are new are initialized using their init method, passing in the new configuration object. Schema nodes and marks should persist across schema changes as a semantically identical but newly created schema may cause issues with document editing.

All 2 comments

Yeah, schemas have identity鈥攆or performance reasons, the NodeType and MarkType objects are compared by pointer rather than by content, so trying to use a document with an identical but newly created schema will break. I agree that this can be inconvenient, but the complexity required to remove the restriction seems more problematic than the restriction itself, so I don't think this is going to change.

馃憤 at the least, it's now been flagged so future folks will understand what's going on if they come across a similar issue around this.

The workaround is fairly simple - it's not as performant as it could be, though it's not a big issue given how rarely such a change should occur:

const editorState = prevState.editorState.reconfigure({ schema, plugins });
editorState.doc = schema.nodeFromJSON(editorState.doc.toJSON());

I'd be happy to raise a PR to extend the current docs for reconfigure to include a disclaimer around this, i.e.

Create a new state based on this one, but with an adjusted set of active plugins. State fields that exist in both sets of plugins are kept unchanged. Those that no longer exist are dropped, and those that are new are initialized using their init method, passing in the new configuration object. Schema nodes and marks should persist across schema changes as a semantically identical but newly created schema may cause issues with document editing.

Was this page helpful?
0 / 5 - 0 ratings