Pages with multiple instances on CKEditor 5 are unnecessary slow

Created on 17 May 2024, 11 months ago

Problem/Motivation

We have nodes with paragraphs which contain ckeditor 5 instances.
Now i know i could load the paragraphs in a closed state but this is not what we're doing.

We're currently optimizing the author performance and benchmark the application with Blackfire and saw that a lot of code is executed for each instance of Ckeditor which i think we should be able to cache for each text editor format?

See the attachments of the timeline and the zoom into the getAttachments functions which i think we should be able to statically cache for each text editor format?

✨ Feature request
Status

Active

Version

10.2 ✨

Component
EditorΒ  β†’

Last updated 14 days ago

Created by

πŸ‡¨πŸ‡­Switzerland yobottehg Basel

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @yobottehg
  • πŸ‡³πŸ‡ΏNew Zealand quietone

    This needs to be fixed on 11.x (our main development branch) first, and are then back ported as needed according to our policies. Also, 10.2 is in security mode now.

  • πŸ‡ΊπŸ‡ΈUnited States Chris Burge

    This makes sense. I have a customer who leverages paragraphs for their site, often with a dozen or more rich text fields on given node edit page. Page load times are quite slow in these instances.

    The ::getAttachments() method belongs to the Drupal\editor\Plugin\EditorManager class, so moving this issue to editor.module.

    Static caching seems reasonable. &drupal_static() can be used. Editors and text formats have a 1:1 relationship. Text formats have permissions and control access their editor, so I don't see any permission issue here with caching.

    We'll want to make sure to preserve the behavior of hook_editor_js_settings_alter() (i.e. $this->moduleHandler->alter('editor_js_settings', $settings); and below should not be cached.

  • First commit to issue fork.
  • Pipeline finished with Success
    6 months ago
    Total: 976s
    #292716
  • Put up an MR with changes to statically cache the editor attachments.

    We'll want to make sure to preserve the behavior of hook_editor_js_settings_alter() (i.e. $this->moduleHandler->alter('editor_js_settings', $settings); and below should not be cached.

    This could an issue if people are doing expensive operations in their alter hook implementations. The alter hook does not provide a way to identify editors by instance, so off the top of my head, I can't think of a reason not to cache after the settings have been altered. That being said, the MR caches before the alter hook, partly because it would break the existing automated tests by caching after.

    Moving to "Needs work" because I think there are tests that need to be added, but I'm not sure what kind of tests.

  • πŸ‡ΊπŸ‡ΈUnited States Chris Burge

    @godotislate - I like the approach of caching attachments in a class property. One thing I noticed when stepping through the method with a debugger is that editor_load() still gets called every loop if the text format doesn't have an editor assigned to it.

    I just pushed a commit to the MR that add an $editors property to the class and checks if the text format has been processed yet instead of checking if $settings['editor']['formats'][$format_id] is set. This ensures editor_load() is only called once for each text format.

    I'm not sure what kind of text coverage could be added for this MR. We can't test performance with unit tests, and the existing test coverage should ensure we haven't broken anything.

  • Pipeline finished with Failed
    5 months ago
    Total: 409s
    #342417
  • Pipeline finished with Success
    5 months ago
    Total: 1763s
    #342592
  • Status changed to Needs work 3 months ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Issue summary appears incomplete.

    This also seems like something that probably should have test coverage but not sure what that would look like.

  • πŸ‡ΊπŸ‡ΈUnited States Chris Burge

    Updated issue summary.

    I don't see a way to "add" test coverage for this performance optimization. Existing test coverage should ensure we haven't broken anything and should cover the changes made by the MR. As of last run, tests are passing.

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    We actually have performance testing in core.

  • πŸ‡ΊπŸ‡ΈUnited States Chris Burge

    I'd missed that addition. Here's a link to the D.O. documentation: https://www.drupal.org/docs/develop/automated-testing/performance-tests β†’ .

    It looks like we'd probably use the getQueries() method and/or the ->getQueryCount() method on the PerformanceData class.

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    I did post into slack asking for a 2nd opinion

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Okay got a 2nd opinion from @catch in slack. It would be nice to have performance coverage for ckeditor but most likely out of scope of this particular issue. So I opened πŸ“Œ Write performance test for ckeditors Active for adding that.

    So believe this one is good to go

  • πŸ‡ΊπŸ‡ΈUnited States nicxvan
  • πŸ‡¬πŸ‡§United Kingdom catch

    So this fixes the problem for this case, but I think we should consider changing editor_load() instead (or maybe as well).

    editor_load() attempts to pre-load all editor config with a multiple config entity load, this is to take advantage of multiple loading - either a cache getMultiple() or from storage.

    However, when caches are warm, this is exchanging multiple cache gets (which as it's config will be against apcu) for a database query + a single cache get - this happens in ConfigEntityStorage::loadMultiple() which calls ConfigFactory::listAll().

    If we only load the editors that are actually requested, we don't need the listing query.

  • If we only load the editors that are actually requested, we don't need the listing query.

    In that case, would there be any reason not to just deprecate editor_load($format_id)? It would be no different from Editor::load($format_id)/$this->entityTypeManager()->getStorage('editor')->load($format_id).

  • Pipeline finished with Failed
    about 2 months ago
    Total: 383s
    #427738
  • Pipeline finished with Success
    about 2 months ago
    Total: 362s
    #427798
  • Refactored this a little to use Editor::loadMultiple() with a set of IDs passed in, instead of editor_load(). This way there is only one query to load the editor entities, but also leverages the entity cache and does not call listAll().

    One possible issue that came to mind is that it is possible that editor entity CRUD actions during a request, so the statically cached copies of attachments and editors in the EditorManager would be stale. This doesn't seem to be all that likely, except possibly in tests, but this doesn't seem to affect existing tests since they all pass. It's possible to bring in memory cache-like functionality, but that increases complexity.

  • πŸ‡¬πŸ‡§United Kingdom catch

    If we make the editor config entity type statically cacheable (if it's not already), would we need the dedicated static cache here at all?

    I thought we'd already done that for all config entities but #1885830: Enable static caching for config entities β†’ is still open, however individual config entities can opt in.

  • If we make the editor config entity type statically cacheable (if it's not already), would we need the dedicated static cache here at all?
    I believe the editor config entity type is statically cached in via entity storage, but I think the weird issue here is that there are formats that could possibly not use an editor, so we'd have to track format IDs that an attempt to editors for but don't exist.

    Even without statically caching the editor entities here, I think we'd still want to statically cache the attachments/settings.

  • I believe the editor config entity type is statically cached

    Actually, looks like no, it's not. Only Role is opted in?

  • Pipeline finished with Failed
    about 1 month ago
    Total: 399s
    #435066
  • Pipeline finished with Failed
    about 1 month ago
    Total: 101s
    #435119
  • Pipeline finished with Success
    about 1 month ago
    Total: 653s
    #435124
  • Status changed to Needs review about 1 month ago
  • Made the change per #17 to editor_load() and deprecated after conversation on Slack. Added a CR.

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Feedback appears to have been addressed.

  • πŸ‡¬πŸ‡§United Kingdom catch

    One comment on the MR.

  • Pipeline finished with Success
    about 1 month ago
    Total: 481s
    #438610
  • πŸ‡ΊπŸ‡ΈUnited States nicxvan

    The comment was straightforward and addressed.

    I've been following and reviewing this issue for a bit so I agree rtbc.

    • catch β†’ committed b1a764c1 on 11.x
      Issue #3447794 by godotislate, chris burge, yobottehg, smustgrave, catch...
  • πŸ‡¬πŸ‡§United Kingdom catch

    Committed/pushed to 11.x, thanks!

  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024