This issue was originally identified in voxpelli/voxpelli.github.com#32
Problem
Templates receive { vars, pages, template } where vars contains only the output from global.vars.js. The aggregated data computed by global.data.js is not included. This forces every template to re-implement the same filtering, sorting, and categorization logic that global.data.js already performs.
Expected: Template vars includes both global.vars.js output and global.data.js output, matching how page vars work (where globalDataVars are merged in via PageData.vars).
Actual: Template vars is set to the bare globalVars object. The globalDataVars computed by global.data.js are stamped onto PageData instances but never passed to the template builder.
Current behavior
How pages get globalDataVars (works correctly)
// lib/build-pages/index.js
if (Object.keys(globalDataVars).length > 0) {
for (const page of pages) {
page.globalDataVars = globalDataVars // ✓ pages get it
}
}
How templates do NOT get globalDataVars (the bug)
// lib/build-pages/index.js
pMap(templatesToRender, async (template) => {
const buildResult = await templateBuilder({
src,
dest,
globalVars, // ← bare globalVars only, no globalDataVars
template,
pages,
})
The TemplateFunction type's JSDoc even says @param {T} params.vars - All of the site globalVars. — confirming only globalVars is passed.
Reproduction
// src/global.data.js -- computes recentPosts, blogPosts, etc.
export default function globalData ({ pages }) {
return { allPosts, recentPosts };
}
// src/feeds.template.js -- CANNOT access recentPosts from vars
export default async function * feedsTemplate ({ pages, vars }) {
// vars.recentPosts === undefined
// Must re-derive everything from pages[]
}
Proposed solution
Merge globalDataVars into the globalVars object passed to templateBuilder. The fix is a one-line change:
// In lib/build-pages/index.js, around line 276:
const buildResult = await templateBuilder({
src,
dest,
globalVars: { ...globalVars, ...globalDataVars }, // Include global.data output
template,
pages,
});
This makes template vars consistent with how page vars already work via the PageData.vars getter.
Real-world impact
This causes every template that needs aggregated data to duplicate the entire filtering/sorting pipeline from global.data.js. For example, a feeds template can end up with 25+ lines of code that are near-identical copies of global.data.js logic — any change to categorization must be made in both places.
Alternatives considered
| Approach |
Pros |
Cons |
Merge globalDataVars into template vars |
One-line fix, consistent with pages |
Could cause namespace collisions if keys overlap |
Pass globalDataVars as a separate data param |
No collision risk |
New API surface; every template signature changes |
| Document the workaround pattern |
Zero code change |
Perpetuates code duplication in every project |
Namespace collision risk is minimal: global.vars.js typically exports static config while global.data.js exports computed aggregates.
Problem
Templates receive
{ vars, pages, template }wherevarscontains only the output fromglobal.vars.js. The aggregated data computed byglobal.data.jsis not included. This forces every template to re-implement the same filtering, sorting, and categorization logic thatglobal.data.jsalready performs.Expected: Template
varsincludes bothglobal.vars.jsoutput andglobal.data.jsoutput, matching how pagevarswork (whereglobalDataVarsare merged in viaPageData.vars).Actual: Template
varsis set to the bareglobalVarsobject. TheglobalDataVarscomputed byglobal.data.jsare stamped ontoPageDatainstances but never passed to the template builder.Current behavior
How pages get
globalDataVars(works correctly)How templates do NOT get
globalDataVars(the bug)The
TemplateFunctiontype's JSDoc even says@param {T} params.vars - All of the site globalVars.— confirming onlyglobalVarsis passed.Reproduction
Proposed solution
Merge
globalDataVarsinto theglobalVarsobject passed totemplateBuilder. The fix is a one-line change:This makes template
varsconsistent with how pagevarsalready work via thePageData.varsgetter.Real-world impact
This causes every template that needs aggregated data to duplicate the entire filtering/sorting pipeline from
global.data.js. For example, a feeds template can end up with 25+ lines of code that are near-identical copies ofglobal.data.jslogic — any change to categorization must be made in both places.Alternatives considered
globalDataVarsinto templatevarsglobalDataVarsas a separatedataparamNamespace collision risk is minimal:
global.vars.jstypically exports static config whileglobal.data.jsexports computed aggregates.