From 12b089bb928c60e8ac3ef5d519d657b16194327e Mon Sep 17 00:00:00 2001 From: james-owen Date: Fri, 4 Nov 2022 12:48:06 -0400 Subject: [PATCH 1/6] feat: handle linked font files --- lib/media.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/media.js b/lib/media.js index f9165f7..16b0531 100644 --- a/lib/media.js +++ b/lib/media.js @@ -274,6 +274,14 @@ function getStyleFiles(state) { } } + // check for clay compile linked? clay compile font files? + const defaultFontPath = path.join(assetDir, 'css', '_linked-fonts._default.css'); + const siteFontPath = path.join(assetDir, 'css', `_linked-fonts.${siteStyleguide}.css`); + + // add any default and site font css + cssFilePaths.push(defaultFontPath); + cssFilePaths.push(siteFontPath); + return cssFilePaths .filter(files.fileExists) .map(pathJoin(assetHost, assetPath, assetDir)); From d3219195d49e26d32bf32150e20878307544f364 Mon Sep 17 00:00:00 2001 From: james-owen Date: Fri, 4 Nov 2022 12:49:28 -0400 Subject: [PATCH 2/6] 6.0.0-dev.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4ad7d53..963d07b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "amphora-html", - "version": "6.0.0-7", + "version": "6.0.0-dev.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/package.json b/package.json index 98d1174..f9f4d45 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "amphora-html", - "version": "6.0.0-7", + "version": "6.0.0-dev.0", "description": "An HTML renderer for component data", "main": "index.js", "scripts": { From 3941ab3141682d2682f2be15c94b283d127aacf0 Mon Sep 17 00:00:00 2001 From: james-owen Date: Tue, 21 Jan 2025 17:06:45 -0500 Subject: [PATCH 3/6] feat: pass res to postrender hooks --- lib/render.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/render.js b/lib/render.js index fd5adb3..0d5011d 100644 --- a/lib/render.js +++ b/lib/render.js @@ -40,7 +40,7 @@ function applyRenderHooks(ref, data, locals) { * @param {Object} locals * @returns {Function} */ -function applyPostRenderHooks(ref, locals) { +function applyPostRenderHooks(ref, locals, res) { return (html) => { // skip postRender hooks in edit mode @@ -50,7 +50,7 @@ function applyPostRenderHooks(ref, locals) { return setup.plugins.filter((plugin) => plugin.postRender) .reduce((val, plugin) => { - return plugin.postRender(ref, html, locals); + return plugin.postRender(ref, html, locals, res); }, html); }; } @@ -148,7 +148,7 @@ function render(data, meta, res) { return applyRenderHooks(state._layoutRef || state.self, data, state.locals) .then(makeHtml(state)) .then(mediaService.injectScriptsAndStyles(state)) - .then(applyPostRenderHooks(state._layoutRef || state.self, state.locals)) + .then(applyPostRenderHooks(state._layoutRef || state.self, state.locals, res)) .then(result => { res.type('text/html'); res.send(result); From 6f6be0f64fff849a9124de592d5c290978612e3a Mon Sep 17 00:00:00 2001 From: james-owen Date: Thu, 23 Jan 2025 11:19:41 -0500 Subject: [PATCH 4/6] use meta ref --- lib/render.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/render.js b/lib/render.js index 0d5011d..428889e 100644 --- a/lib/render.js +++ b/lib/render.js @@ -40,7 +40,7 @@ function applyRenderHooks(ref, data, locals) { * @param {Object} locals * @returns {Function} */ -function applyPostRenderHooks(ref, locals, res) { +function applyPostRenderHooks(ref, locals, res, self) { return (html) => { // skip postRender hooks in edit mode @@ -50,7 +50,7 @@ function applyPostRenderHooks(ref, locals, res) { return setup.plugins.filter((plugin) => plugin.postRender) .reduce((val, plugin) => { - return plugin.postRender(ref, html, locals, res); + return plugin.postRender(ref, html, locals, res, self); }, html); }; } @@ -148,7 +148,7 @@ function render(data, meta, res) { return applyRenderHooks(state._layoutRef || state.self, data, state.locals) .then(makeHtml(state)) .then(mediaService.injectScriptsAndStyles(state)) - .then(applyPostRenderHooks(state._layoutRef || state.self, state.locals, res)) + .then(applyPostRenderHooks(state._layoutRef || state.self, state.locals, res, meta._ref)) .then(result => { res.type('text/html'); res.send(result); From 5c688df535aec8222db94732e6e1804299f376c3 Mon Sep 17 00:00:00 2001 From: james-owen Date: Thu, 23 Jan 2025 15:09:31 -0500 Subject: [PATCH 5/6] 6.0.1-dev.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 963d07b..45c848c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "amphora-html", - "version": "6.0.0-dev.0", + "version": "6.0.1-dev.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "amphora-html", - "version": "6.0.0-6", + "version": "6.0.1-dev.0", "license": "MIT", "dependencies": { "amphora-fs": "^2.0.0", diff --git a/package.json b/package.json index f9f4d45..9185a35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "amphora-html", - "version": "6.0.0-dev.0", + "version": "6.0.1-dev.0", "description": "An HTML renderer for component data", "main": "index.js", "scripts": { From e8b38f350f23a4c76938fd66a2b60d8b7270aa82 Mon Sep 17 00:00:00 2001 From: Jordan Paulino Date: Sun, 8 Mar 2026 17:06:44 -0400 Subject: [PATCH 6/6] Add modulepreload and module script support for esbuild pipeline - Add MODULE_SCRIPT_TAG and MODULEPRELOAD_TAG constants to media.js - Add omitCacheBusterOnModules flag (enabled when modulepreload:true) so content-hashed ESM filenames skip the redundant ?version= query string - Handle moduleScripts and modulePreloads in injectScriptsAndStyles(), injecting `; } else if (tag === ASYNC_DEFER_SCRIPT_TAG) { return ``; + } else if (tag === MODULE_SCRIPT_TAG) { + return ``; + } else if (tag === MODULEPRELOAD_TAG) { + // tells the browser to fetch ESM scripts early, + // during HTML parsing, before reaching the `; } @@ -378,6 +390,14 @@ function configure(options, cacheBuster = '') { if (options && _.isObject(options)) { module.exports.editStylesTags = options.styles || false; module.exports.editScriptsTags = options.scripts || false; + // modulepreload: when true, hints are injected + // into for ESM scripts, and ?version= is omitted from module URLs + // since content-hashed filenames already provide cache busting. + // Opt-in only — defaults to false for backwards compatibility. + if (options.modulepreload !== undefined) { + module.exports.modulepreload = !!options.modulepreload; + module.exports.omitCacheBusterOnModules = !!options.modulepreload; + } } else { module.exports.editStylesTags = options; module.exports.editScriptsTags = options; @@ -412,8 +432,29 @@ function injectScriptsAndStyles(state) { mediaMap = module.exports.getMediaMap(state); // allow site to change the media map before applying it + // Expose rendered component names so resolveMedia can do per-component script resolution + // (e.g. pack-next manifest lookup) without needing a reference to the full state object. + locals._components = state._components; if (setup.resolveMedia) mediaMap = setup.resolveMedia(mediaMap, locals) || mediaMap; + // moduleScripts: ESM scripts (e.g. from esbuild pack-next) that need type="module" + const moduleScriptFiles = mediaMap.moduleScripts || []; + + mediaMap.moduleScripts = moduleScriptFiles.length + ? injectTags(moduleScriptFiles, locals.site, MODULE_SCRIPT_TAG) + : bluebird.resolve(false); + + // modulePreloads: hints for . + // Only active when configure({ modulepreload: true }) has been called — opt-in so + // sites not using the clay build pipeline are completely unaffected. + const modulePreloadFiles = module.exports.modulepreload + ? (mediaMap.modulePreloads || []) + : []; + + mediaMap.modulePreloads = modulePreloadFiles.length + ? injectTags(modulePreloadFiles, locals.site, MODULEPRELOAD_TAG) + : bluebird.resolve(false); + if (!locals.edit) { mediaMap.styles = combineFileContents(mediaMap.styles, 'public/css', '/css/', STYLE_TAG); mediaMap.scripts = !!mediaMap.manifestAssets && mediaMap.manifestAssets.length > 0 @@ -426,7 +467,11 @@ function injectScriptsAndStyles(state) { return bluebird.props(mediaMap) .then(combinedFiles => { + // modulepreload hints go first in , before CSS, so the browser can + // start fetching ESM scripts at the earliest possible moment. + html = combinedFiles.modulePreloads ? appendMediaToTop(combinedFiles.modulePreloads, html) : html; html = combinedFiles.styles ? appendMediaToTop(combinedFiles.styles, html) : html; // If there are styles, append them + html = combinedFiles.moduleScripts ? appendMediaToBottom(combinedFiles.moduleScripts, html) : html; // ESM module scripts (type="module") html = combinedFiles.scripts ? appendMediaToBottom(combinedFiles.scripts, html) : html; // If there are scripts, append them return html; // Return the compiled HTML }); @@ -439,6 +484,10 @@ module.exports.cacheBuster = ''; module.exports.configure = configure; module.exports.editStylesTags = false; module.exports.editScriptsTags = false; +// Opt-in flags for the clay build (esbuild) pipeline. +// Enable via configure({ modulepreload: true }). +module.exports.modulepreload = false; +module.exports.omitCacheBusterOnModules = false; // For testing module.exports.getManifestAssets = getManifestAssets; diff --git a/lib/render.js b/lib/render.js index 428889e..5be6d69 100644 --- a/lib/render.js +++ b/lib/render.js @@ -182,8 +182,12 @@ function logTime(hrStart, msg, route) { }; } -function configure({ editAssetTags, cacheBuster }) { - mediaService.configure(editAssetTags, cacheBuster); +function configure({ editAssetTags, cacheBuster, modulepreload }) { + const mediaOptions = editAssetTags && typeof editAssetTags === 'object' + ? Object.assign({}, editAssetTags, modulepreload !== undefined ? { modulepreload } : {}) + : editAssetTags; + + mediaService.configure(mediaOptions, cacheBuster); } /**