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.
Problem
Layouts receive page variables via the
varsobject, butpageUrl(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
Expected behavior
DomStack should automatically inject
pageUrl(derived frompageInfo.path) into thevarsobject before passing it to layouts. For a page atsrc/2015/01/my-post/page.md, the layout should receive:Source code analysis
The
PageData.varsgetter (lib/build-pages/page-data.js) merges:No
pageInfoproperties are injected into this merge. Thepageobject is passed as a separatepageparameter to the layout function:Workaround
Layouts can construct the URL from the separate
pageparameter: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
pageUrlinto the merged vars:Alternatively, document that layouts should use
page.pathto construct URLs, and that the convention'/' + page.path + '/'is standard — as already used inglobal.data.jsand DomStack's own example layouts.This would be a non-breaking change since no existing
pageVarsorglobalVarswould typically use thepageUrlkey.