Skip to content

Templates should receive global.data.js output in vars, not just global.vars.js #235

@bcomnes

Description

@bcomnes

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions