Testing CKEditor 5 with Drupal: part 2

Table of contents

This article follows Testing CKEditor 4 to 5 upgrade path where I test the process to upgrade from CKEditor 4 to 5. The purpose is to review the ease of the upgrade path as part of its stabilization to be ready for Drupal 10.

Once more, I must warn the reader that all the difficulties I experience here are coming from how early this test occurs on the stabilization of this upgrade path. As I know of, while working on it at Drupal Dev Days Ghent, this is one of the first article to present it on a real website with complex (or at least not out-of-the-box) setup for my CKEditor. Please do not take this article for granted as of how Drupal 10 will work: every issues will be solved by then.

Start testing CKE5

Upgrade was done in the first article. My naive first test is now to edit my testing article which I described in part 1. Doing so, I quickly noticed that CKEditor does not show up at all :

CKEditor does not even load!

The reason is indicated in the browser console :

A not that cryptic error message.

From here, you might want to revert your mess to CKEditor 4. However, CKEditor 4 to 5 update is a destructive process. Therfore, reverting to CKEditor 4 via the UI dropdown will lead to a non-configured minimal toolbar.

Your only solution for a full downgrade is to revert your config files :

editor.editor.[xxx].yml
filter.format.[xxx].yml

After some digging, it appears that a Drupal specific configuration regarding the alignment plugin is causing CKEditor 5 to fail here. 

Short digression

Before I enter into that problem, let me digress on how Drupal handles CKEditor in core. As a developer, your first idea to debug the situation would probably be to click the alignment.js link on the console and see what's in the code here. Because you are on your local machine, you disabled CSS preprocess (merge and minify) from core - and eventually AdvAgg - via configuring your settings.php file as such : 

$config['system.performance']['js']['preprocess'] = FALSE;

However, you will soon notice that this has no effect on the CKEditor javascript source code. This code indeed is already shipped minified in Drupal. In fact, the workflow as a developer is that CKEditor plugins - such as the alignment one - are added to the project via an npm dependency to its packagist version. Running yarn install, the files end up in node_modules folder within the core folder. These plugins come pre-built for production, hence already minified. Of course, we don't ship the node_modules folder with Drupal therefore a webpack CI command, namely yarn run build:ckeditor5, copies those files outside the node_modules folder to the core/assets/vendor folder which ships with Drupal.

In other words, if you want CKEditor unminified, you have to manually install it from the source and build it yourself. A handy documentation is available for that but its discovery is hard. Fortunately, we have been working on it, and here is the issue created for it : 

[#3273532] Better discovery of DX CKE5 debug documentation

Feedback #4: As a developer, finding out how to install CKEditor from source and use it unminified in the project seems essential for easier debugging.

Back to a working CKEditor

End of digression: let's get back to the critical issue of CKEditor not running at all here.

Thanks to the error message and after some analysis, I was able to find the root of it. The issue [#3259179] introduced this regression in the first place. Now if you are ok to put your finger into this and dive in, the issue I opened and am trying to solve on the subject if this one :

[#3273510] CKEditor 5 crash when multiple alignment buttons are activated due to duplicate configuration

It is this kind of issue that starts with "hum.. those two items in the toolbar crashes when they are together" and end-up with "we have this whole inextricable situation that would require a whole new API for config files to be able to work the conflicts". The subject is really interesting and led me to one of my best times at DrupalDevDays Ghent: a pair-programming with Wim Leers and a beer during what was supposed to be social time night!

The whole story starts with the alignment buttons.

In a few words, let say that we - as in Drupal - have configuration yaml files for ckeditor5 related stuff. Namely in core, you will find ckeditor.ckeditor5.yml. In this file, we can define the CKEditor 5 behavior at the text format configuration page, meaning the available plugins and buttons (toolbar items) that can be dragged and dropped in the toolbar. In particular, we use a CKEditor 5 plugin named alignment which provides a dropdown button with the various alignment types possible : align left, right, center and justify.

In CKEditor 4, we had the same functionality, but provided as separate buttons. Hence, it was decided to trick the CKEditor 5 configuration to provide additional single alignment type buttons in addition to the dropdown. It was supposed to ease the upgrade from CKEditor 4 to 5 as well as keep the usability our site editors were used to. That addition is better explained at the following issue : [#3259179].

Text alignments dropdown and single alignment buttons. CKE5 crashes as soon as more than one of any of those buttons is used.

The dropdown button is defined as such : 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ckeditor5_alignment:
  ckeditor5: &alignment_ckeditor5_section
    plugins: [alignment.Alignment]
    config:
      # @see core/modules/system/css/components/align.module.css
      alignment:
        options:
          - name: left
            className: text-align-left
          - name: center
            className: text-align-center
          - name: right
            className: text-align-right
          - name: justify
            className: text-align-justify
....

and the configuration is reused all over the single alignment buttons : 

ckeditor5_alignment.left:
  ckeditor5: *alignment_ckeditor5_section
...

Did you notice the named reference and how it can be reused in YAML ? You can also concatenate your own changes with the one referenced via : 

1
2
3
drupal:
    foo: bar
    <<: *alignment_drupal_section

The whole thinking process over this took a few iterations but ultimately, it boiled down to a two-parts decomposition of the situation : 

  • Logical: It would be a nice addition to warn site builders that two buttons are not supposed to work together as it makes no sense. Here the dropdown and the single alignments, but it could also be the codeblock button from core and geshifilter button for instance.
  • Technical: Even if the user does add uncompatible buttons, it should not crash.

The thoughts over this has made us try multiple implementations, but ultimately, no generic way has been found to solve the technical crash that might happen here. Especially because we can't know which contrib modules will implement what and how can we make those behave together.

The logical aspect led us to implement additional API keys for the YAML configuration file of type conflicts_with. Follow the POC and help at :

[#3273510] CKEditor 5 crash when multiple alignment buttons are activated due to duplicate configuration

The technical issue is also discussed in that issue. But the resolution applied to alignment buttons is done in

[#3259593] Alignment being available as separate buttons AND in dropdown is confusing

where I am contributing a "configurable dropdown alignments type button". Your help, review and opinion is more than welcomed.

I will not bother you more with this issue as it gets pretty technical from here. I am not even sure at that stage if we could say it is a CKEditor 5 upstream issue or an issue with how Drupal uses it and builds the configuration. I suppose if somehow the toolbar items in config where namespaced in CKEditor it would arguably solves the issue, but it is true to say that our usecase - with available toolbar items configurable from a UI and provided by separate contrib modules - is a rather edgy use case for CKEditor 5.

To move on testing, I will now activate only the single dropdown alignment toolbar button.

Data lost

Let's edit my first paragraph.

It uses CKEditor 5 which loads properly here. However, at first sight, you can see that our <drupal-entity> tag is stripped from the source code and therefore, the image is missing. If I had clicked the save button from here: that image would have been lost. As I do not use the revision feature, it would be lost forever, which is totally unacceptable.

Entity Embed are stripped by CKEditor 5.

Feedback #5: Custom HTML tags are filtered even in full HTML mode. This is unacceptable as it strips and irremediably loses some data.

My image here is added using the Media Directories module, in particular its CKEditor integration submodule. That submodule uses Entity Embed as a dependency, and that last one leverages a <drupal-entity> custom tag to insert and process the content.

In parallel, Drupal uses the CKEditor 5 plugin named HTML support to offer full HTML support and restricted HTML support. This plugin however may allow any HTML to be valid via a special configuration which seems not respected, or at least not as per the documentation. Instead of allowing *any* HTML tag, if accepts any of the known HTML tags. <foo> or here <drupal-entity> or any non-existing HTML tag is stripped. Both a Drupal issue and a CKEditor upstream are opened for that purpose and can be followed from here : 

[#3268306] Custom/unofficial HTML tags not retained: <drupal-media>, <drupal-entity>, <foobar>

This is an issue with CKEditor 5 and unfortunately, that constitutes a release blocker for CKEditor 5 in Drupal core. I don't really know however if it could delay Drupal 10. In my opinion, keeping CKEditor 4 is not a viable option for backward compatibility and the expected life-time of Drupal 10, therefore we have to wait until this is solved.

Missing or broken functionalities

Moving on with testing my new CKEditor 5 toolbar, I can notice some functionalities missing. Those are mostly coming from non ported contribs so it misbehave as expected. Still, let's have a quick overview.

LinkIt

The LinkIt module lets me create links in my article that redirect to inner nodes within my website. The link is generated from the node data (uuid) directly and not from its URL as usual. That allows me to rewrite my URLs or move my node/view/etc... around and keep the link updated. That module does not provide an upgrade path so its functionality is not ported to CKEditor 5 at the moment. 

If I move to the source then back to the editor, the data attributes are kept. But as long as I edit any portion of the link (the link URL or link content), it is rewritten with a simple <a> tag and the data- attributes are lost. Hence, it is simply not usable at the moment, well... as per expected!

Follow LinkIt migration to CKE5 at [#3232190]

Lists <ul> and <ol>

I have in my article some pretty nasty nested lists with newlines, images, code and various things within. This is fully functional at the moment. However, I don't use specific attributes such as <ol start> or <ul type>. Those are currently supported when manually used from the source tab, but do not have a functional UI yet. A bunch of issues are tracking that on Drupal, and have correspondance upstream on CKEditor 5 as it is currently a limitation of that tool itself. Tracks can be followed at [#3274635] and [#3261599] plus associated issues.

Code blocks and syntaxic coloration

I have an extensive use of inline code, code blocks and syntaxic coloration via GeshiFilter.

The inline code tool is available directly in core, but there is no upgrade path at the moment from the CKE4 equivalent. That only means I had to activate it manually after my migration which is totally fine for me. However, a migration path is being worked on for core and track can be followed in this issue [#3274278].

I use GeshiFilter module for syntaxic coloration of my code snippets. That module does not support CKEditor 5 at the moment, so of course that misses. The upgrade to CKE5 and Drupal 10 can be followed here [#3274974].

The question here is to evaluate if an acceptable solution can be found with the provided CKE5 in the meantime. The answer to that is yes, "but". The "but" part being that the codeblocks tool only comes at the cost of migrating to 9.4.x which is currently not even alpha. Switching to that dev version took me literally only a minute and a change to my package.json so I did try!

It works fine here but a small quirk from CKEditor 5 itself: when editing the language via the source directly, the block is cut into three pieces.

CKEditor 5 codeblock edited from source splits the block into three parts.

As said above, this is a minor upstream issue with CKEditor 5, but it is kept tracked in core here [#3273552] for reference.

However, I did find out that for non-existing languages attributes, a language-plaintext value is added. That is the case for instance when editing an html5 block where language-html5 is unknown from the new CKEditor 5 plugin. It ends up as a language-plaintext code block where newlines seems to be ignored. The whole code block therefore ends up as a mono extra long line.

There is no geshi integration with CKEditor, but of course the text format still works. Surprisingly, because the original language-* is still kept, GeshiFilter module filter still runs and displays the proper coloration on the node itself which makes it all fine at the end of the day.

From dialogs to balloons

Let's focus a moment on a detail here, but that might have an importance.

In CKEditor 4, everything was modal dialogs. To illustrate, here is a link addition in CKEditor 4.

Dialog to create a link in CKE5
Dialog to create a link in CKE4.

The equivalent of those in the CKEditor 5 world are balloons (or tooltips). Let's see that in practice too.

CKE5 create link using balloon
Balloons to create a link in CKE5.

Why is it worth mentioning ?  Because of a long long on-going issue with nested modals in core ([#2741877]). It prevented the adoption of wysiwyg in views text-areas for instance. I created an issue about that in 2016 (!!) and still contribute to this day to solve the situation: see here [#2741187].

Needless to say, I was delighted by the removal of those modal dialogs here and I retried with CKEditor 5. It could actually work fine but the tooltip is not shown unfortunately. Even worth, CKEditor 5 tooltips do not work in *any* modal. If you remember well, in part 1, we discussed how I use Paragraph Layout to build my articles. CKEditor 5 is simply not usable at all via such a setup because of the non-displayed tooltips. That means I can't in practice edit or create articles on this website using CKEditor 5.

After some investigation, I found that the functionality is here though, just the tooltip is misplaced. Because CKEditor 5 adds it off-canvas it not that easy to fix, but I have created yet another issue to track that : 

[#3274937] Get CKEditor 5 to work in modals

Feedback #6: CKEditor 5 should definitely work for textarea inside modal dialogs as this is IMHO a pretty common use case, specially in contrib and custom world.

Conclusion

My tests with CKEditor 5 unfortunately have to end here. Hopefully I will be able to keep track of the various subjects pointed in this article and maybe even continue contributing.

I must confess how futureproof is my website here. How soon will I be able to migrate to Drupal 10 if so many features are depending on contrib? Will I be stuck on 9.3 or 9.4 with CKEditor 4 until all of them provide migration to CKEditor 5? Will there be leftover contribs and unsupported modules along the way? Well... wait and see.

This little taste of CKEditor 5 did not give me enough to let me enjoy as much as I would have liked. One thing is sure, in its current state, I would not be able to migrate  and use it for writing an article such as this one... which is a bit sad. The positive aspect is that issues are identified soon enough that work can still be done to get everything tuned for Drupal 10.

Add new comment

Your name will be publicly displayed along with your comment.
Your email will be kept private and only used to notify you.
On internet, you can be who you want. Please be someone nice :)