Perl 我可以使用Mojolicious来构建静态站点吗?

Perl 我可以使用Mojolicious来构建静态站点吗?,perl,mojolicious,Perl,Mojolicious,是否可以使用Mojolicous模板系统来构建静态网站 我正在尝试使用如下(骨架)脚本: use Mojo::Template; use Mojolicious::Plugin::DefaultHelpers; use Mojolicious::Plugin::TagHelpers; my $mt = Mojo::Template->new; print $mt->render_file('index.html.ep'); % layout 'default'; This is

是否可以使用Mojolicous模板系统来构建静态网站

我正在尝试使用如下(骨架)脚本:

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

my $mt = Mojo::Template->new;
print $mt->render_file('index.html.ep');
% layout 'default';
This is a foo
其中
index.html.ep
如下所示:

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

my $mt = Mojo::Template->new;
print $mt->render_file('index.html.ep');
% layout 'default';
This is a foo
但是,我在nessage中遇到一个错误:

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'一切都很好,但能够重用代码片段和布局才是关键

我知道我可以使用模板工具包或其他模板系统,但我希望尽可能避免使用多个系统的认知摩擦

我也知道我可以启动mojolicious作为一个服务器,并下载所有页面,但这似乎有些过头了


这里有什么帮助吗?

您可以在Mojolicious web框架之外使用Mojo模板——我过去常常这样做来为我的博客呈现静态页面。但是,默认情况下,
Mojo::Template
不附带普通助手。相反,Mojolicous的其余部分将变量和助手注入到模板中

对于我的博客,我决定实现我自己的助手系统。我将在这个答案的其余部分描述我的解决方案。Mojo可能在这段时间发生了变化,可能更喜欢一些不同的解决方案

我将模板建模为一对隐藏引用和Mojo::template对象。每个模板都编译到自己的包中。稍后,我们可以将临时值注入到stash引用中,并将值传递给外部。helper是特定stash ref的闭包,因此它可以在不使用显式参数的情况下访问这些值

以下是模板的编译方式:

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
帮助程序,它将请求的布局写入一个隐藏变量:

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(特别是控制器,对于静态站点来说毫无意义)。一段时间后,我切换到另一个模板引擎,该引擎支持开箱即用的模板继承,而无需如此广泛的解决方法。

添加了另一种(最小)方法:

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

通过多个模板进行迭代,并将输出发送到适当命名的文件应该很简单

如果你通过
Plack
运行你的Mojo应用程序,那么你可以使用它从你的应用程序中创建一个静态站点。

多亏了@amon answer,我想出了一个有点复杂的方法来处理这个问题-见下面我的答案。显然,我接受了霍斯的回答,没有这个答案我是不会明白的。