11ty / eleventy

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

Global import of macros fails in Eleventy 3.0.0-alpha.14 #3345

Open groenroos opened 1 week ago

groenroos commented 1 week ago

Operating system

macOS Sonoma 14.4.1

Eleventy

3.0.0-alpha.14

Describe the bug

Using the technique described in this comment to load common macros globally for each Nunjucks and Markdown template. It works without errors in Eleventy 2.x.

However, on Eleventy 3.0.0-alpha.14, this technique quits the build with the following error:

[11ty] Unfortunately you’re using code that monkey patched some Eleventy internals and it isn’t async-friendly. Change your code to use the async `read()` method on the template instead! (via Error)

My understanding of the TemplateContent class (or other Eleventy internals) is limited, but I attempted to adapt it to use the advertised read() method:

const frontMatter = await item.template.read();
frontMatter.content = `${macroImport}\n${frontMatter.content}`;
item.template.frontMatter = frontMatter;

However, this does not appear to make the components available in Markdown files. As a test, I deleted the few Markdown pages that require components, and it then fails by confusingly claiming the collection is already defined (regardless of what the collection is named):

[ELEVENTY] [11ty] 1. Having trouble rendering liquid template ./site/src/blog/example-blog-post-slug.md (via TemplateContentRenderError)
[ELEVENTY] [11ty] 2. Error in your Eleventy config file '.eleventy.js'., file:./site/src/blog/example-blog-post-slug.md, line:18, col:1 (via RenderError)
[ELEVENTY] [11ty] 3. Error in your Eleventy config file '.eleventy.js'. (via EleventyConfigError)
[ELEVENTY] [11ty] 4. config.addCollection(everything) already exists. Try a different name for your collection. (via UserConfigError)

Reproduction steps

  1. Load a macro file globally using this technique
  2. Attempt to build with Eleventy 3.0.0-alpha.14
  3. Build will fail

Expected behavior

Either the build should succeed, or an alternative pattern should be established for loading template macros globally such that they are available in every template

Reproduction URL

No response

Screenshots

No response

zachleat commented 5 days ago

Somewhat related to #188—though this request is limited to collection entries I think!

This seems to work for me:

eleventyConfig.addCollection("userCollection", async function (collection) {
  let c = collection.getFilteredByTag("posts");
  for(let item of c) {
    const frontMatter = await item.template.read();
    frontMatter.content = `lol\n${frontMatter.content}`;
    item.template.frontMatter = frontMatter;
  }
  return c;
});
groenroos commented 4 days ago

Somewhat related to #188—though this request is limited to collection entries I think!

I reckon doing it via an (essentially unfiltered) collection is just a way to apply a template fragment to every page. It does unnecessarily "pollute" the collections with this dummy collection. Additionally, this collection approach does have the downside that these macros still aren't automatically available within layouts or includes.

Therefore, I think I'd ultimately personally prefer it if there was a dedicated feature to define global macros such that they are available on every page, include, and layout, without the need for a dummy collection like this.

Thanks for the snippet! I tried a very similar approach, but I didn't get far; I've set up a demo repo:

https://github.com/groenroos/eleventy-global-macro

Each subfolder has the same demo site on different versions of Eleventy, with your async read() approach in the 3.0.0 folder. The build currently fails due to an undefined macro, as though the injected import for component.njk hadn't been computed at all;

[11ty] Problem writing Eleventy templates: (more in DEBUG output)
[11ty] 1. Having trouble rendering njk template ./nunjucks.njk (via TemplateContentRenderError)
[11ty] 2. (./nunjucks.njk) [Line 2, Column 12]
[11ty]   Error: Unable to call `component`, which is undefined or falsey (via Template render error)
[11ty]
[11ty] Original error stack trace: Template render error: (./nunjucks.njk) [Line 2, Column 12]
[11ty]   Error: Unable to call `component`, which is undefined or falsey
[11ty]     at Object._prettifyError (/eleventy-global-macro/eleventy-3.0.0/node_modules/nunjucks/src/lib.js:32:11)
[11ty]     at /eleventy-global-macro/eleventy-3.0.0/node_modules/nunjucks/src/environment.js:464:19
[11ty]     at Template.root [as rootRenderFunc] (eval at _compile (/eleventy-global-macro/eleventy-3.0.0/node_modules/nunjucks/src/environment.js:527:18), <anonymous>:19:3)
[11ty]     at Template.render (/eleventy-global-macro/eleventy-3.0.0/node_modules/nunjucks/src/environment.js:454:10)
[11ty]     at file:///eleventy-global-macro/eleventy-3.0.0/node_modules/@11ty/eleventy/src/Engines/Nunjucks.js:426:10
[11ty]     at new Promise (<anonymous>)
[11ty]     at file:///eleventy-global-macro/eleventy-3.0.0/node_modules/@11ty/eleventy/src/Engines/Nunjucks.js:425:11
[11ty]     at Template._render (file:///eleventy-global-macro/eleventy-3.0.0/node_modules/@11ty/eleventy/src/TemplateContent.js:588:25)
[11ty]     at async TemplateMap.populateContentDataInMap (file:///eleventy-global-macro/eleventy-3.0.0/node_modules/@11ty/eleventy/src/TemplateMap.js:537:7)
[11ty]     at async TemplateMap.cache (file:///eleventy-global-macro/eleventy-3.0.0/node_modules/@11ty/eleventy/src/TemplateMap.js:444:3)
[11ty] Wrote 0 files in 0.06 seconds (v3.0.0-alpha.14)

This is the same behaviour that I get in my production repo; I initially thought it was a specific issue with using this technique in Markdown files (as my prod repo fell over on a Markdown page first), but this demo repo seems to fail with the Nunjucks template, too.