#lazy_builder (not to be confused with lazy load) in Drupal 8/9

Continuing to study Drupal, we came across a very interesting technology that is built into it. And which, in our opinion, is used unreasonably little. And completely in vain. Because the approach that this technology uses makes it possible to instantly give a highly loaded (or just a long-forming) page to a user, and then "give" him data that takes a lot of time to form. And while studying this technology, we were faced with the fact that there is not a single simple explanation of what it is and how to start it. No, there are explanations. There are no simple ones. Now we will try to make up for this trouble.



general description



So, we have a page that, for some reason, takes a long time to form part of the data. The reasons can be different - a large amount of calculations, a large amount of data, long requests to some slow database, or in general it is necessary to go to a third-party service from which to get information, which then also needs to be processed. The reasons are not important. It is important that our page contains data that we can send right away - headers, footer, some pictures, a bunch of framing, text, advertising, in the end. And there is data that we need to "get", and it will take a certain amount of time.



So that's it. Usually this task is solved through the mechanism of "lazy loading" - a light version of the page is loaded, and then the lazy loading script is triggered, which, using JavaScript, goes to the backend, takes the data from there and puts it in the right places. But lazy loading has a ton of downsides. Starting with the fact that if, for example, our data is given only to an authorized user, then we need to additionally authorize this lazy script. Also, we always need JavaScript enabled. This "lazy thing" is not very friendly with search engines. And so on.



And the creators of Drupal, it turns out, are great. And they offer us another mechanism, which is devoid of almost all the disadvantages of lazy loading. And this mechanism is called "lazy builder" - lazy builder. It works like everything ingenious - very simple.

In the place in the twig-template where we need to display "heavy" data, we put an ordinary (almost) variable, in a completely normal way, like this: {{lazy_data}}. But in the preprocessor in which we prepare this variable, we must say magic words to it so that it becomes a lazy builder. It looks like this:



$variables['lazy_data'] = [
  '#create_placeholder' => TRUE, // -  ,  Drupal   .
  '#lazy_builder' => [ // -     , -   .
    //...    
    ],
  ],
];
      
      





And now Drupal, when it will render the page, will replace this variable with a JavaScript placeholder, and the data itself will not be generated at the time of rendering. That is, this page will be formed quickly, and will be given to the user just as quickly. And only then, when it is shown by the browser on the screen, this placeholder will trigger, which will climb to the backend and tell it - "I'm ready, send the data." The backend will calmly form and give this data. And they will be inserted where they should be.



That's all! And no additional authorization is needed - it has already been done on the backend. And you don't need to include any additional scripts - Drupal will take care of everything. And you don't need any additional entry point APIs that need to be additionally written and maintained. There is no need to clarify what kind of data you need - all this has already been done on the backend. We just put off a piece of "page building" for later. That's all we did.



And the most ingenious thing here is that if the user does not have JavaScript enabled, then Drupal itself recognizes this and generates this heavy data immediately, without using a placeholder. That is, as if there was no mechanism for delayed construction. Search bots will be happy that they don't have to deal with self-written lazy loads, they will get a regular page. But to wait a few seconds this page is not as critical for them as it is for a person.



And now, some technical details of how all of this fly do



Let's repeat - in the twig-template we write as usual - we just put the variable in the place we need. And that's it, you don't need to take any more gestures.

In the template preprocessor, in which we need to form this variable, we write "magic words" so that it becomes "lazy" and write what it should call to lazy render our variable:



$variables['lazy_data'] = [
  '#create_placeholder' => TRUE, // -  ,  Drupal   .
  '#lazy_builder' => [ // -   , -   .
    '_.lazy_renderer:renderBigData', [ // -   ,   . ,    .
      'info' => ' ', // -   ,     . . 
      'params' => ['foo' => 'boo'],
        'something_else' => 11
    ],
  ],
];
      
      





Now we need to make a Drupal "service" that will be engaged in the formation of our big data. To do this, in the file module_name.service.yml, which lies at the root of the required module (not necessarily self-written), we must declare this service (module_name.lazy_renderer), which will be called to form what needs to be output to the 'lazy_data' variable, which then it will go to that stub , to the house that Jack built .



In this service, we make the renderBigData function, which will be called. And this function should return a link to the template, which will be rendered and inserted in the right place on the page in the house that Jack built .



But you want to pass something to this function, right? Here's how to do it.



First, we remind you that in order to sell something unnecessary, you must first buy something unnecessary, and in order to use a template for rendering, you must first declare it. That is, in the file module_name.module, in the function promotion_theme (...) function, you need to return, along with the rest of the templates, the template for the new template:



'my_template_for_lazy_building' => [
  'variables' => [
    'info' => '',
    'params' => [],
    'something_else' => 1
  ],
],
      
      





And then everything is simple - in the service, in the function, everything that is needed is prepared, and this freshly declared template is returned to the render, passing it what you need to transfer to it.



And this template, in turn, has its own preprocessor, which will be triggered when Drupal tries to render the template. At this point, the preprocessor will receive those variables that are declared and passed.



That is, technically it looks like this:



//        :
// '_.lazy_renderer:renderBigData'
//   :

class lazy_renderer {
        public function renderBigData($info, $params, $something_else) {
        //    
    //-  ,  .
    return [
        '#theme' => 'my_template_for_lazy_building',
      '#info' => $info,
      '#params' => $params,
      '#something_else' => $something_else
    ];
  }
}
      
      





The twig template itself must be in the module's template directory, of course.



That's all.



And again, to sum up "who stood on whom":



  • We have a lazy_data variable. We put it in the twig-template of some page as a simple variable.
  • We form it in the preprocessor. And we tell her that she is "lazy" and that she should call the service ('module_name.lazy_renderer: renderBigData'), which will return the template (another, 'my_template_for_lazy_building') to render. This template will be rendered and inserted in place of 'lazy data'.
  • Do not forget to declare our template.


We hope that we were able to tell you about the Lazy Builder technology in a simple, but at the same time as detailed as possible.



Thanks for attention.



All Articles