Export ProsemirrorState to Microsoft Word (Docx)

Hi all, I wanted to show a package that we are developing at Curvenote that allows us to export from a ProseMirror document directly to a Microsoft Word, docx file: prosemirror-docx. It is early, but functional and would love help or suggestions on how to improve the library.

prosemirror-docx has a similar structure to prosemirror-markdown, with a DocxSerializerState object that you write to as you walk the document. It is a light wrapper around https://docx.js.org/, which is what is doing all of the heavy lifting for export. Right now prosemirror-docx is write only (i.e. can’t read from a word doc), and has most of the basic nodes covered.

As a bit of an example:

import { defaultDocxSerializer, writeDocx } from 'prosemirror-docx';
import { EditorState } from 'prosemirror-state';
import { writeFileSync } from 'fs'; // Or some other way to write a file

// Set up your prosemirror state/document as you normally do
const state = EditorState.create({ schema: mySchema });

// If there are images, we will need to preload the buffers
const opts = {
  getImageBuffer(src: string) {
    return anImageBuffer;
  },
};

// Create a doc in memory, and then write it to disk
const wordDocument = defaultDocxSerializer.serialize(state.doc, opts);

writeDocx(wordDocument, (buffer) => {
  // This can be some other export if you are client-side
  writeFileSync('HelloWorld.docx', buffer);
});

We are using this to export from @curvenote/editor to word docs, but this library currently only has dependence on docx, prosemirror-model and buffer-image-size - and similar to prosemirror-markdown, the serialization schema can be edited externally.

Let me know if this is helpful, or what changes you would like to see in the library! Looking forward to feedback.

4 Likes

Very nice — I’m sure this’ll be useful to people already in its current form.

2 Likes

Cool! Don’t use docx myself but if I will, I’ll definitely try this out. Off the top of my head I guess it’s the norm to release stuff as ES modules nowadays alongside CJS. But that’s bit of a nitpick.

Totally fair, would love to learn how to do that or review a PR!! :slight_smile: