The ‘core’ library (not including the language packages) currently consists of 24 different packages. Setups usually don’t need all of them, but you’ll still easily end up with almost 20 of them, plus language support, for a typical editor project.
I really like the way this allows for tiny, separate codebases, makes sure I design package interfaces that actually allow 3rd party code to implement similar extensions, and produces very focused changelogs and releases. And if I at some point decide that, for example, the tooltip interface should work completely differently, I could release a new major version of @codemirror/tooltip without impacting the other packages.
Also, a structure like this encourages an ecosystem of 3rd party extensions, by giving them a similar shape to the ‘official’ packages. This is important to me, since I have no taste or energy to maintain every possible language and plugin myself as part of the core library.
But for client developers, the experience of setting up an editor and having to chase down 20 packages and figure out what to import from where is … not great. The long, flat list of package names in the reference guide’s table of contents is a pain even for me myself to navigate.
On top of that, npm often duplicates packages when you upgrade stuff and you have multiple things that depend on them, causing constant confusion.
So, as part of the things to take care of before locking down the API for a stable release, I have been thinking about package structure again. People have asked if the project can become a single package/repository, but I really don’t like that—it suggests this is a monolithic library, which is very much isn’t, and ties updates to all the various extensions together in big blobs of unrelated changes. Language packages should definitely be separate (having heaps of—often poor quality—contributed language modes in the main distribution almost burned me out on CodeMirror 5), so installing CodeMirror is never going to be a case of just linking in a single script tag or referencing some CDN script.
Given all that, what I’m currently leaning towards is to move a bunch of the smaller packages into other packages, to get a structure that is still modular, but not annoyingly modular. The interface as a whole of course doesn’t get smaller, but needing to install and import from fewer different packages should reduce cognitive load for developers somewhat.
The list below shows the design I am now looking at, with the remaining (8) core packages as top level items, and the packages that are being merged into them as sub-items.
- state
- text
- rangeset
- collab
- view
- tooltip
- panel
- gutter
- rectangular-selection
- matchbrackets
- language
- stream-parser
- fold
- autocomplete
- closebrackets
- commands
- comment
- history
- language-data
- search
- lint
The exports from merged packages would remain the same, they’d just move to a different package, making the overall effort needed for porting your code over to this relatively small.
Before I pull the switch on this I’d be interested in feedback, so if you have any thoughts or questions, please reply here.