Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating to 4.1.0 causes build failure #96

Open
uncenter opened this issue Dec 10, 2024 · 12 comments
Open

Updating to 4.1.0 causes build failure #96

uncenter opened this issue Dec 10, 2024 · 12 comments
Assignees
Labels
bug Something isn't working

Comments

@uncenter
Copy link

Steps to reproduce

The build for this dependency update PR on my website is failing: uncenter/uncenter.dev#234.


20:03:44.311 | [11ty] Problem writing Eleventy templates:
-- | --
20:03:44.311 | [11ty] 1. Having trouble rendering vto template ./src/posts/index.vto (via TemplateContentRenderError)
20:03:44.312 | [11ty] 2. [22:13-22:18]: Await is only valid in async functions (via SyntaxError)
20:03:44.312 | [11ty]
20:03:44.312 | [11ty] Original error stack trace: SyntaxError: [22:13-22:18]: Await is only valid in async functions

I can't even see what is async about https://github.com/uncenter/uncenter.dev/blob/main/src/posts/index.vto (which just wraps the https://github.com/uncenter/uncenter.dev/blob/main/src/components/postlist.vto component, which also doesn't appear to be async). Is this an issue with Vento 1.12.12 that was bumped in this update? I don't see anything about it in the upstream issues or release notes for the recent 1.12.13 release.

Expected behavior

Successful build, as it is with v4.0.1.

Actual behavior

Got error as above.

Plugin version

4.1.0

Eleventy version

3.0.0

Reduced Test Case URL

No response

Additional information

No response

@uncenter uncenter added the bug Something isn't working label Dec 10, 2024
@noelforte
Copy link
Owner

Will investigate. Apologies for all the weird errors! Hopefully we'll get to something stable eventually 😅

@uncenter
Copy link
Author

No worries ahah, this plugin is amazing and I am so glad I switched to Vento - happy to help debug whatever and hopefully get other 11ty users to switch over as well :)

@noelforte
Copy link
Owner

noelforte commented Dec 10, 2024

Could you try running your build with the environment variable DEBUG=Eleventy:Vento*? I've got the plugin set up to print the transformed template function just before render, so that might help determine where the error is getting thrown.

You could take the transformed function and use it to trace where [22:13-22:18] is happening

Output should be similar to something like this:

Eleventy:Vento Getting template function for `page.vto` +20ms
Eleventy:Vento:Cache Cache MISS for `page.vto`, compiled new template:
Eleventy:Vento:Cache Use Vento cache: false
Eleventy:Vento:Cache 
Eleventy:Vento:Cache async function (it) {
Eleventy:Vento:Cache         let __pos = 0;
Eleventy:Vento:Cache         try {
Eleventy:Vento:Cache           it = Object.assign({}, __defaults, it);
Eleventy:Vento:Cache           const __exports = { content: "" };
Eleventy:Vento:Cache           __exports.content += "<head>\n\t";
Eleventy:Vento:Cache __pos = 8;
Eleventy:Vento:Cache for (let [name, content] of __env.utils.toIterator(it.meta, true)) {
Eleventy:Vento:Cache   __exports.content += "\n\t\t<meta name=\"";
Eleventy:Vento:Cache   __pos = 54;
Eleventy:Vento:Cache   __exports.content += name ?? "";
Eleventy:Vento:Cache   __exports.content += "\" content=\"";
Eleventy:Vento:Cache   __pos = 75;
Eleventy:Vento:Cache   __exports.content += content ?? "";
Eleventy:Vento:Cache   __exports.content += "\"> \n\t";
Eleventy:Vento:Cache }
Eleventy:Vento:Cache __exports.content += "\n</head>\n\n<body>\n\t";
Eleventy:Vento:Cache __pos = 121;
Eleventy:Vento:Cache {
Eleventy:Vento:Cache   const __result = await __env.utils.eleventyFunctions.shortcodes.testShortcode.call({
Eleventy:Vento:Cache     page: it.page,
Eleventy:Vento:Cache     eleventy: it.eleventy
Eleventy:Vento:Cache   }, "arg1", "arg2");
Eleventy:Vento:Cache   __exports.content += __result;
Eleventy:Vento:Cache }
Eleventy:Vento:Cache __exports.content += "\n\n\t";
Eleventy:Vento:Cache __pos = 158;
Eleventy:Vento:Cache __exports.content += await __env.filters.test.call({
Eleventy:Vento:Cache   data: it,
Eleventy:Vento:Cache   env: __env
Eleventy:Vento:Cache }, "{{ 2 + 2 }}") ?? "";
Eleventy:Vento:Cache __exports.content += "\n</body>\n\n";
Eleventy:Vento:Cache 
Eleventy:Vento:Cache           return __exports;
Eleventy:Vento:Cache         } catch (cause) {
Eleventy:Vento:Cache           const template = __env.cache.get(__file);
Eleventy:Vento:Cache           throw new __err(__file, template?.source, __pos, cause);
Eleventy:Vento:Cache         }
Eleventy:Vento:Cache       } +0ms
Eleventy:Vento:Render Rendering `page.vto` +0ms

@noelforte
Copy link
Owner

noelforte commented Dec 10, 2024

If it helps, I just put 4.1.1-beta.0 (with ventojs v1.12.13) on npm via #97.

I'm not super familiar with Vento's function and exports patterns, but that's definitely something not covered in tests. Probably should add test cases for that. Seems like something regressed between 4.0.1 and 4.1.0 though if things were building fine before. I'm including the diff here for reference.

@uncenter
Copy link
Author

 Eleventy:Vento Getting template function for `src/posts/index.vto` +1ms
  Eleventy:Vento:Cache Cache MISS for `src/posts/index.vto`, compiled new template:
  Eleventy:Vento:Cache Use Vento cache: false
  Eleventy:Vento:Cache
  Eleventy:Vento:Cache async function (it) {
  Eleventy:Vento:Cache         let __pos = 0;
  Eleventy:Vento:Cache         try {
  Eleventy:Vento:Cache           it = Object.assign({}, __defaults, it);
  Eleventy:Vento:Cache           const __exports = { content: "" };
  Eleventy:Vento:Cache           __pos = 0;
  Eleventy:Vento:Cache let {PostList: PostList} = await __env.run("../components/postlist.vto", {
  Eleventy:Vento:Cache   ...it
  Eleventy:Vento:Cache }, __file);
  Eleventy:Vento:Cache __exports.content += "\n\n";
  Eleventy:Vento:Cache __pos = 61;
  Eleventy:Vento:Cache __exports.content += PostList(it.collections.posts.toReversed()) ?? "";
  Eleventy:Vento:Cache __exports.content += "\n";
  Eleventy:Vento:Cache
  Eleventy:Vento:Cache           return __exports;
  Eleventy:Vento:Cache         } catch (cause) {
  Eleventy:Vento:Cache           const template = __env.cache.get(__file);
  Eleventy:Vento:Cache           throw new __err(__file, template?.source, __pos, cause);
  Eleventy:Vento:Cache         }
  Eleventy:Vento:Cache       } +0ms
  Eleventy:Vento:Render Rendering `src/posts/index.vto` +0ms
[11ty] Problem writing Eleventy templates:
[11ty] 1. Having trouble rendering vto template ./src/posts/index.vto (via TemplateContentRenderError)
[11ty] 2. Error in template src/posts/index.vto:1:1
[11ty]
[11ty] <empty file>
[11ty]
[11ty] (via TemplateError) (via TemplateError)

@noelforte
Copy link
Owner

noelforte commented Dec 11, 2024

Thinking out loud:

Given the file is empty, whatever's in ./src/posts/index.vto isn't yielding anything, meaning the error is probably originating from some internal operation. That said this section, seems the most likely.

let { PostList: PostList } = await __env.run("../components/postlist.vto", {
  ...it
}, __file)

This is where this plugin and Vento differ in implementation. This plugin uses Vento's compile() method directly since it allows for Eleventy to handle caching of template functions used directly and can get access to the Template.code and Template.source properties.

However, when Vento runs a template internally, it uses __env.runto load, cache, and execute the template function in one go, which is what's in the docs.

Couple ways we could proceed to identify the cause of the issue:

  1. I think adding test cases for function/export tags in https://github.com/noelforte/eleventy-plugin-vento/tree/main/tests could help rule out issues compiling those tags.
  2. Could also go insert some console.logs into node_modules for the run() method, and/or insert some directly in the generated template function.
  3. Since Vento has the ability to run real JS at runtime via its Function constructor, adding {{ console.log() }} statements in your template might also help nail down where the await in non-async issue is stemming from.

With 4.1.1-beta.0, the changes from ventojs/vento#89 are in there, but as you've already seen, this:

[11ty] Problem writing Eleventy templates:
[11ty] 1. Having trouble rendering vto template ./src/posts/index.vto (via TemplateContentRenderError)
[11ty] 2. Error in template src/posts/index.vto:1:1
[11ty]
[11ty] <empty file>
[11ty]
[11ty] (via TemplateError) (via TemplateError)

is even more vague than this:

20:03:44.311 | [11ty] Problem writing Eleventy templates:
-- | --
20:03:44.311 | [11ty] 1. Having trouble rendering vto template ./src/posts/index.vto (via TemplateContentRenderError)
20:03:44.312 | [11ty] 2. [22:13-22:18]: Await is only valid in async functions (via SyntaxError)

Eleventy doesn't correctly report the entire error chain, including Errors with a cause property attached. Therefore, releasing [email protected] with [email protected] is blocked until 11ty/eleventy#3572 (and possibly 11ty/eleventy#3582) gets resolved.

Think that just about covers everything for now. Unfortunately, I don't have time in the next couple days to work on this but if you want to raise any PRs I can look and review. Otherwise, I'll get back to this when I have a moment.

@noelforte
Copy link
Owner

Oh! One other thing: DEBUG=Eleventy* will log the entire error object which could help trace the error through causes. Might help reveal something.

@noelforte
Copy link
Owner

@uncenter I was able to ID this for you by cloning uncenter.dev and fiddling with the code. That, combined with the changes now in Vento v1.12.13 and Eleventy 4.0.1-alpha.1 yielded this error message:

[11ty] Problem writing Eleventy templates:
[11ty] 1. Having trouble rendering vto template ./src/tags.vto (via TemplateContentRenderError)
[11ty] 2. Error in template src/tags.vto:1:2
[11ty] 
[11ty] <empty file>
[11ty] 
[11ty] (via TemplateError) (via TemplateError)
[11ty] 3. Error in template src/components/postlist.vto:7:92
[11ty] 
[11ty] <h2 class="font-semibold mx-0 my-0 text-xl leading-8" style="view-transition-name: post-{{ post.data.title |> slugify }}">
[11ty] 
[11ty] (via TransformError) (via TemplateError)
[11ty] 4. [meriyah] [22:13-22:18]: Await is only valid in async functions while parsing compiled template function:
[11ty] 
[11ty] 22 __output += (await __env.filters.slugify.call({data:it,env:__env}, post.data.title)) ?? "";
[11ty]              ^ (via TransformError)
[11ty] 
[11ty] Original error stack trace: TransformError: [meriyah] [22:13-22:18]: Await is only valid in async functions while parsing compiled template function:
[11ty] 
[11ty] 22 __output += (await __env.filters.slugify.call({data:it,env:__env}, post.data.title)) ?? "";
[11ty]              ^
[11ty]     at transformTemplateCode (file:///Users/noel/Developer/projects/tools/eleventy-plugin-vento/node_modules/.pnpm/[email protected]/node_modules/ventojs/esm/src/transformer.js:114:15)
[11ty]     at Environment.compile (file:///Users/noel/Developer/projects/tools/eleventy-plugin-vento/node_modules/.pnpm/[email protected]/node_modules/ventojs/esm/src/environment.js:48:24)
[11ty]     at Environment.load (file:///Users/noel/Developer/projects/tools/eleventy-plugin-vento/node_modules/.pnpm/[email protected]/node_modules/ventojs/esm/src/environment.js:99:35)
[11ty]     at async Environment.run (file:///Users/noel/Developer/projects/tools/eleventy-plugin-vento/node_modules/.pnpm/[email protected]/node_modules/ventojs/esm/src/environment.js:19:26)
[11ty]     at async eval (eval at compile (file:///Users/noel/Developer/projects/tools/eleventy-plugin-vento/node_modules/.pnpm/[email protected]/node_modules/ventojs/esm/src/environment.js:57:29), <anonymous>:10:28)
[11ty]     at async renderVentoTemplate (file:///Users/noel/Developer/projects/tools/eleventy-plugin-vento/dist/plugin.js:122:23)
[11ty]     at async Object.<anonymous> (file:///Users/noel/Developer/projects/tools/eleventy-plugin-vento/dist/plugin.js:224:30)
[11ty]     at async Template._render (file:///Users/noel/Developer/projects/external/uncenter.dev/node_modules/.pnpm/@[email protected]/node_modules/@11ty/eleventy/src/TemplateContent.js:586:19)
[11ty]     at async file:///Users/noel/Developer/projects/external/uncenter.dev/node_modules/.pnpm/@[email protected]/node_modules/@11ty/eleventy/src/TemplateMap.js:555:8
[11ty]     at async file:///Users/noel/Developer/projects/external/uncenter.dev/node_modules/.pnpm/[email protected]/node_modules/p-map/index.js:121:20
[11ty] Copied 13 Wrote 0 files in 3.40 seconds (v3.0.1-alpha.1)
 ELIFECYCLE  Command failed with exit code 1.

At last, we have a good trace of the error chain. This plugin wraps all Eleventy filters in async functions, so this:

{{ post.data.title |> slugify }}

becomes this:

__output += (await __env.filters.slugify.call({data:it,env:__env}, post.data.title)) ?? "";

Because postlist.vto exports a regular function that includes an async filter, the error gets thrown. Couple of ways we can resolve this:

  1. You could update postlist.vto and any other components that use filters in this way to be async-friendly:
- {{ export function PostList(posts) }}
+ {{ export async function PostList(posts) }}
  1. I can patch the code introduced to resolve Inject ctx into addFilter  #72 so that non-async functions aren't converted, which I'll probably do anyway to avoid any further unexpected behavior.

If there's another way I haven't mentioned that you think would be better used to solve this, let me know!

@noelforte
Copy link
Owner

noelforte commented Dec 23, 2024

Ok, progress. Unfortunately, it seems that even when addFilter has an async callback, the resulting filter that exists in Eleventy's filters.universal object is a synchronous function:

It's a shame, since Vento has the ability to identify if a filter is an instance of AsyncFunction and await it automatically in the resulting code, even though it maybe makes things more abstract.

I would rather not coerce all filters to be sync-by-default and then have to force {{ value |> await asyncFilter }} patterns over everyone's templates for async Eleventy filters (which is something Vento can handle), but it looks like that might be the cleanest solution so far...

@uncenter
Copy link
Author

Sorry for the delayed response, thank you for taking the time to look into it further!

I wonder if Eleventy could add methods for extracting only synchronous or asynchronous filters? Such as eleventyConfig.getSyncFilters() and eleventyConfig.getAsyncFilters()? Then it would be possible to handle this better I think.

@noelforte
Copy link
Owner

Perhaps? I dig a bit more digging to confirm I understood await properly. Even if async filters get wrapped in sync functions by Eleventy it shouldn't matter when using {{ dataValue |> await myFilter }}.

As I understand it, if myFilter is async, then what happens is:

  1. The sync wrapper function returns a call to the async filter function
  2. The async filter function returns a Promise, either inherintly because it's declared with async or it returns a Promise explicitly.
  3. The Promise gets passed to the wrapper, and then back to the template.

Behavior shouldn't change, it just means that if you use async filters in your Eleventy config, you'll have to remember to use await syntax when calling the filter in your template is all.

@uncenter
Copy link
Author

But I thought you said all filters are async because of some changes made recently? I don't think slugify is supposed to be async.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants