Last week brought another successful pair-programming sprint towards ApostropheCMS 3.0, the next version of our open-source Node.js CMS. A major focus is migrating to the Vue frontend framework. And we really like Vue. Because Vue can do magic.
This time, Bob Clewell and I focused on a simple goal: editing Apostrophe’s pieces with Vue. “Pieces” are simple, standalone documents like blog posts and events.
Pieces rely heavily on schemas. So the greatest amount of work went into bringing Apostrophe’s schemas to Vue.
Magic trick #1: the Component element
Apostrophe developers expect to just list the fields they want and watch the magic happen; Vue is more commonly used for “bespoke” user interfaces where each field is hand-coded. How to bring them together?
We solved it by making liberal use of Vue’s Component
element. Here’s how we loop over all of the schema fields and output each one with the appropriate component for its field type:
component lets us delay the decision of what Vue component to use for each field until we know the field’s type. Nice one, Vue.
Magic trick #2: keeping a Rabbit inside your Hat
We also love Vue’s “slot pattern,” which allows us to wrap a component in another, reusable “layout component.” Here’s our ApostropheFieldset
component:
And now the ApostropheString
component that wears it like a tailored suit, slipping its body
in the middle:
Magic trick #3: two-way data binding
All of that is pretty magical. But our favorite bit of Vue magic, so far, is v-model
.
v-model
allows us to create a “two-way binding” in which a certain property of our data automatically “comes to life,” powered by a particular component.
All Vue developers have used it to power ordinary form fields; what you might not know is that you can add that same power to your own components.
What’s the big win there? We can just hand an Apostrophe document object off to an ApostropheSchemaEditor
component with v-model
, and… boom. Instant editability.
Here’s ApostrophePiecesInsertModal
, a dialog box for creating a new document. We use v-model
to hand control of our “piece” off to the ApostropheSchemaEditor
component. Easy-peasy.
We also take advantage of slots again here, overriding parts of ApostropheModal
, which is based on the excellent example in the Vue documentation.
Magic trick #4: mixins save time (and prevent bugs)
There’s one more bit of Vue magic that we really like: mixins. Vue doesn’t have object-oriented inheritance, as such. But mixins provide very similar capabilities, in a way that is especially well suited to creating reusable interface components without duplicating code.
Here’s ApostropheFieldMixin.js
. Here we implement all the parts of a component for an individual field that most field types won’t need to change:
The mixin does so many things for us right off the bat:
- It implements the
v-model
pattern, accepting avalue
prop and emitting aninput
event when the value changes. It also watches thevalue
prop so it can react if the field’s value is changed “upstream” in the schema editor. - It provides a
next
data property that’s ready to be hooked up to the actual input field, again viav-model
. - It handles defaults.
- It obtains
options
for us from theapostrophe-schemas
module. Before you ask: these don’t change during the lifetime of the page in the browser, and they are pushed down to the browser by server-side code. So yes, they do belong inwindow.apos
. - It invokes a
validate
method to make sure there are no errors in the input.
But wait, where is that validate
method? It is provided by each field component. Here’s the code for ApostropheStringField
:
Thanks to the mixin, plus the template you saw earlier that binds a text input field to next
, the only thing we have left to do is validate our input by providing a validate
method. If we don’t like it, we return an error string that will become part of a CSS class.
Upstream from us, ApostropheSchemaEditor
can easily inspect all of the values of all of the fields, spot any error
properties, and present ApostrophePiecesInsertModal
with what it really needs: the latest version of the document, plus a hasErrors
flag to help decide if we can save it yet or not.
This is some really cool magic. But Apostrophe 3.0 still isn’t a usable CMS just yet (although 2.x surely is, and will be supported for years to come). So what’s our next trick?
Sprint #3: editing content on the page
We have further to go with pieces, for sure. We still need to build a tabbed interface, and many more schema field types including complex cases like array
that can have their own schemas. But we’re confident in our direction and can work independently to take those things to the finish line.
So the next sprint will focus on a different area of Apostrophe: editing content in context on the page.
That means marrying Apostrophe’s concepts of widgets and areas on the page with Vue components that play nicely together even if some of the content inside them isn’t coming with Vue, since we don’t plan to require Vue on the front end. And that should be an interesting challenge.
Sprint #4: is it time for a new rich text editor?
One thing that will make sprint #3 a little easier: while widgets have a place on the page, they are most often edited via simple schema-based forms.
But there are exceptions. And that brings us to one of the most interesting challenges.
Is it time to ditch CKEditor?
We’ll put it right out there: CKEditor has been great for Apostrophe for many, many years. And we’re grateful. Along with TinyMCE, CKEditor has for many years been the only in-browser rich text editor with two critical features:
- A permissive open source license, compatible with most projects.
- Serious… even fanatical… amounts of cross-browser testing.
And we can’t stress either of those enough. Without the first, developers won’t use it. And without the second, a rich text editor is just a cute parlor trick that only works in Chrome.
So while other editors are aesthetically appealing and might load more quickly, it’s been hard to part with CKEditor.
But the latest version of CKEditor has a different license. And in recent years, Quill has broken free from the pack of flash-in-the-pan rich text editors to make a serious dent. And it sure is pretty, both for users and for developers.
But… so does Slate. And developers are passionate about the pros and cons of both. We hear things. Things worth testing for ourselves.
So in Sprint #4, we’ll make up our minds through experiment and experience. And that should be great fun.