我可以使用 Mojolicious 构建静态站点吗? [英] Can I use Mojolicious to build a static site?

查看:43
本文介绍了我可以使用 Mojolicious 构建静态站点吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is it possible to use the Mojolicious template system to build a static website?

我正在尝试使用这样的(骨架)脚本:

I'm trying to use a (skeleton) script like this:

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

但是我收到一个错误消息:

However I get an error 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'; 一切都很好,但能够重用片段和布局才是重点.

Obviously, if I omit % layout 'default'; all is good, but being able to reuse snippets and layout is the whole point.

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

I know I could use Template Toolkit or some other templating system, but I want to avoid the cognitive friction of using multiple systems if at possible.

我也知道我可以将 mojolicious 作为服务器启动并获取所有页面,但这似乎有点矫枉过正.

I'm also aware that I could start up mojolicious as a server and wget all the pages, but it seems overkill.

这里有什么帮助吗?

推荐答案

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

You can use Mojo templates outside of the Mojolicious web framework – I used to do that to render static pages for my blog. However, the Mojo::Template does not come with the normal helpers by default. Instead, the rest of Mojolicous injects variables and helpers into the template.

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

For my blog, I decided to implement my own helper system. I'll describe my solution in the rest of this answer. Mojo may have changed in the meantime, and may prefer some different solution.

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

I modelled a template as a pair of a stash reference and the Mojo::Template object. Each Template is compiled into its own package. Later, we can inject temporary values into the stash reference and communicate values to the outside. A helper is a closure of a specific stash ref, so it can access these values without using an explicit parameter.

以下是模板的编译方式:

Here's how templates are compiled:

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 帮助器,它将请求的布局写入存储变量:

Here is a layout helper that writes the requested layout into a stash variable:

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

outer sub 仅用于关闭$stash_ref,并在上面的模板编译期间执行.

The outer sub is only used to close over the $stash_ref, and is executed during template compilation above.

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

To render the template, we supply temporary stash values, then process the Mojo::Template. If the stash contains a layout argument, we recurse to render the layout template with the current template's output as content:

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

This approach is not terribly elegant, but it works without having to pull in all the rest of Mojolicious (particularly controllers, which are pointless for a static site). Some time later I switched to a different template engine that supports template inheritance out of the box, without such extensive workarounds.

这篇关于我可以使用 Mojolicious 构建静态站点吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆