Prose Mirror, buildless! (ESM support)

Hi there!

Browsers have improved a lot over the past years and it is now possible to do web development without requiring any build tools. That’s what I do by serving es modules with es-dev-server on my dev environment, buildless! Here is a nice article introducing the benefits:

Recently, I was comparing solutions for creating/integrating a rich text editor and Prose Mirror (PM) looks really interesting. Unfortunately, PM published NPM packages do not work buildless with modern web apps.

I am not the first to raise a similar need:

Going buildless, especially in dev environments is more and more frequent and the trend is not going to decrease with all major browsers supporting ES modules natively.

In order to assess what changes are required to make PM work buildless, I made a Proof of Concept locally for the basic example. As a result, the changes that are required are quite minor and are non-breaking! but they involve multiple packages.

Briefly speaking, it requires adding the non-standard but commonly accepted “module” field to all PM package.json packages. All dependencies must also provide an ES6 version of the code (no problems since the source code is already packaged). Besides, PM has only a few external dependencies (and most are managed by @marijnh), it is easily feasible. From what I experienced there are only 4 external dependencies for the basic example:

  • prosemirror-history -> rope-sequence

  • prosemirror-keymap -> w3c-keyname

  • prosemirror-menu -> crel

  • prosemirror-model -> ordered-map

Once these are updated to provide an ES6 version of the code (I adapted them locally), then all is working, buildless!

My question is twofold: are there other people who would benefit from such an improvement? @marijn (Marijn Haverbeke), would you accept the required changes after review if I contribute the PRs?

PS: the module field looks like a simple, transition solution to a better solution that was introduced in NodeJS 12 and still experimental in NodeJS 13:

1 Like

I have created a dedicated organization, forked all required repositories (24 repositories including transitive dependencies) and applied changes:

As mentioned previously, the changes are quite minor but are spread over several repositories.

I decided to publish packages on Github Package Registry to prevent polluting npmjs if the changes are eventually merged with upstream. To import dependencies, you need to create a .npmrc file in your project folder with the following content:


Then, you can import dependencies using common methods:

"@prosemirror-esm/prosemirror-example-setup": "^1.0.1",
"@prosemirror-esm/prosemirror-model": "^1.7.4",
"@prosemirror-esm/prosemirror-schema-basic": "^1.0.1",
"@prosemirror-esm/prosemirror-state": "^1.2.4",
"@prosemirror-esm/prosemirror-view": "^1.12.2"

The forked repositories are synchronized automatically but conflicts and package publications require manual intervention, so in the long term it will be hard to maintain. @marijn your thoughts are welcome. I would be happy to contribute the changes to upstream repositories.

Sure, let’s start with pull request to one of the cjs-only packages—if you port the source to ES6 modules and add a build step (using some small, quick, tool, I’m not sure what the options are at the moment, but I’d like to avoid Babel’s bloat for trivial packages like this), I’ll review your PR.

Does a "type": "module" field in package.json allow a package to expose both cjs and esm files? Or is that not what you’re suggesting? (Switching to esm entirely doesn’t seem like an option for the time being.)

Great! Thanks for your reply.

I will start with a PR to orderedmap so that we can agree on the method.

Does a “type”: “module” field in package.json allow a package to expose both cjs and esm files?

No. This field is still in the experimental part of the doc and would imply to switch entirely to ESM. I agree with you this is not an option.

Based on the recommendations, it seems the best would be to provide an ESM version of the code using the dedicated mjs extension, ideally, next to the cjs version of the files. Also, due to a large ecosystem that supports the module field (e.g. "module": "index.mjs"), it worths defining this field. I think it will be more clear in the PR.

I have sent 2 PRs to give an idea about what the changes are:

Looking forward to your feedback before going further.

@marijn PRs have been submitted for all submodules with the exception of prosemirror-schema-table that is deprecated. Do you plan to perform a release soon after the PRs are merged?

Running the release script right now. They should all be on npm in the coming minutes.

Thanks for your time and the release.

I noticed the PR for prosemirror_tables was not merged and thus no release was performed. Is there a reason?

Following your comment on prosemirror-menu, I added a suggestion:

I don’t maintain prosemirror-tables, so I can’t help there.