11ty / eleventy

A simpler site generator. Transforms a directory of templates (of varying types) into HTML.
https://www.11ty.dev/
MIT License
17.18k stars 494 forks source link

global data is not passed to liquidjs as globals #1541

Open binyamin opened 3 years ago

binyamin commented 3 years ago

Describe the bug With {% render layout.html %}, you can only access a variable if it's defined in the included template/partial or passed down to liquid via liquidOptions.globals. 11ty refers to "global data", which is undefined within such partials.

To Reproduce See example repo If you don't feel like running the example repo:

  1. In a new 11ty project, reference a global data key from within an include/partial.
  2. In a markdown file, {% render %} the include/partial.
  3. Run npx eleventy

Expected behavior I expect that data which is the same for every page (eg. pkg, _data/**/*) is passed down to liquid, whereas local variables are not.

Environment:

Additional context Related: https://github.com/harttle/liquidjs/issues/185

KittyGiraudel commented 3 years ago

I’m not a Liquid expert, so don’t quote me on this, but I believe this is intended. The documentation on render states:

When a snippet is rendered, the code inside it does not automatically have access to the variables assigned using variable tags within the snippet's parent template. Similarly, variables assigned within the snippet can't be accessed by the code outside of the snippet. This encapsulation increases performance and helps make theme code easier to understand and maintain.

My understanding of this is that by definition, render does not pass through its current scope to the partial (which is overall a good thing, as they explain). Any variable that requires reading needs to be passed as an argument to the render call. In your case:

{% render "foo.html", bar: bar %}

Edit: If you would like to circumvent that issue, I believe you could use the deprecated include tag which does share scopes between the parent and the child templates. The 11ty docs use include everywhere by the way.

binyamin commented 3 years ago

@HugoGiraudel thanks, I've seen that in the docs. I guess this is really a question of whether eleventy's global data should be passed down as liquidjs's global data.

sentience commented 1 year ago

Per the LiquidJS docs on passing variables to rendered partials,

globals don’t need to be passed down. They are accessible from all files.

I believe this issue as @binyamin originally posted is valid: Eleventy globals (like collections) should be provided to LiquidJS as globals, so they can be accessed in Liquid partials without passing them down.

sentience commented 1 year ago

A practical use case to show why this matters. In my blog post, I want to render a partial that will render an embedded view of an item from my notes collection, given its fileSlug:

{% # some-post.md %}
This is a toot I wrote:

{% render embedded-note fileSlug: 'abc123' %}

Inside embedded-note.liquid, I'd like to find the item and render it:

{% # embedded-note.liquid %}
{% assign note = collections.note | where 'fileSlug', fileSlug | first %}

<div>{{ note.templateContent }}</div>

This will not currently work, because the partial does not have access to the global collections!

Instead, I must currently pass down the collections object:

{% # some-post.md %}
This is a toot I wrote:

{% render embedded-note fileSlug: 'abc123', collections: collections %}

Having to list all the globals your partial uses is tedious and messy. Given that LiquidJS has a supported concept of globals that are accessible to all partials, I think Eleventy should use it.