Research and implementation notes¶
This page is historical and explanatory. It preserves the design notes and alternatives considered when the exporter was first built, and is here for contributors who want context on why the project looks the way it does. It is not a tutorial and does not describe current behavior – for that, start with Getting started and the API reference.
R&D notes¶
Useful resources¶
Draft.js¶
- https://medium.com/@rajaraodv/how-draft-js-represents-rich-text-data-eeabb5f25cf2
- https://github.com/nikgraf/awesome-draft-js
- https://github.com/rajaraodv/draftjs-examples
Generating HTML in Python¶
- http://lxml.de/
- https://www.crummy.com/software/BeautifulSoup/
- https://github.com/html5lib/html5lib-python
- http://www.yattag.org/
- http://markup.sourceforge.net/
- http://pythonhosted.org/pyquery/
- https://wiki.python.org/moin/MiniDom
Limitations of lxml¶
- Succinct documentation (http://lxml.de/tutorial.html is the best)
- XML parser first, not really meant to build HTML.
- No support for document fragments.
- No support for text nodes (
elt.textandelt.tailattributes instead).
Limitations of html5lib¶
- Generated HTML is always "made valid" by being wrapped in
<html><head></head><body></body></html>.
Limitations of BeautifulSoup4¶
- The API to parse/generate HTML is clunky.
Constraints (to be weighted)¶
- Keeping the coupling between the CMS and the editor low so that we can change the editor's capabilities without having to write back-end code
- Giving the CMS enough control over the generated HTML. Not sure if "the CMS" just means "back-end" or if some JS code next to the editor code counts as well.
- Maintaining this over time with changing Draft.js output formats and unmaintained or wildly changing AST formats
- Regardless of implementation, being on the right spot between: "over the lifetime of the site/CMS, a given piece of content should always render the same HTML" and "a piece of content should always render the best HTML"
- Keeping the coupling between CMS and editor low so that we can swap editors easily (bigger scope than the one of a single site/project here)
- Favor logical completeness over raw speed. A regex parser will be faster than building a DOM. But caching makes that mostly irrelevant. The bottlenecks will all likely be in the DB lookups for inline entities anyway.
Other approaches to exporting from Draft.js¶
We have so far discussed a few different strategies to solve the rendering problem. Below are some of our notes.
We could create the HTML in JS when you save it in draft, then apply a similar strategy to Wagtail’s Rich Text, by iterating over the output with regexes? Still get the benefits of a much improved quality of editor and we can make use of existing JS-based draft exporters.
contentStateto JSON, Python doing JSON to HTML, with this contentState -> HTML exportercontentStateto AST to JSON, with AST to HTML in PythoncontentStateto AST to HTML, with extra Python regexescontentStateto HTML, with extra Python regexes
and it's not just contentState but contentState + some config
History¶
This project started as a Python port of the draftjs_exporter ruby library.
Other Draft.js exporter implementations¶
Full list on https://github.com/nikgraf/awesome-draft-js