eleventy
eleventy copied to clipboard
TemplateContentPrematureUseError resulting from eleventyConfig.addFilter()
Operating system
mac OS Sequoia, Debian 6.1
Eleventy
3.0.0
Describe the bug
Build output errors with the following:
> eleventy
[11ty] Problem writing Eleventy templates:
[11ty] 1. Having trouble rendering njk template (via TemplateContentRenderError)
[11ty] 2. Tried to use templateContent too early (via TemplateContentPrematureUseError)
[11ty]
[11ty] Original error stack trace: TemplateContentPrematureUseError: Tried to use templateContent too early
[11ty] at Object.get [as templateContent] (file:///var/www/html/node_modules/@11ty/eleventy/src/Template.js:620:14)
[11ty] at Object.get [as content] (file:///var/www/html/node_modules/@11ty/eleventy/src/Template.js:640:18)
[11ty] at /var/www/html/.eleventy.js:147:25
[11ty] at Array.map (<anonymous>)
[11ty] at lunr.Builder.<anonymous> (/var/www/html/.eleventy.js:142:10)
[11ty] at lunr (/var/www/html/node_modules/lunr/lunr.js:53:10)
[11ty] at Context.<anonymous> (/var/www/html/.eleventy.js:127:24)
[11ty] at Context.<anonymous> (file:///var/www/html/node_modules/@11ty/eleventy/src/UserConfig.js:419:24)
[11ty] at Context.fn (file:///var/www/html/node_modules/@11ty/eleventy/src/Benchmark/BenchmarkGroup.js:37:23)
[11ty] at Context.<anonymous> (file:///var/www/html/node_modules/@11ty/eleventy/src/Engines/Nunjucks.js:109:15)
[11ty] Copied 2 Wrote 0 files in 0.28 seconds (v3.0.0)
Failed to run npm run build: exit status 1
The root cause appears to be trying to pre-build a search index for Lunr.js. To accomplish this, I've created a new filter using eleventyConfig.addFilter() which iterates over all the items in a collection, and calls the content getter.
I did not encounter this error during development. If I comment out this specific call to content and build, followed by un-commenting and building with --incremental everything seems to work ok. This is fine for local, but breaks testing & production deploys.
Reproduction steps
Currently experiencing this in https://github.com/Lullabot/architecture/pull/693
npm run build
Expected behavior
Running eleventy's build command would successfully build the site
Reproduction URL
No response
Screenshots
No response
Was able to bypass the error by forcing the template to render all the content values in a way it expected, but that didn't actually print anything.
---
layout: false
permalink: /searchindex.json
eleventyExcludeFromCollections: true
---
{#
Needed to prevent TemplateContentPrematureUseError.
Doesn't actually get printed.
#}
{% set rendered %}
{% for adr in collections.adrs %}
{{ adr.content }}
{% endfor %}
{% endset %}
{# This actually does what I want. #}
{% lunrIndex collections.adrs %}
We ran into this issue too, but only on certain devices, and only intermittently; which suggests some sort of race condition.
Our use case was paginating through the list of collections to return a JSON of all posts per collection in a specific format:
export.njk
---js
{
"sitemap": false,
"eleventyExcludeFromCollections": true,
"pagination": {
"data": "collections",
"size": 1,
"alias": "collection",
"addAllPagesToCollections": false
},
"eleventyComputed": {
"permalink": function() {
return process.env.NODE_ENV === 'production' ? false : 'export/{{ collection }}.json';
}
}
}
---
{{ collections[collection] | export | safe }}
export.js filter
/* Keys of recursive or unnecessary data supplied by Eleventy and data files */
const pollution = [
/* Eleventy internals */
'eleventy',
'eleventyComputed',
'collections',
'pkg',
'page',
'pagination',
/* etc */
];
export default function (collection) {
/* Clean up the collection items */
const sanitisedCollection = Array.isArray(collection) ? collection.map(item => {
const data = { ...item.data };
/* Remove unnecessary keys from data */
for (const pollutant of pollution) {
if (pollutant in data) {
delete data[pollutant];
}
}
/* Construct minimal page object */
return {
data,
page: item.page,
slug: item.fileSlug,
url: item.url,
content: item.content,
};
}) : [];
return JSON.stringify(sanitisedCollection);
}
In our case, we only solved it by adding the entire list of collections into eleventyImport:
---js
{
/* ... */
"pagination": {
"data": "collections",
"size": 1,
"alias": "collection",
"addAllPagesToCollections": false
},
"eleventyImport": {
"collections": [
"posts",
"pages",
"things",
"stuff",
/* etc */
]
},
/* ... */
}
---
{{ collections[collection] | export | safe }}
However, it's not very durable to maintain a manual list of all the collections in this specific file (and remembering to add and remove values as the collections change over time).
In the absence of any other fix for this, I'd at least be interested to see if there's a way to use the JS frontmatter to automatically generate the array of all available collections to use for eleventyImport.collections - or any other change I should make to my filter or pagination to avoid TemplateContentPrematureUseError errors.
I don’t see https://github.com/Lullabot/architecture/pull/693 is it a private repo?
eleventyImport and eleventyExcludeFromCollections can be used to influence template rendering order
- https://www.11ty.dev/docs/collections/#declare-your-collections-for-incremental-builds
- https://www.11ty.dev/docs/collections/#how-to-exclude-content-from-collections
You can use them together, we use this in the RSS Virtual Template:
https://github.com/11ty/eleventy-plugin-rss/blob/76d452a847322d25c525d17dceb83eb07e9b9793/src/virtualTemplate.js#L138-L148
Oh, sorry, yeah. I forgot that's a private repo.
The basic structure of what was happening is that I created a filter in .eleventy.js. This filter was applied to a collections.collectionName to iterate over each entry in that collection to generate a static search index for Lunr.js
This all worked fine locally when the dev server was already up and running, but a cold start failed with the TemplateContentPrematureUseError. Even with eleventyImport and eleventyExcludeFromCollections, a cold build wouldn't work.
I have since added a for loop in the template where I want the generated index that doesn't actually output anything. That seems to have sidestepped whatever bug was happening (see code in previous comment)