11ty / eleventy

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

Use parsed symbols to inform content dependency rendering order (aka fix more “Tried to use templateContent too early” edge cases) #1615

Open teekay opened 3 years ago

teekay commented 3 years ago

The build process sometimes ends with an exception TemplateContentPrematureUseError.

Steps to reproduce Steps to reproduce the behavior:

  1. I have a bunch of posts in several collection
  2. For one specific collection, I want to generate a RSS feed, placing it under /_site/tango/rss/index.njk
  3. The RSS feed looks like this:
---js
{
  permalink: "tango/rss/index.xml",
  excludeFromSitemap: true,
  pubDate: new Date()
}
---
<?xml version="1.0" encoding="UTF-8"?>
[... snip]
    {% for item in collections.tango %}
    <item>
    [... snip]
      <content:encoded>
      <![CDATA[{{ item.templateContent | htmlToAbsoluteUrls(absolutePostUrl) | safe }}]]>
      </content:encoded>
    </item>
    {% endfor %}
[... snip]

The build script invokes .\node_modules\.bin\eleventy.cmd --output=./build. This comes out on the command line:

[... snip]
Unhandled rejection in promise ([object Promise]): (more in DEBUG output)
> Tried to use templateContent too early (./_site/tango/2020-12-26-review-para-siempre-by-pablo-valle-sexteto.md)

`TemplateContentPrematureUseError` was thrown:
    TemplateContentPrematureUseError: Tried to use templateContent too early (./_site/tango/2020-12-26-review-para-siempre-by-pablo-valle-sexteto.md)
        at Object.get templateContent [as templateContent] (C:\Users\tomas\Documents\Projects\Blog\node_modules\@11ty\eleventy\src\Template.js:484:19)
        at Object.memberLookup (C:\Users\tomas\Documents\Projects\Blog\node_modules\nunjucks\src\runtime.js:253:17)
        at eval (eval at _compile (C:\Users\tomas\Documents\Projects\Blog\node_modules\nunjucks\src\environment.js:631:18), <anonymous>:85:59)
        at iterCallback (C:\Users\tomas\Documents\Projects\Blog\node_modules\nunjucks\src\runtime.js:295:11)
        at next (C:\Users\tomas\Documents\Projects\Blog\node_modules\nunjucks\src\lib.js:326:7)
        at eval (eval at _compile (C:\Users\tomas\Documents\Projects\Blog\node_modules\nunjucks\src\environment.js:631:18), <anonymous>:89:1)
        at C:\Users\tomas\Documents\Projects\Blog\node_modules\@11ty\eleventy-plugin-rss\.eleventy.js:21:7
        at runMicrotasks (<anonymous>)
        at processTicksAndRejections (internal/process/task_queues.js:97:5)

The first item in the stack trace (in which post this error occurs) changes from time to time. And sometimes, there is no error and everything works as expected.

When I remove this line from /_site/tango/rss/index.njk, there is no error:

      <![CDATA[{{ item.templateContent | htmlToAbsoluteUrls(absolutePostUrl) | safe }}]]>

Expected behavior The build process finishes normally

Environment:

teekay commented 3 years ago

When I add eleventyExcludeFromCollections: true to the front matter data, the problem seems to disappear:

---js
{
  permalink: "tango/rss/index.xml",
  excludeFromSitemap: true,
  eleventyExcludeFromCollections: true,
  pubDate: new Date()
}
---

I took the hint from the comments to #522.

It still takes me by surprise because all of my collections are specified by the glob ...**/*.md. This page is a nunjucks template, not a post. It must've been added to collections.all nevertheless, right?

andeersg commented 2 years ago

I suddenly started seeing this error too today.

It does not happen on the initial build of eleventy --serve but if I save a markdown file afterwards it fails.

It looks like the error comes from node_modules/@11ty/eleventy-plugin-rss/.eleventy.js:28:7:

 eleventyConfig.addNunjucksAsyncFilter("htmlToAbsoluteUrls", (htmlContent, base, callback) => {
    if(!htmlContent) {
      callback(null, "");
      return;
    }

    let posthtmlOptions = Object.assign({
      // default PostHTML render options
      closingSingleTag: "slash"
    }, options.posthtmlRenderOptions);

    convertHtmlToAbsoluteUrls(htmlContent, base, posthtmlOptions).then(html => {
      callback(null, html); // <- THIS LINE
    });
  });

I have Eleventy 1.0.0 and eleventy-plugin-rss 1.1.2

statox commented 2 years ago

I am facing the exact same symptoms as @andeersg with eleventy 1.1.0 and eleventy-plugin-rss 1.1.2 and nunjucks template:

Initial build is ok. Modifying a file in the post collection generates the same error from the plugin but the issue doesn't happen for pages which are not in the post collection.

Is there a workaround or something we can do about this?

(I don't have a minimal example to reproduce but this repo exhibits the behavior: clone, npm install, npm run dev then edit any file in the src/posts directory and you get the error)

xplosionmind commented 2 years ago

I am having this issue too! In several for loops (e.g. {% for entry in collections.all %}), when I call entry.templateContent I get: Tried to use templateContent too early. Nevertheless, in some other pages it works. I cannot figure out if there is any pattern or any particular reason.

Please, refer to this set of examples to reproduce the issue.

Thanks a lot! T

RobinCsl commented 2 years ago

What I've done to make it better in development is to enable the plugin only in the production build (rss.html is the only file using the filters added by the plugin):

// .eleventy.js
// ... other imports
const rssPlugin = require('@11ty/eleventy-plugin-rss');

module.exports = (config) => {
  config.ignores.add("./src/rss.html");

  if (process.env.NODE_ENV === "production") {
    config.ignores.delete("./src/rss.html");
    config.addPlugin(rssPlugin);
  }

// ... the rest
}

Hope that can help someone while a fix is found!

zachleat commented 2 years ago

Eleventy does its best to generated an ordered dependency graph of the content to generate templateContent correctly. You can read more about that here:

https://www.11ty.dev/docs/advanced-order/

That said, there are some edge cases here, because we don’t yet take into account the AST of the templates to determine what they consume (only where they publish to), as noted on the docs above.

One easy way to influence that order is to use eleventyExcludeFromCollections. That being said, in my mind this is another vote for https://github.com/11ty/eleventy/issues/975 as an escape hatch to have more control over the ordering (until we get a more advanced solution in place).

I don’t think this has anything specifically to do with the RSS plugin, it’s just where the templateContent property was referenced from.

I was not able to reproduce from https://github.com/11ty/eleventy/issues/1615#issuecomment-1060652030

So, just to summarize: I will leave this one open as the home base for a more automated solution to parse the templates to see what collections they consume. But a more short-term solution will be #975

zachleat commented 2 years ago

For me:

https://github.com/11ty/eleventy/blob/1db6a10a98f35b6f6bcac94222cdd8597e6f7928/src/Engines/Liquid.js#L207

https://github.com/11ty/eleventy/blob/1db6a10a98f35b6f6bcac94222cdd8597e6f7928/src/Engines/Nunjucks.js#L369

zachleat commented 2 years ago

Related to https://github.com/11ty/eleventy/issues/108 as well

statox commented 2 years ago

@zachleat My bad in #1615 (comment) I should have linked to this commit because after that I disabled the feed template on local build to temporarily avoid the issue.

I agree that the issues you linked seems like good solution options for this issue :+1:

zachleat commented 1 year ago

975 is shipping with 2.0.0-canary.20