Closed janreges closed 1 year ago
I'm going to close this as a duplicate of https://github.com/craftcms/cms/issues/13297 since most of it is not Neo-specific, but I've separated the points about the performance issues when editing Neo fields with a large number of block types, and suggestion of lazy loading of block type settings, into #752.
Hi @ttempleton - thank you for your reply and creating #752.
In the case of the division of responsibility in the code between Neo and Craft CMS, I estimated that an optimization could be made also in the Neo code, which would prevent the constantly repeating initialization of the field if it is used in several Neo blocks.
Example: for absolutely all types of blocks, we have an optional field htmlId
- if it is filled, the wrapping HTML element of block on the frontend will have the HTML id
attribute filled in, e.g. for the possibility of referring to part of the page with the anchor #myBlock
or for similar purposes (element identification for E2E tests, JavaScript functionalities, etc.). It would therefore be appropriate for Neo to initialize this field only once and not 100 times, if it is occupied in 100 block types.
Is this my thinking wrong? Or do you think that specifically in this matter it is possible to perform optimization only in the code of the Craft CMS itself and not in the Neo plugin?
I know that in Craft CMS version 5 some improvements are also being made to Matrix, which Neo is partly based on. But we are trying to find a solution to this performance problem that we could deploy these days. I will be grateful for any ideas and quick-win solutions. Thank you :)
If I'm understanding correctly - e.g. if you're accessing block.someField
where block
is a block of any block type that has someField
on its field layout - I'm not sure how feasible it would be for us to try Neo-specific optimisations, since getting the someField
value involves code that runs by default for all Craft elements, so I'm guessing there would be a decent amount of duplication of that code that we would need to do to replicate the process in general. It'd be far better if any possible optimisations of that type were made in Craft itself, so that all types of elements - both internal and provided by plugins - could benefit.
@ttempleton - please accept my apology. I found and checked templates/block.twig
in the Neo repository and now I understand you.
At the Twig templating and rendering level, you're really using variables directly from the Craft model, and you can't really cache much at that level.
For example, my thought was... I'm iterating through each block type of Neo block. If I find that a call in the sense of block.myField.type
will search for information about the field type, I implement a simple cache at my level so that I don't ask for the myField
type again when rendering the next block type with same field. In this case, however, I agree that this cache should be implemented on the model side in Craft. Thanks to this, other plugins, such as SuperTable, will also benefit from it.
I will try to do a deeper investigation into which parts of the Craft model code are called repeatedly (because lot of same fields are used in multiple blocks) and where they could potentially go to implement optimizations. I will then send these to Brandon as part of the task https://github.com/craftcms/cms/issues/13297
Thank you for your time.
Just released Neo 3.8.0, in which block type and block type group settings are lazy loaded, among a few other optimisations that should significantly improve the loading time for Neo field settings pages.
Hi @ttempleton.
Thank you very much - I tried version 3.8 and it works great! 😍
On AMD Ryzen 5950x, the initialization of the Neo block setup page in our project was shortened from 65 seconds to 1 second. This is great 👍
By the way, is it impossible to implement lazy-loading as part of addding/editing a page with a Neo block?
In our case, the user wants to create a page. It doesn't have any content yet, but it already has a Neo dropdown option with a selection of all available blocks. Even if you do not select a single block, or select 2-3, the forms for managing all blocks are still rendered when the page is loaded (even if they are hidden in HTML/JS). Therefore, the form for adding or editing a page is generated on the server for 5-10 seconds.
I assume that implementing lazy-loading at this level would be significantly more complex?
The code we have in place to render cloned/pasted blocks could probably be used to support lazy loading of block type input HTML/JS, so that's definitely worth looking into. I might not be able to look into it for a few weeks, though, but will open a new issue for it so I don't forget.
@ttempleton - that's great news! Thank you very much :hugs: This optimization will be essential for our team and our clients.
We will also deal with some related optimizations with the Craft developers. For example - below is a screenshot of Ajax profiling of the request that executes after clicking on the configuration of the Neo block. Even on the powerful Ryzen 5950x, this request takes 1.6 seconds, on the average server it will take, for example, 4-6 seconds. One of the reasons is the non-optimal lifecycle of Craft CMS architecture. For example, it is very inefficient that even with an Ajax request like in your plugin, SEOmatic and other plugins or CMS functions, which generate hundreds of DB queries and thousands of events, have to be initialized unnecessarily. A bunch of completely unnecessary overhead and load that the Ajax request itself doesn't need at all.
Ajax requests are made by other plugins as well, that's perfectly fine. With another plugin, for example, we see an Ajax request that performs 2 DB queries and returns 2 small text items in JSON. The whole request could take 10-20 ms even with authentication, instead it takes 1.5s (150x slower).
Bug Description
Hi,
for our projects we use Craft CMS (PRO) and usually we need the client to compose the individual pages himself from the individual visual blocks. We implemented the management of the structured content of these blocks using Neo and SuperTable plugins.
Note: I am creating this ticket in the Craft CMS, Neo and SuperTable GitHub repositories. I am interested in the opinion of the authors and architects of Craft CMS and these plugins. After investigating these performance issues, it is evident that some optimizations and solutions to these problems can be implemented in the Craft CMS code and then subsequently in the individual plugins.
Facts about our project
Settings -> Fields
section - 20 of them are of Asset type (typically images for visual components). We have all assets in only one common volume, which is on one local filesystem.Issues we have and perceive from the Craft CMS perspective
Our investigation of the problems and findings
How can you help us
We would like to hear an informed opinion from the authors/architects of the existing code on the possible causes of these problems, but our investigation of the existing code shows that:
getRootFolderByVolumeId($volumeId)
method is called over 1,000 times, causing over 1,000 identical queries to the database. We have therefore implemented a simple composer patch below that will reduce the number of related identical duplicate DB queries from 1,000 to units and likewise reduce the number of events or logs by thousands. A sample of this patch is at the end of this ticket. Even this one small optimization sped up page generation with page editing by 15-30%. However, this patch does not address the situation where the volume settings are modified as part of the script run, so it is not an ideal solution.How to proceed?
We really like the Craft CMS and a number of useful plugins and we are trying to promote them. Unfortunately we have now run into some very fundamental performance issues.
So the first thing we thought of was to start investigating these causes ourselves, think of and implement some optimizations and then send pull requests.
As authors, do you please have an opinion on how to solve this situation? We'd be happy to help with optimizations, but if any of the Craft CMS architects have already had some thoughts and ideas on these improvements, we'd like to know so we don't do double work. This will also increase the chances that even if we design and implement some specific optimizations ourselves, they will be incorporated into future versions faster and without major comments.
You may also be self-aware that, based on some historical architectural decisions, some forms of efficient caching are now not applicable at all. For example, I imagine that serializing some complexly loaded objects into the cache won't work because the architecture requires that lifecycle of their initialization throws a number of events on which other functionality depends.
I would be very grateful for any thoughts and ideas on how to grasp and implement these necessary optimizations.
If needed, I can also provide a complete configuration of our CMS, including a database dump to your e-mail address.
Thank you very much for your time and support.
Patch
getRootFolderByVolumeId()
Craft CMS version
4.4.13
PHP version
8.1.18
Operating system and version
Debian 11 Bullseye
Database type and version
MariaDB 10.11.2
Image driver and version
GD 8.1.18
Installed plugins and versions
Steps to reproduce
See description.
Expected behaviour
No response
Neo version
3.7.9
Craft CMS version
4.4.13
What is the affected Neo field's propagation method?
No response
Does this issue involve templating, and if so, is eager-loading used?
This is not a templating issue