11ty / webc

Single File Web Components
MIT License
1.3k stars 36 forks source link

Scoped Webc Functions Lose Correct Page Context #174

Open CanIGetaPR opened 1 year ago

CanIGetaPR commented 1 year ago

I'm currently debugging an issue with webc where my footer thinks every page it's on is the about page. Diving in deeper reveals the page is being incorrectly set to a reference of the first page that was processed by 11ty.

Here are two debugging screenshots showing the page context being lost and ultimately set to the about page. This is paused on the scoped function call and analyzing the page reference along the stack.

image

image

There is an issue about this posted in the webc plugin: https://github.com/11ty/eleventy-plugin-webc/issues/69

CanIGetaPR commented 1 year ago

Seems to be a bug in fasterVmContext.js

CanIGetaPR commented 1 year ago

fasterVmContext is working as it needs to be.

A further look shows that the data proxy only gets accessed in the vm to fetch context for the code written inside the page markup, for example:

<title @html="page.url"></title>

If I understand correctly, the functions defined in webc:setup script elements are created once and their context is never updated, causing the stale data issue.

The screenshot below shows the difference between the context within a function defined in webc:setup and a page reference passed as a parameter:

<script webc:setup>
function getTitle(pageRef) { 
   let pageRefX = pageRef;
}
</script>

<title @html="getTitle(page)"></title>

image

CanIGetaPR commented 1 year ago

This is further verified by expanding the getTitle() function in newData (which has the updated page context and being passed to the vm script context), contains a stale scope which still has the page as index.webc

image

CanIGetaPR commented 1 year ago

Just a note of clarification, the page chosen as the stale data varies from run to run, and in the above two screenshots the stale page is index.webc, where as the code has moved on to building about.webc. This is unlike the first two screenshots in the issue which were from a different run and the stale page context was about.webc.

CanIGetaPR commented 1 year ago

According to https://github.com/11ty/webc/blob/09689c42624ef49380254791d2a4d0e9a82e48a5/src/componentManager.js#L28 this is intended behaviour, however, the comment states:

"this has no attributes or context sensitive things, only global helpers and global data"

Which is incorrect because several context sensitive things such as page are made available, giving the idea that this data is usable.

CanIGetaPR commented 1 year ago

I found a simple work-around,

https://github.com/11ty/webc/blob/09689c42624ef49380254791d2a4d0e9a82e48a5/webc.js#L225

By changing this line from ast.setComponentManager(this.globalComponentManager); to ast.setComponentManager(new ComponentManager());, each page gets its own component manager which means web components will have the correct page context as they are rebuilt and their setup scripts are assigned the corresponding page context.

CanIGetaPR commented 1 year ago

Also, at some point down the line, this might be useful, unless you want to just share the vm context across all rendering.

let scriptContextKey = data.page?.inputPath ?? options.closestParentComponent;
        let { returns } = await ModuleScript.evaluateScriptInline(attrContent, data, `Check the dynamic attribute: \`${name}="${attrContent}"\`.`, scriptContextKey);

At https://github.com/11ty/webc/blob/09689c42624ef49380254791d2a4d0e9a82e48a5/src/ast.js#L787 and other relevant areas.