11ty / eleventy-plugin-webc

Adds support for WebC *.webc files to Eleventy
https://www.11ty.dev/docs/languages/webc/
120 stars 10 forks source link

Cannot access data with the same name as a filter in webc (+ workaround) #97

Open fg23 opened 8 months ago

fg23 commented 8 months ago

What is the problem

When :

=> we cannot access the data value directly in webc.

Note : This works as expected in njk files.

I have investigated in the source code and found a work around that seems fine but not documented anywhere. Maybe the fix to this problem is to simply document it somewhere but why it happens it also interesting.

PS: English not my native langage :sweat_smile:, sorry for the mistakes i make.

TL;DR :

In njk the syntax is unambiguous eleventyNavigation is clearly a data while here collections.all | eleventyNavigation it is cleary a filter function. In webc the syntax is eleventyNavigation for the data and eleventyNavigation(collections.all) and it it resolve via a node vm. This is ambiguous because in both case this is considered the same identifier. In the context given to the vm eleventyNavigation filter function have overridden the data from cascade so it always resolve to the filter.

Workaround: Inspecting the context we can see that it has a $data property with the data not overridden. We can use $data.eleventyNavigation instead of eleventyNavigation when we want to access eleventyNavigation data.

Contexte : what is not working

For context, I was trying to debug eleventyNavigation value for a page, I was succeeding reading it in a njk template but when converting it to webc it was not working anymore.

In njk the following was working :

<pre><code>{{ eleventyNavigation | dump(2) | safe }}</code></pre>

but translating it to webc was not working (with a custom dump filter since it does not exist by default in webc) :

<pre><code @raw="dump(eleventyNavigation, 2)"></code></pre>

This is because eleventyNavigation can be resolved to the data from the cascade or the filter with the same name. In njk it is able to make the difference while in webc it is not. This is because in webc expression are resolved using a node vm and a context object. Context is a proxy object that proxy to the data cascade. However in the data cascade filters overrides data with the same name.

That said, I've found that a copy of the data is kept in a $data property of the data object before filters and other things are applied. So we can work around this using this non standard, non documented $data property, like this :

<pre><code @raw="dump($data.eleventyNavigation, 2)"></code></pre>

Resolving this ?

I was not able to find a way to get the same behavior as in the njk files due to the vm proxy usage. Maybe documenting and making the $data property part of the public spec is a correct way of addressing this issue but I don't know the implications.

Reproduce to test

Let me give you a simple project to reproduce and test this : i will use the @11ty/eleventy-navigation example since that is how I found the problem.

So first step is to init project :

npm init -y
npm install @11ty/eleventy @11ty/eleventy-plugin-webc @11ty/eleventy-navigation --save-dev

Here is a config with a dump filter (~same as default nunjucks "dump" filter because it does not exist for webc) :

const eleventyNavigationPlugin = require("@11ty/eleventy-navigation");
const pluginWebc = require("@11ty/eleventy-plugin-webc");

module.exports = function (eleventyConfig) {
    eleventyConfig.addPlugin(eleventyNavigationPlugin);
    eleventyConfig.addPlugin(pluginWebc, {
        components: ["./_includes/components/*.webc"],
    });

    eleventyConfig.addFilter("dump", function (obj, space) {
        return JSON.stringify(obj, null, space) || "undefined";
    });

    return {
        templateFormats: ["html", "webc", "njk"]
    };
};

Create a page those pages:

index.njk : ```html --- tags: ["tag1", "tag2"] eleventyNavigation: key: njk --- Document {{ collections.all | eleventyNavigation | eleventyNavigationToHtml | safe }}

NKJ

{{ tags | dump | safe }}

{{ eleventyNavigation | dump(2) | safe }}

```
webc.webc : ```html --- tags: ["tag1", "tag2"] eleventyNavigation: key: webc --- Document

WEBC



```
webc_fix.webc : ```html --- tags: ["tag1", "tag2"] eleventyNavigation: key: webc --- Document

WEBC



```

Start the project :

npx @11ty/eleventy --serve