【问题标题】:Can I use Mojolicious to build a static site?我可以使用 Mojolicious 构建静态站点吗?
【发布时间】:2018-03-12 08:24:53
【问题描述】:

是否可以使用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'; 一切都很好,但能够重用 sn-ps 和布局是重点。

知道我可以使用 Template Toolkit 或其他一些模板系统,但我想尽可能避免使用多个系统的认知摩擦。

我也知道我可以启动 mojolicious 作为服务器并获取所有页面,但这似乎有点过头了。

这里有什么帮助吗?

【问题讨论】:

    标签: perl mojolicious


    【解决方案1】:

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

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

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

    以下是模板的编译方式:

    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 };
        };
    },
    

    外层sub仅用于关闭$stash_ref,在上面的模板编译时执行。

    为了呈现模板,我们提供临时存储值,然后处理 Mojo::Template。如果 stash 包含布局参数,我们会递归以当前模板的输出作为内容来渲染布局模板:

    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 的所有其余部分(尤其是控制器,它们对于静态站点毫无意义)就可以工作。一段时间后,我切换到了一个不同的模板引擎,它支持开箱即用的模板继承,没有如此广泛的解决方法。

    【讨论】:

    • 感谢@amon 的回答,我想出了一个有点复杂的方法来处理这个问题 - 请参阅下面的回答。我显然接受了居屋的回答,没有它我就不会明白。
    【解决方案2】:

    添加另一种(最小)方式来做到这一点:

    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
    

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

    【讨论】:

      【解决方案3】:

      如果您通过 Plack 运行您的 Mojo 应用程序,那么您可以使用 https://metacpan.org/pod/wallflower 从您的应用程序创建一个静态站点。

      【讨论】:

        猜你喜欢
        • 2016-10-13
        • 2022-11-03
        • 2019-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-26
        • 2021-02-17
        • 1970-01-01
        相关资源
        最近更新 更多