Могу ли я использовать Mojolicious для создания статического сайта?

Можно ли использовать систему шаблонов Mojolicious для создания статического веб-сайта?

Я пытаюсь использовать (каркасный) скрипт следующим образом:

use Mojo::Template;
use Mojolicious::Plugin::DefaultHelpers;
use Mojolicious::Plugin::TagHelpers;

my $mt = Mojo::Template->new;
print $mt->render_file('index.html.ep');

Где index.html.ep выглядит так:

% layout 'default';
This is a foo

Однако я получаю сообщение об ошибке:

String found where operator expected at index.html.ep line 1, near "layout 'default'"
    (Do you need to predeclare layout?)
syntax error at index.html.ep line 1, near "layout 'default'"
1: % layout 'default';
2: This is a foo

Очевидно, что если я пропущу % layout 'default';, все будет хорошо, но возможность повторного использования фрагментов и макета — это все.

Я знаю, что мог бы использовать Template Toolkit или какую-либо другую систему шаблонов, но я хочу по возможности избежать когнитивного трения, связанного с использованием нескольких систем.

Я также знаю, что мог бы запустить mojolicious как сервер и получить все страницы, но это кажется излишним.

Любая помощь здесь?


person simone    schedule 12.03.2018    source источник


Ответы (3)


Вы можете использовать шаблоны Mojo вне веб-фреймворка Mojolicious — я делал это для рендеринга статических страниц для своего блога. Однако по умолчанию Mojo::Template не поставляется с обычными помощниками. Вместо этого остальная часть Mojolicous внедряет переменные и помощники в шаблон.

Для своего блога я решил реализовать собственную вспомогательную систему. Я опишу свое решение в остальной части этого ответа. Mojo, возможно, изменился за это время и может предпочесть какое-то другое решение.

Я смоделировал шаблон как пару ссылки stash и объекта Mojo::Template. Каждый шаблон компилируется в отдельный пакет. Позже мы можем ввести временные значения в ссылку на тайник и передать значения наружу. Помощник — это закрытие определенной ссылки на тайник, поэтому он может получить доступ к этим значениям без использования явного параметра.

Вот как компилируются шаблоны:

package AMON::Blog::TemplateCollection;

sub add_template($self, $name, $source) {
    state $namespace_id = 0;
    my $namespace = Package::Stash->new(
        __PACKAGE__ . '::Namespace::' . ++$namespace_id);

    my $template = Mojo::Template->new(
        name => $name,
        namespace => $namespace->name,
        auto_escape => 1,
        tag_start => '{{',
        tag_end => '}}',
    );

    # enter the helpers into the namespace
    my $stash_ref = \{};
    while (my ($name, $code) = each %{ $self->helpers }) {
        $namespace->add_symbol('&' . $name => $code->($stash_ref));
    }

    $template->parse($source);

    $self->templates->{$name} = {
        stash_ref => $stash_ref,
        template => $template
    };

    return;
}

Вот помощник layout, который записывает запрошенный макет в переменную stash:

layout => sub ($stash_ref) {
    return sub ($name, %args) {
        if (my $existing = $$stash_ref->{layout}) {
            croak sprintf q(Can't change layout from "%s" to "%s"), $existing->{name}, $name;
        }
        $$stash_ref->{layout} = { name => $name, args => \%args };
    };
},

Внешняя подпрограмма используется только для закрытия $stash_ref и выполняется во время компиляции шаблона выше.

Чтобы отобразить шаблон, мы предоставляем временные значения тайника, а затем обрабатываем Mojo::Template. Если тайник содержит аргумент макета, мы рекурсивно отображаем шаблон макета с выводом текущего шаблона в качестве содержимого:

sub render($self, $name, %args) {
    my $template = $self->templates->{$name}
        // croak qq(Unknown template "$name");

    my ($stash_ref, $template_object) = @$template{qw/stash_ref template/};

    $$stash_ref = {
        name => $name,
        layout => undef,
        args => \%args,
    };

    my $result = $template_object->process();

    my $layout_args = $$stash_ref->{layout};
    $$stash_ref = undef;

    if (blessed $result and $result->isa('Mojo::Exception')) {
        die $result;
    }

    if ($layout_args) {
        my $name = $layout_args->{name};
        my $args = $layout_args->{args};
        return $self->render($name, %$args, content => $result);
    }

    return $result;
}

Этот подход не слишком элегантен, но он работает без использования всего остального Mojolicious (особенно контроллеров, которые бессмысленны для статического сайта). Некоторое время спустя я переключился на другой механизм шаблонов, который поддерживает наследование шаблонов из коробки, без таких сложных обходных путей.

person amon    schedule 12.03.2018
comment
Благодаря ответу @amon я придумал несколько запутанный способ решения проблемы - см. мой ответ ниже. Я, очевидно, принял этот ответ, без которого я бы не понял. - person simone; 12.03.2018

Добавление еще одного (минимального) способа сделать это:

use Mojolicious;

my $m = Mojolicious->new->log(Mojo::Log->new);
my $r = $m->renderer;

push @{$r->paths}, './templates';

my $c = Mojolicious::Controller->new->app($m);

my ($output, $format) = $r->render($c, { template => 'index' });
print $output

Повторение этого через несколько шаблонов и отправка вывода в файлы с соответствующими именами должны быть простыми.

person simone    schedule 12.03.2018

Если вы запускаете приложение Mojo через Plack, вы можете использовать https://metacpan.org/pod/wallflower для создания статического сайта из вашего приложения.

person oalders    schedule 12.03.2018