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

空扰寡人 提交于 2020-05-15 08:12:03

问题


I am trying to write a recursive Jekyll navigation template (include) as described in "Nested tree navigation with recursion". I have a minimal example committed in jekyll-min, which basically has:

  • two top-level dirs, each with one page
  • another dir under the second top-level dir, containing one page
  • a navigation template (_includes/docs_contents.html) that loops through the top-level dirs and initiates recursive traversal for each
  • a recursive include (_includes/nav.html) that accepts a navigation entry, renders its title and child links, and invokes itself recursively for any dirs in its children list
  • a layout (_layouts/doc.html) that renders the navigation pane and content for each page

I'm using Ruby v2.7.0 and 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>

As far as I understand, for each page the navigation template render should work like this:

  1. _layouts/doc.html
  2. _includes/docs_contents.html: iterate root level entries, calling _nav for each
  3. _nav(/a/ entry): render title, iterate docs, render /a/ link, and quit
  4. _nav(/b/ entry): render title, iterate docs, render /b/ link, and then call _nav(/b/1/ entry)
  5. _nav(/b/1/ entry): render title, iterate docs, render /b/1/ link, and quit
  6. _nav(/b/ entry) (already in stack): quit
  7. _includes/docs_contents.html: quit

However, when I perform a bundle exec jekyll build I get:

  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):

[...]

What is the problem with my content or the recursive template? I have been struggling with this for hours with no luck.

JEKYLL_LOG_LEVEL=debug

didn't produce any additional useful info.

The actual document structure is more complex and could go arbitrarily deep, so writing a non-recursive template to manually handle nested levels may not be an option.


回答1:


Excellent question.

With help of {{ myvar | inspect }} and a flag limiting recursion, I've successfully debugged your code and understood why this infinite recursion occurs.

It comes from the fact that the section variable in docs_contents.html is assigned by in a for loop and freezed : it cannot be changed.

The first time you include nav.html, {% assign section=include.nav %} is not changing section and your code just use the one assigned in your for loop.

When you recurse and call nav.html a second time it will use the same freezed global section variable and recurse indefinitely.

The solution is to change your variable name in nav.html from section to something else. eg: sub_section, and it will work, because this new variable will not be freezed and can be reassigned as needed during recursion.

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

If you want to experiment here is my test code with some comments :

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 %}


来源:https://stackoverflow.com/questions/60923504/how-to-fix-stacklevelerror-stack-overflow-in-jekyll-navigation-template

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!