Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to postpone <head> rendering?

I have the layout like this:

@@ layouts/v2.html.ep
<html lang="en">
  <head>
    %= content_for 'stylesheets'
  </head>
<body>
  %= include 'layouts/v2/header'
  <main class="main">
    %= include 'layouts/v2/menu'
    <div class="content">
    %= content
    </div>
  </main>
</body>
</html>


@@ layouts/v2/menu
% content_for stylesheets => begin
  %= stylesheet 'v2/css/menu.css'
% end
<aside class="menu">
  ...
</aside>

@@ layouts/v2/header
% content_for stylesheets => begin
  %= stylesheet 'v2/css/header.css'
% end
<header class="header">
  ...
</header>

Here when templates are included I include their style sheets. Notice this in template:

% content_for stylesheets => begin
  %= stylesheet 'v2/css/menu.css'
% end

But this is too late to do that, because the <head> is already rendered.

As workaround this problem I can move %= content_for 'stylesheets' from <head> to the bottom of page. But I want style sheets are loaded first.

Is there any way to postpone rendering for the content of 'stylesheets' block until whole page is rendered?

UPD

Thank to @amon about that Mojolicous layouts are rendered inside out. I understand the problem and there for templates included from first layout I include stylesheets manually:

@@ layouts/v2.html.ep
<html lang="en">
  <head>
    %= stylesheet 'v2/css/header.css'
    %= stylesheet 'v2/css/menu.css'
    %= content_for 'stylesheets'
  </head>
<body>
  %= include 'layouts/v2/header'
  <main class="main">
    %= include 'layouts/v2/menu'
    <div class="content">
    %= content
    </div>
  </main>
</body>
</html>

So in any rendered/included template (except layout) next works fine:

@@ some/template
% content_for stylesheets => begin
  %= stylesheet 'some/template.css'
% end
template content
like image 252
Eugen Konkov Avatar asked Aug 14 '26 02:08

Eugen Konkov


1 Answers

Mojolicous layouts are rendered inside-out, and you can nest arbitrarily many layouts.

Create a template that includes just the outermost document content and other HTML boilerplate, with a placeholder for the content of <body>

<html lang="en">
  <head>
    %= content_for 'stylesheets'
  </head>
  <body>
    %= content
  </body>
</html>

Then you can use that template as the layout for the body of your HTML page. I.e., use the layout helper like this:

% layout 'outermost_layout';
%= include 'layouts/v2/header'
<main class="main">
  %= include 'layouts/v2/menu'
  <div class="content">
  %= content
  </div>
</main>

After rendering the template, Mojolicious will check whether you specified a layout and then render it, using the output from this template as the outer layout's content. So because the innermost layout is rendered first, data can flow from your templates through the stash to wrapping layouts.

like image 75
amon Avatar answered Aug 20 '26 02:08

amon



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!