如何修复 Jekyll 导航模板中的 "StackLevelError (Stack Overflow)"

How to fix "StackLevelError (Stack Overflow)" in Jekyll navigation template

我正在尝试编写递归 Jekyll 导航模板(包括),如“Nested tree navigation with recursion". I have a minimal example committed in jekyll-min 中所述,它基本上具有:

我正在使用 Ruby v2.7.0 和 Jekyll v3.8.5。

# docs structure

_docs
|
|_a/
| |_index.md
|
|_b/
  |_index.md
  |
  |_1/
    |_index.md  
# _data/docs-nav.yml

- title: a
  docs:
    - link: /a/
- title: b
  docs:
    - link: /b/
    - title: 1
      docs:
        - link: /b/1/
# _includes/nav.html

{% assign section=include.nav %}
<div class="ui accordion">
    <div class="title active">
        <i class="dropdown icon"></i>
        {{ section.title }}
    </div>
    <div class="content active">
        <div class="ui vertical text menu">
            {% for item in section.docs %}
            {% if item.link %}
            {%- assign p = site.documents | where: "url", item.link | first %}
            <a {%- if page.url== p.url %} class="current item" {% endif %} class="item" href="{{ p.url }}">
                {{ p.menu_name | default: p.title }}
            </a>
            {% endif %}
            {% if item.docs %}
            {% include nav.html nav=item %}
            {% endif %}
            {% endfor %}
        </div>
    </div>
</div>
# _includes/docs_contents.html

<div class="unit one-fifth hide-on-mobiles">
    <aside>
        {% for section in site.data.docs_nav %}
        {% include nav.html nav=section %}
        {% endfor %}
    </aside>
</div>
# _layouts/doc.html

---
title: Docs
description: version 1.0
---

<html>
<body>
{% include docs_contents.html %}
{{ content }}
</body>
</html>

据我了解,对于每个页面,导航模板呈现应该像这样工作:

  1. _layouts/doc.html
  2. _includes/docs_contents.html:迭代根级条目,为每个
  3. 调用_nav
  4. _nav(/a/ entry):渲染标题,迭代docs,渲染/a/link,然后退出
  5. _nav(/b/ entry):渲染标题,迭代docs,渲染/b/link,然后调用_nav(/b/1/ entry)
  6. _nav(/b/1/ entry):渲染标题,迭代docs,渲染/b/1/link,然后退出
  7. _nav(/b/ entry)(已经在堆栈中):退出
  8. _includes/docs_contents.html: 退出

但是,当我执行 bundle exec jekyll build 时,我得到:

  Liquid Exception: Liquid error (/mnt/e/ThirdParty/jekyll-min/_includes/docs_contents.html line 17): 
Nesting too deep included in /_layouts/doc.html
jekyll 3.8.5 | Error:  Liquid error (/mnt/e/ThirdParty/jekyll-min/_includes/docs_contents.html line 17): 
Nesting too deep included
Traceback (most recent call last):

[...]

我的内容或递归模板有什么问题?我已经为此苦苦挣扎了几个小时,但没有运气。

JEKYLL_LOG_LEVEL=debug

没有产生任何额外的有用信息。

实际文档结构更复杂,可以任意深入,因此编写 non-recursive 模板来手动处理嵌套级别可能不是一种选择。

问得好。

{{ myvar | inspect }} 和限制递归的标志的帮助下,我已经成功调试了您的代码并理解了为什么会出现这种无限递归。

这是因为 docs_contents.html 中的 section 变量是在 for 循环中赋值的 freezed : 无法更改。

你第一次包含 nav.html 时,{% assign section=include.nav %} 没有改变 section,你的代码只使用你的 for 循环.

当您第二次递归并调用 nav.html 时,它将使用相同的冻结全局 section 变量并无限递归。

解决方案是将 nav.html 中的变量名称从 section 更改为其他名称。例如:sub_section,它会起作用,因为这个新变量不会被冻结,并且可以在递归期间根据需要重新分配。

{% assign sub_section=include.nav %}
{{ sub_section.title }}
{% for item in sub_section.docs %}
...

如果你想试验这里是我的测试代码和一些评论:

docs_contents.html

{% for section in site.data.docs_nav %}

{% comment %} ++++ Try to reassign "section" ++++ {% endcomment %}
{% assign section = "yolo from docs_contents.html" %}

{% assign recursion = 0 %}
<pre>
&gt;&gt; docs_contents.html
++++ "recursion" var is assigned and becomes global
recursion : {{ recursion | inspect }}
++++ "section" is freezed to loop value ++++
including nav with include nav.html nav=section &gt;&gt; {{ section | inspect }}
</pre>

{% include nav.html nav=section %}
{% endfor %}

nav.html

{% comment %} ++++ Try to reassign "section" ++++ {% endcomment %}
{% assign section = "yolo from nav.html" %}

<pre>
    &gt;&gt; nav.hml
    recursion : {{ recursion }}
    include.nav : {{ include.nav | inspect }}
    ++++ "section" is freezed to loop value ++++
    section : {{ section | inspect }}
</pre>

{% comment %} ++++ useless assignement ++++ {% endcomment %}
{% assign section=include.nav %}

{% for item in section.docs %}
  {% if item.link %}
    {%- assign p = site.documents | where: "url", item.link | first %}
    <a {%- if page.url== p.url %} class="current item" {% endif %} class="item" href="{{ p.url }}">
    {{ p.menu_name | default: p.title }}
    </a>
  {% endif %}

  {% comment %}++++ limiting recursion to 2 levels ++++{% endcomment %}
  {% if item.docs and recursion < 2 %}
    {% comment %}++++ incrementing "recursion" global variable ++++{% endcomment %}
    {% assign recursion = recursion | plus: 1 %}
    {% include nav.html nav=item %}
  {% endif %}

{% endfor %}