Hacker News new | comments | show | ask | jobs | submit login
ProseMirror 1.0 (marijnhaverbeke.nl)
287 points by bpierre 8 months ago | hide | past | web | favorite | 66 comments

Hello, from The New York Times CMS team. We have been working with ProseMirror for the last year and a half or so. Congratulations, it's great to see this finally reach 1.0!

Some of the things we've found really great about working with ProseMirror:

- Separation of the data model from the rendered display has allowed us to extract things like tracked changes and comments which we traditionally embedded as HTML tags in TinyMCE. This leads to less cleaning and prevents inadvertent publishing of metadata.

- Unidirectional data flow makes it work well with applications that use this type of data architecture.

- Separation of modules (prosemirror-state, prosemirror-model, etc) has allowed us to quickly write better tests around our editor code.

- Decorations have been great for implementing the previously mentioned metadata aspects of our editor like comments and change tracking. They're useful for features like our custom spell checking implementation, which checks for Times style in addition to normal spelling/grammar.

- Node views allow us to implement rendering in our own way. We've been rendering React components into them which will eventually allow us to share code between our editing environment and our user facing web stack. They also allow use to render the same editor schema in different ways depending on the context/view they are being used in.

- The step/transaction model has allowed us to move from what was previously a set of additions and deletions persisted within the document to a calculated change tracking implementation. This allows both for a cleaner document but also allows for a wider range of tracking (i.e. show the differences between versions 10 and 15) rather than a static current vs the last "accepted" version comparison.

- Prosemirror’s plugin system is really simple and flexible and has allowed us to add new features to our editor rapidly in a modular way without interfering with other features (comments, custom spell checking, custom find/replace, etc).

Nice overview on the pros of ProseMirror.

When you were surveying the editor-landscape, what made you choose ProseMirror over its competitors?

At the time we started revamping our editing interface many of the options were still in early/incomplete places. I think ProseMirror had an funding campaign at the time that didn't meet its goal initially, although did later on in a second attempt. Ultimately we decided to venture down the path of building our own editor, which was based on a combination of our own learnings in text editing and a collaborative system some folks in our graphics department had put together.

About 6 months in, near the start of 2016, when moving on from the exploration/demo stage of the project to actually building out the real deal we took another look at the landscape and decided to move to ProseMirror. I don't remember the exact points that went into the decision but transitioning from our in house solution to ProseMirror felt pretty natural as they followed similar design philosophies.

Thanks for the response!

You went down the hard path of rolling out your own editor, and used the knowledge gained to choose a worthy successor.

I'm impressed. I should give ProseMirror another shot.

I also think the fact that Marijn had CodeMirror on his resume helped with our willingness to take a risk on a pre 1.0 library

i think the most similar lib to ProseMirror is http://bustle.github.io/mobiledoc-kit/demo/

I think they just told you?

There is some overlap between the points listed and the features other editors offer. Unidirectional data model for example is also in SlateJS.

More pertinently, I’m interested in what made them choose ProseMirror at the time, as opposed to what they like about it now.

The true test of ProseMirror, SlateJS, and all these new augmented text-editors will not be comments, posts or even blog articles.

It will be Wikipages.

A visual editor for a wikipage is the crystallization of the semantic-content conflict as described eloquently by https://en.wikipedia.org/wiki/WYSIWYM

To date, despite a stream of donations and years of development, Wikimedia has failed to develop an editor that is better, by productivity and other lagging metrics, than just editing a text-field:

https://en.wikipedia.org/wiki/VisualEditor https://www.theregister.co.uk/2013/09/25/wikipedia_peasants_...

Increasingly, I believe what we really need is an enhanced markup editor-- where bolded text is bolded text, a quote is automatically highlighted as a quote, but links look like (check this link out)[http://example.com]. The ideal would be to forgo the "drop down to normal text editor" button and have the only & best way to edit be through the new editor.

Atlassian is experimenting with ProseMirror for their wiki—I think the configurable schema feature goes a long way towards solving this. (Coincidentally, Adrian, who is a contributor to ProseMirror, was one of the people who worked on WikiMedia's editor effort.)

We’re building the wiki engine https://www.nuclino.com based on Prosemirror. It would be great to get your feedback on it! I think a single editing mode is the way to go and Prosemirror's flexibility allows us to strike a great balance between usability for non-technical users (via menus) and speed for technical users (via markdown commands).

I find the UI of your website to be intuitive and attractive, although I'm probably not the customer you have in mind.

Can these WikiPages be made public to non team users? I.e., made public?

This is likely a non-issue for your product, seeing as it is team-oriented rather than community-oriented.

I'm glad you like the UI. Unfortunately, making the entire wiki public is not possible at the moment due to our focus on teams and companies. They use it to share knowledge internally and explicitly don’t want to have it indexed and publicly accessible.

It could be interesting though to expand Nuclino for the use in communities in the future as a lot of requirements overlap.

I couldn’t agree more. We were in the process of building our intuitive wiki platform (https://www.wikiful.com) when Marijn first announced ProseMirror. Seeing what a powerful tool it was, we decided to make it the backbone of our WYSIWYG editor.

Our goal was to create an editor intuitive enough to be accessible to the tech-unsavvy, while also curing the ills (slowness, plugin overload) that frustrate our tech colleagues who use current enterprise wiki products.

You’ve clearly put a lot of thought into what makes a great editor — any comments you have on Wikiful's editor would be much appreciated.

I wrote this. I'll be monitoring this thread and responding to questions here for the next few hours.

I'm currently experimenting with CodeMirror for one of my projects, and it shows that you spent a lot of time to refine its design and API. You did an awesome job, seriously.

I haven't tried ProseMirror yet, but I'm pretty sure that the same level of quality is there.

Thanks for your work!

This looks awesome! I'm a big fan of CodeMirror and I will definitely play with this tool as well.

Quick note: the Markdown example page (http://prosemirror.net/examples/markdown/) has a javascript error that's keeping the editor from loading.

Thanks for all your hard work.

Markdown demo should be fixed now, thanks!

I just wanted to say thanks for this (and for Codemirror.)

I haven't released a product using this yet (although I hope to) but I really want to congratulate you for writing something that focuses on a narrow yet hard problem, that a lot of folks would consider uninteresting because it's been "solved" in other domains, and just doing a really, really good job.

Seeing an issue on Chrome 61 on http://prosemirror.net/ : If I highlight some text in the example editor and click the link button, the 'Create a link' box displays at the bottom of the page.

Thanks for letting me know! I was failing to include a CSS file—should be better now.

Glad I could help! Also seeing an issue where the editor isn't loading on http://prosemirror.net/examples/markdown/

Thanks once more -- that was another build problem.

Thanks for all the work you've put in to this. I'm actually using this on a moderately large project at work and it's been a dream to integrate and learn.

That's great to hear! Learning curve is definitely something that's tricky with a library like this (big, modular, with concepts that are unfamiliar to many), so I've tried to compensate with consistency and lots of documentation.

In theory, would ProseMirror work well as the foundation for a code editor (instead of CodeMirror)?

No, it wouldn't. That requires a completely different set of features (gutters, syntax highlighting, etc).

CKEditor 5 is also worth a look. They just released their first alpha version. The editor now uses a model separate from the DOM which can be used to implement support for collaborative editing. In addition to providing an extensive API, there are ready-made builds which can serve the same purpose as TinyMCE and CKEditor 4. This being CKEditor, we can probably expect support for pasting content from Word and Excel in the future. GPL/LGPL/MPL. We've just started using it in our SaaS product and have been impressed so far. https://github.com/ckeditor/ckeditor5-design/issues/181

Your note is very appreciated. I'm currently in the early stages of deciding on an editor/framework that we need to build upon for custom features. CKEditor just went up the list after looking at it.

ProseMirror was up there from recommendations from a colleague who has worked with CodeMirror as a basis for a collaborative editor before, but it needs more work for basic features.

I love CodeMirror and like very much the content of the Marijn's blog posts I've read, but I must say ProseMirror is a nightmare to work with. I guess the problem is that there is too much customization options, no sane defaults, no understandable tutorials, many different overlapping API and documentation versions.

I've tried a lot to get it working for https://github.com/fiatjaf/coisas and only managed to make it work by copying running code from one of the demos, ignoring all customization and working myself around the editor to provide the custom functions I needed.

I may be totally wrong here, but I'm trying to be sincere about my experience.

Thanks for sharing your experience. It sounds like the author is aware that ProseMirror is hard to work with, and to some degree this is "by design". From the announcement:

> If you're looking for a simple drop-in rich text editor component, ProseMirror is probably not what you need. (We do hope that such components will be built on top of it.) The library is optimized for demanding, highly-integrated use cases, at the cost of simplicity.

I used ProseMirror back in the day (well over a year ago now) on a site I was working on and it ended up being a nightmare to maintain. It would break on every new version, screw up the build process, error constantly in mysterious ways that forced you to dive into the internals... At the time it was not designed with the state-view architecture either, making it harder to reason about.

I ended up scrapping it entirely for Quill and it was a massive relief.

In my opinion as a mostly-uneducated observer to this project, it is exactly the kind of project that would benefit massively from static type-checking. I can't count the number of times things broke on an upgrade because of simple bugs in the code where `undefined` would trickle through function calls or function interfaces were updated and other parts of the codebase were not updated in accordance. These are not hard problems to solve, but if you're dogmatic about using vanilla JS with as little build step as possible, you're going to run into these all the time.

As announced, breaking changes are over now. And the interface is written to be easy to type, and [type definitions](https://github.com/DefinitelyTyped/DefinitelyTyped/pull/1698...) are available.

Sorry that I was not clear in my original comment, I meant to say that I speculate the ProseMirror codebase itself would have taken massive benefit from type-checking over its lifetime, to reduce the number of bugs the end user would have to track down.

Have you looked at Quill https://quilljs.com/? I was looking at text editors yesterday for a new project, where I want to represent images as either custom tags or placeholders that get transformed (in the system the image is known by its storage ID, not a URL) and Quill looked easier to work with than ProseMirror.

I haven't tried ProseMirror, but I've can second the endorsement for Quill. For the past three months, I've been working on a large-scale integration of Quill (with lots of customizations) into a commercial word-processor (https://shaxpir.com) and it has been a lovely experience.

A lot of the underlying ideas are similar between Quill and ProseMirror, so I'm curious to hear a knowledgable comparison of the two. But the excellent Quill documentation, as well as the responsiveness of the primary developer to github issues and stackoverflow questions, made it an easy choice for me.

I have looked at it and don't remember why I didn't end up using it. Perhaps due to my ignorance, I have probably thought it wasn't capable of outputting Markdown seamlessly, and that was really necessary for https://github.com/fiatjaf/coisas/.

If you want to drop-in rich editor, give froala a try: https://www.froala.com/wysiwyg-editor We are super happy with it.

Cool to see persistent data structures under the covers here. I tried to make a contentEditable editor some time ago and gave up when I realized how many edge cases there would be, but from what I learned when working on that, this general sort of approach seems like the right way.

What do you feel like you learned when working on this project? Will any of it make it back to Codemirror?

I finally figured out how to apply a functional / unidirectional data flow architecture to the (demanding) case of an editor. And yes, there are plans to integrate this into CodeMirror at some point.

Can you comment on what you figured out? Was it about making functional/persistent data structures performant enough, or something else?

That. And also how to deal with the interaction between browser state (around IME and such) and the component state. And how to properly model updates (see thread [1]) in a way that plugins can extend and consume in a modular way.

[1]: https://discuss.prosemirror.net/t/discussion-the-limits-of-a...

Marijn, congratulations on the 1.0! This project is a great example of an entirely new crowd-funded open-source project. I am glad I made a small personal 25€ contribution, and I hope that future work projects will allow me to send more money your way.

How does it compare with other modern solutions like https://quilljs.com/?

Author of Quill here. Interested in hearing Marjin’s thoughts but here are some of my main observation is at a high level Prosemirror is much more willing than Quill to sacrifice simplicity for power. This value difference manifests in the target audience, architecture and API design:

Quill can be used for the get going quickly drop in use case. Prosemirror specifically warns against this: “If you're looking for a simple drop-in rich text editor component, ProseMirror is probably not what you need. (We do hope that such components will be built on top of it.) The library is optimized for demanding, highly-integrated use cases, at the cost of simplicity.”

Prosemirror’s schema, as documented, is more flexible than Quill’s. Prosemirror appears to allow anything, whereas Quill imposes some constraints. For example Quill requires all nodes to either be a leaf and cannot have children or a container and must at least one child. There cannot be a node that can optionally have children as is allowed in Prosemirror. In my experience the constraints Quill imposes lead to a more consistent and bug free experience across browsers. I will be curious to try out the edge cases I have encountered at this new 1.0 Prosemirror to see if it handles them the way an end user typist would expect. If Quill can benefit from a shift in the flexibility in its schema, it will do so.

Quill is far more battle tested. Slack, Salesforce, LinkedIn, Intuit and many others are using Quill in their main user-facing production products, not an internal employee only tool. Prosemirror has a great start with the NY Times but there is a large difference in adoption at the moment.

> Interested in hearing Marjin’s [sic] thoughts

Sure. I think it's fair to say that ProseMirror is a more ambitious project, reaching for features that aren't part of (even the new crop of) existing libraries.

* Firstly, the schema feature. ProseMirror's content expressions [1] are a regular language that can be used to describe a sequence of child nodes. The editor will make sure the content of the node always matches this expression. This allows significantly more interesting things than Quill's array of allowed children—i.e. "heading block* section*" to say that a given node must first contain a heading, then any number of blocks (say, paragraph, list, figure, aside, etc), then any number of subsections. (HN's half assed markup doesn't seem to allow escapes on asterisks, so I used *'s)

* Quill uses imperative data structures and events throughout. I've really become convinced of the power of functional Redux-style architectures for this kind of component—I've found it makes it much easier to write bullet-proof extensions. (This may be a matter of taste.)

* Table support doesn't appear to exist in Quill yet. A table module with features like colspan/rowspan and cell selections has been written as a relatively small plugin [2] for ProseMirror.

* Exposing all the system interals (and designing them in a way that makes them usable), rather than hiding stuff behind a small API, means that people can do really advanced things as extensions. This was a lot of work, and wasn't initially planned, but the kind of users we're aiming for require it.

* As for real-world use, yeah, we've just released 1.0, your project is older. Still, our users (including Atlassian, which has already rolled out ProseMirror in user-facing products) have been doing very advanced stuff already, and my ten years of experience with CodeMirror mean that I more or less know what I'm going to run into.

[1]: http://prosemirror.net/docs/guide/#schema.content_expression... [2]: https://github.com/prosemirror/prosemirror-tables

(Also your website claims, wrt to ProseMirror: "Quill’s architecture is more modular, allowing for easier customization of internals. Core modules that handle basic functionality like copy/paste and undo/redo can be swapped out in Quill." I think that's a mischaracterization.)

Also, ProseMirror is definitely seeing wider adoption than the parent implies. Even from this thread alone, we're seeing Atlassian and startups pop-up attesting to its good design.

Your points are fundamentally correct, and I would argue that your parent is attempting to limit the potential of ProseMirror, in order to preserve the need for Quill.

there's more than enough room for everyone.

indeed, there will be demand for more/different products even after both of these competitors maximize their reach.

The issue isn't so much about room as it is about bandwidth. Specifically, mental bandwidth.

There use to be loads and loads of JS frameworks of dubious merit and with equally dubious developers. Now there's generally an agreed upon few (Angular 2.0, React, Vue) that are pretty solid and seem to be helmed by mostly sensible people.

Unfortunately, we're still in the early stages of open-source WYSWIG/WYSWIM;. By the later stages, I hope we can thin out the technically unsound editors with insecure authors.

I wouldn't use Quill.

The developers are passive-aggressive to the notion of rendering Quill content outside of the Quill Editor, having ripped out the APIs to do so from newer versions, and silencing conversations in their Github Issues.

You can see the latest flare-ups here: https://github.com/quilljs/quill/issues/993

The project also has secondary smells such as inventing weird names for existing concepts; 'Delta', for example instead of 'data source' or something more intelligible.

Lastly, it markets itself as feature-complete, but has failed to implement support for something as basic as tables, which have been repeatedly requested for the past 3 years.

Personally, I would be afraid to build anything mission-critical upon it.

Quill is now a very popular project on Github, in the top 250 of all projects. A lot of people want to add their two cents to popular project and unfortunately the volume is far too high for a) me to respond to every single attempt at adding said cents and b) Github Issues's linear commenting UI makes all attempts at adding two cents confusing and cluttering. With this I prioritize the question that was asked, and specifically the concerns the OP raises.

I have repeated many times that the removal of getHTML was because it was a passthrough function that added no additional value to Quill. You can look at the code history and the implementation of getHTML to confirm this fact. It has nothing to do with the desire to remove functionality as no functionality was removed.

I'm confused why Delta is a bad name, since the word delta means change, variation or difference and that's seems to describe what it is: a change to Quill's content. Data source on the other hand is unspecific and even misleading. Naming is hard though and other readers can find out what Deltas are here https://quilljs.com/docs/delta/ and decide for themselves.

Tables was reported as a feature request by me early in the project life because it is a known feature of Word but only years later did users indicated strong interest in it in Sept 2016. I believe in community contribution to open source so I decided to give the community a chance to build it so I wrote offered detailed implementation guidance: https://github.com/quilljs/quill/issues/117#issuecomment-244.... The fact that this user had seemingly urgent need for it and was employed by a large public company with resources also contributed to this decision. Valuable exchanges were had in the Issue and multiple users has fully implemented it for their companies to varying levels of feature richness depending on their requirements. An official canonical implementation is coming in 2.0: https://medium.com/@jhchen/the-state-of-quill-and-2-0-fb38db....

Your response is mostly reasonable and your parent sounds overdramatic. However the github thread looks quite bad for you.

For the record, I know jchen has already responded but I thought I'd add my bit here.

I display html content based on quill data all the time. I've done it using quill to generate the html source, by writing a separate library to convert from Delta representations to html strings, and most recently as an angular 2 webcomponent (since angular 2 doesn't really like it when you inject html strings outside of it's lifecycle, if you want the resultant DOM nodes to be angularized).

All three ways have worked well. Personally, I like this last way the most, but owing to the vagaries of angular template compilation it is difficult (or impossible) to really abstract it into a standalone library (because the top level template needs to reference any possible custom components that are local to your app, such as an atmention thing that pulls in an avatar image from some profile data or whatever)).

Anyway, I use quill, and have used it since we'll before 1.0 days. At the time, it was the only game in town for emitting Deltas that could be wired into an OT engine, and it still works really well in my concurrent rich text editor for an internal cms/forum.

That said, prosemirror also looks pretty rad, and I will also be checking that out eventually also. I feel like there's room for both in the world.

Marijn, I'm big fan and user of CodeMirror. I make extensive use (and arguably abuse) of it in my side project. Thanks for building ProseMirror.

One thing, how does ProseMirror work roughly? Does it avoid the `contentEditable` minefield? (I'm speaking as someone who has built a WYSIWYG editor in a past job.)

Yes, it uses contentEditable. There's a write-up from last year at http://marijnhaverbeke.nl/blog/prosemirror.html . Some details have changed (we make more use of DOM diffing and mutation observers than initially hoped), but most of the info there still applies.

We actually use codemirror at work as the basis of a fully-operational operation-transform based collaborative editor. We are working on open-sourcing our implementation, but thank you for all your hard work!

It's interesting about not being able to easily bolt on collaboration; it was not a trivial endeavor at all, but codemirror's APIs made that part exceedingly easy :)

What I've never seen in any rich-text web editor is an ability to have more complex numbered lists. So often I want to put in a block of content (e.g., a small code example) as part of a numbered list item, and then resume the list after the block . But they all restart me at "1."...

If you press backspace in an empty list item in the demo, you can continue the item above. The schema is tree-shaped, so you don't have the usual awkwardness about nesting things.

Or, if you mean lists starting at something other than 1.--The schema used in the examples actually supports a `start` attribute on numbered lists, but the UI doesn't currently expose it.

The color of the links on that blog is not very colorblind friendly. I couldn't tell what was a link and what wasn't without zooming in to make the text larger.

I've made them a little brighter, hope that helps.

I'm a big fan of your work Marijn!

Do you have a Patreon or other donation method on your site?

Yes, I have a small patreon at https://www.patreon.com/marijn. Right now I'm also running a crowd-funding for the new edition of my book at https://eloquentjavascript.net/3rd_edition/

Don't forget to download a bitcoin wallet and add a bitcoin address for donations to the page.

I've added a bitcoin address (but didn't integrate it into the automated checkout flow, so you'd have to email me to claim perks).

Could you also open an account on [Liberapay](https://liberapay.com/)?

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact