eleventy
eleventy copied to clipboard
Accessing data.collections in eleventyComputed.permalink kills paginated pages
Operating system
macOS Sonoma 14.2.1
Eleventy
3.0.0-alpha.3
Describe the bug
Using eleventyComputed to build permalinks for paginated pages works great… unless the permalink function access data.collections.anyCollectionName
.
If that variable is touched (checking the length of a collection, console logging its existence, etc) the permalink function's return value is ignored, and all of the paginated items produce conflicting permalinks.
Reproduction steps
eleventy.config.js:
export default async function(eleventyConfig) {
// Manually add the documents to global data
eleventyConfig.addGlobalData('documents', [
{ "title": "page 1", "id": "page-1", "content": "this is the first data page." },
{ "title": "page 2", "id": "page-2", "content": "this is the second data page." },
{ "title": "page 3", "id": "page-3", "content": "this is the third data page." }
]);
// Build a dummy collection
eleventyConfig.addCollection("test", () => []);
// Define computed functions
eleventyConfig.addGlobalData('eleventyComputed.permalink', computedPermalink);
}
const computedPermalink = function() {
return( data ) => {
if (data.collections.test || 1) {
return `/${data.document.id}/`;
}
}
}
page.md:
---
pagination:
data: documents
size: 1
alias: document
---
# {{ document.title }}
{{ document.content }}
Expected behavior
When the data.collections.test
reference is removed from the code above, all three pages are generated correctly.
Eleventy:Logger Writing _site/page-1/index.html from ./page.md (liquid) +0ms
Eleventy:Logger Writing _site/page-2/index.html from ./page.md (liquid) +0ms
Eleventy:Logger Writing _site/page-3/index.html from ./page.md (liquid) +0ms
Eleventy:Template _site/page-3/index.html written.. +5ms
Eleventy:Template _site/page-1/index.html written.. +0ms
Eleventy:Template _site/page-2/index.html written.. +0ms
[11ty] Wrote 3 files in 0.05 seconds (v3.0.0-alpha.3)
When data.collections.test
is referenced in any way, building the site generates the following error:
[11ty] Problem writing Eleventy templates:
[11ty] Output conflict: multiple input files are writing to `_site/page/index.html`. Use distinct `permalink` values to resolve this conflict.
[11ty] 1. ./page.md
[11ty] 2. ./page.md
[11ty] 3. ./page.md (via DuplicatePermalinkOutputError)
[11ty] Wrote 0 files in 0.05 seconds (v3.0.0-alpha.3)
Reproduction URL
Screenshots
No response
I've spend two hours to understand why it's happening. Solutions is easy. 11ty generating N pages for each pagination page, and trying to create files with same name. Solution to add permalink, which is depends on pagination page number:
permalink: /my-awesome-listing/{% if pagination.pageNumber > 0 %}/page-{{ pagination.pageNumber }}{% endif %}
I think it would be greate to have a warning at least if we have paggination and missing permalink properties.
I think there might be some misunderstanding — the issue isn't that a paginated page without a permalink is generating permalink collisions. It's that the eleventyComputed
permalink is working correctly until the permalink generation function access one of the collections in data.collection
; once a collection is touched via the data proxy object, the permalink function's return value appears to be ignored.
export default async function(eleventyConfig) {
// ...
eleventyConfig.addGlobalData('eleventyComputed.permalink', computedPermalink);
}
const computedPermalink = function() {
return( data ) => {
// Accessing data.collections.[whatever] in any way -- with a conditional check,
// iterating its contents, etc -- prevents the next line from returning the permalink value.
console.log(data.collections.all);
// This return value is ignored unless the console.log call is commented out
return `/${data.document.id}/`;
}
}
The discarding of the returned permalink is what results in the collisions — just adding a hard-coded permalink line to the frontmatter works because it doesn't touch any collections.
After some additional digging, I think I'm a bit closer to figuring out what's going on:
-
TemplateMap.cache()
gets called whenever any collections data is retrieved. (This includes collections.all, etc) -
TemplateMap.checkForDuplicatePermalinks()
is called inside ofTemplateMap.cache()
; by that point all of the paginated outputs for a single template have already been expanded. If duplicates are found, an error is thrown. - If an
eleventyComputed.permalink
function accesses any collections, the permalinks are checked for collisions before the actual permalink can be returned; eleventy uses a fallback permalink based on the filepath, which causes collisions for paginated templates.
I'm not sure if this is something that can be resolved (I think i remember some poking near this in the serverless code?), or if I'm just pushing computed permalinks too far for my own good. Will continue poking at it, but at least I understand what order of operations triggers the issue.
I ran into this too.
I think our problem is actually "accessing data.collections in eleventyComputed.permalink makes the permalink empty", and that the collision error you're getting is a secondary effect of multiple items getting the same buggy permalink (and that the secondary error prevents the primary from being logged).
Stackblitz reproduction https://stackblitz.com/edit/stackblitz-starters-ukmhij (where you used addGlobalData
I used files; the repro uses v3 alpha but I confirmed that the same thing happens in the latest v2)
The bug trigger:
export default {
eleventyComputed: {
permalink: (data) => {
console.log(data?.collections?.length);
return;
},
},
}
With the computed permalink applied to only one input file, the error is (with a real path instead of <input file path>
)
[11ty] 1. Having trouble writing to "" from "<input file path>" (via EleventyTemplateError)
The debug mode has more details (with a real path instead of <input file path>
)
Eleventy:Template First round of computed data for '<input file path>' +8ms
Eleventy:Template Rendering permalink for '<input file path>': (((11ty(((permalink)))11ty))) becomes '(((11ty(((permalink)))11ty)))' +3ms
Eleventy:ComputedData 'page.url' accesses [ 'permalink' ] variables +0ms
Eleventy:Template Rendering permalink for '<input file path>': (((11ty(((permalink)))11ty))) becomes '(((11ty(((permalink)))11ty)))' +1ms
Eleventy:ComputedData 'page.outputPath' accesses [ 'permalink' ] variables +0ms
Eleventy:ComputedData 'eleventyExcludeFromCollections' accesses [] variables +5ms
Eleventy:ComputedData 'permalink' accesses [ 'collections', 'collections.length' ] variables +0ms
Eleventy:ComputedData Computed data order of execution: [ 'eleventyExcludeFromCollections' ] +1ms
Eleventy:TemplateMap Collection: collections.all size: 1 +13ms
Eleventy:TemplateMap Collection: collections.posts size: 1 +0ms
Eleventy:TemplateMap Collection: collections.all size: 1 +0ms
Eleventy:Template Second round of computed data for '<input file path>' +6ms
Eleventy:ComputedData Computed data order of execution: [ 'collections.length', 'permalink', 'page.url', 'page.outputPath' ] +0ms
Eleventy:TemplateWriter Template map created. +124ms
Eleventy:Logger Writing from <input file path> (liquid) +0ms
[11ty] Problem writing Eleventy templates:
[11ty] 1. Having trouble writing to "" from "<input file path>" (via EleventyTemplateError)
Eleventy:EleventyErrorHandler (error stack): EleventyTemplateError: Having trouble writing to "" from "<input file path>"
Eleventy:EleventyErrorHandler at eval (/home/projects/stackblitz-starters-ukmhij/node_modules/@11ty/eleventy/src/TemplateWriter.js:390:8)
Eleventy:EleventyErrorHandler at async Eleventy.executeBuild (/home/projects/stackblitz-starters-ukmhij/node_modules/@11ty/eleventy/src/Eleventy.js:1259:10) +0ms
The source lines linked in that error are
- https://github.com/11ty/eleventy/blob/main/src/TemplateWriter.js#L374
- https://github.com/11ty/eleventy/blob/main/src/Eleventy.js#L1259