Skip to content

pageUrl not available to layouts for directly-rendered pages #238

@bcomnes

Description

@bcomnes

This issue was originally identified in voxpelli/voxpelli.github.com#32

Problem

Layouts receive page variables via the vars object, but pageUrl (the URL path of the current page) is not included for pages rendered directly from markdown or HTML sources. This means layouts cannot construct canonical URLs, Open Graph URLs, or any other URL-dependent metadata without manual workarounds.

Every page on a site ends up with the same canonical URL (e.g., https://example.com/) regardless of the actual page URL, harming SEO and breaking IndieWeb URL discovery.

Current behavior

// In a layout function:
export default function rootLayout ({ children, vars }) {
  console.log(vars.pageUrl); // undefined for article pages
  const pageUrl = String(vars.pageUrl || '') || '/';
  const canonicalUrl = `${siteUrl}${pageUrl}`; // Always https://example.com/
}

Expected behavior

DomStack should automatically inject pageUrl (derived from pageInfo.path) into the vars object before passing it to layouts. For a page at src/2015/01/my-post/page.md, the layout should receive:

vars.pageUrl === '/2015/01/my-post/'

Source code analysis

The PageData.vars getter (lib/build-pages/page-data.js) merges:

{ ...globalVars, ...globalDataVars, ...pageVars, ...builderVars }

No pageInfo properties are injected into this merge. The page object is passed as a separate page parameter to the layout function:

await layout.render({ vars, styles, scripts, page: pageInfo, pages, children, workers })

Workaround

Layouts can construct the URL from the separate page parameter:

export default function rootLayout ({ children, vars, page }) {
  const pageUrl = page.path ? '/' + page.path + '/' : '/'
  const canonicalUrl = `${vars.siteUrl}${pageUrl}`
}

This works but is fragile — every layout must remember to do this, and there is no guarantee the path-to-URL convention matches global.data.js.

Proposed fix

In the page rendering pipeline, inject pageUrl into the merged vars:

const mergedVars = {
  ...globalVars,
  ...pageVars,
  ...frontmatterVars,
  pageUrl: '/' + pageInfo.path + '/',  // Auto-derived from filesystem path
};

Alternatively, document that layouts should use page.path to construct URLs, and that the convention '/' + page.path + '/' is standard — as already used in global.data.js and DomStack's own example layouts.

This would be a non-breaking change since no existing pageVars or globalVars would typically use the pageUrl key.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions