Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi source support for commerce configs and placeholders #286

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5af1925
refactor: update fetchPlaceholders import path and enhance multi-stor…
fnhipster Jan 28, 2025
6d845e6
fix: disable eslint rule for cyclic imports in configs.js
fnhipster Jan 28, 2025
a60bc9c
refactor: update fetchPlaceholders function for improved multi-store …
fnhipster Jan 28, 2025
1433d1a
index all pages in the two-tiers structure
fnhipster Jan 28, 2025
4174060
refactor: update helix-query.yaml to exclude drafts, enrichment, and …
fnhipster Jan 28, 2025
3ef2451
refactor: remove tiers configuration from helix-query.yaml
fnhipster Jan 30, 2025
5517558
refactor: simplify buildConfigURL and remove unused root path handlin…
fnhipster Jan 30, 2025
09f2ed1
fix: ensure checkIsAuthenticated returns a boolean value
fnhipster Jan 30, 2025
f50a66e
refactor: enhance buildConfigURL to accept dynamic root path and upda…
fnhipster Jan 30, 2025
6bccb24
refactor: simplify fetchPlaceholders to support single store fetching
fnhipster Jan 30, 2025
f7458e3
refactor: update fetchPlaceholders import paths to use aem.js
fnhipster Jan 30, 2025
4af4b69
Update scripts/configs.js
fnhipster Jan 30, 2025
30be7c5
refactor: enhance fetchPlaceholders to support multiple source fetchi…
fnhipster Jan 31, 2025
396deb2
refactor: update fetchPlaceholders to handle empty string for overrides
fnhipster Jan 31, 2025
a0fa27a
refactor: update loadFragment to use getRootPath for dynamic URL cons…
fnhipster Jan 31, 2025
5f78829
USF-1918: Sharepoint documents have a two-tier structure with English…
anthoula Jan 31, 2025
9156bd9
fix: correct logical condition for link href validation
fnhipster Feb 1, 2025
7e9133b
USF-1918: Sharepoint documents have a two-tier structure with English…
anthoula Feb 3, 2025
91a34b7
feat: add dynamic metadata fetching for 404 page based on URL patterns
fnhipster Feb 3, 2025
1a7c265
Merge branch 'multistore' of https://github.com/hlxsites/aem-boilerpl…
fnhipster Feb 3, 2025
a2e1271
USF-1918: Sharepoint documents have a two-tier structure with English…
anthoula Feb 3, 2025
7c6a4f2
USF-1918: Sharepoint documents have a two-tier structure with English…
anthoula Feb 3, 2025
e63b1f6
Update scripts/scripts.js
fnhipster Feb 4, 2025
9cc9754
USF-1918: Sharepoint documents have a two-tier structure with English…
anthoula Feb 5, 2025
42efb12
USF-1918: Sharepoint documents have a two-tier structure with English…
anthoula Feb 6, 2025
e0943a7
Merge branch 'main' of github.com:hlxsites/aem-boilerplate-commerce i…
anthoula Feb 7, 2025
6efb16f
USF-1918: Sharepoint documents have a two-tier structure with English…
anthoula Feb 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion blocks/commerce-mini-cart/commerce-mini-cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import MiniCart from '@dropins/storefront-cart/containers/MiniCart.js';
import '../../scripts/initializers/cart.js';

import { readBlockConfig } from '../../scripts/aem.js';
import { localizeLink } from '../../scripts/scripts.js';

export default async function decorate(block) {
const {
Expand All @@ -18,7 +19,7 @@ export default async function decorate(block) {
return provider.render(MiniCart, {
routeEmptyCartCTA: startShoppingURL ? () => startShoppingURL : undefined,
routeCart: cartURL ? () => cartURL : undefined,
routeCheckout: checkoutURL ? () => checkoutURL : undefined,
routeCheckout: checkoutURL ? () => localizeLink(checkoutURL) : undefined,
routeProduct: (product) => `/products/${product.url.urlKey}/${product.topLevelSku}`,
})(block);
}
5 changes: 4 additions & 1 deletion blocks/fragment/fragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import {
decorateMain,
getRootPath,
} from '../../scripts/scripts.js';

import {
Expand All @@ -20,7 +21,9 @@ import {
*/
export async function loadFragment(path) {
if (path && path.startsWith('/')) {
const resp = await fetch(`${path}.plain.html`);
const root = getRootPath().replace(/\/$/, '');
const url = `${root}${path}.plain.html`;
const resp = await fetch(url);
if (resp.ok) {
const main = document.createElement('main');
main.innerHTML = await resp.text();
Expand Down
1 change: 0 additions & 1 deletion head.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
<script src="/scripts/configs.js" type="module"></script>
<script src="/scripts/commerce.js" type="module"></script>

<link rel="preload" href="/placeholders.json" as="fetch" crossorigin="anonymous" />
<link rel="modulepreload" href="/scripts/initializers/index.js" />
<link rel="modulepreload" href="/scripts/initializers/auth.js" />
<link rel="modulepreload" href="/scripts/initializers/cart.js" />
Expand Down
30 changes: 24 additions & 6 deletions scripts/aem.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,20 +503,35 @@ function decorateSections(main) {
*/
// eslint-disable-next-line import/prefer-default-export
async function fetchPlaceholders(prefix = 'default') {
const overrides = getMetadata('placeholders') || '';
const [fallback, override] = overrides.split('\n');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment on placeholder fallbacks.

window.placeholders = window.placeholders || {};
if (!window.placeholders[prefix]) {
window.placeholders[prefix] = new Promise((resolve) => {
const url = getMetadata('placeholders') || `${prefix === 'default' ? '' : prefix}/placeholders.json`;
fetch(url)
.then((resp) => {
const url = fallback || `${prefix === 'default' ? '' : prefix}/placeholders.json`;
Promise.all([fetch(url), override ? fetch(override) : Promise.resolve()])
.then(async ([resp, oResp]) => {
if (resp.ok) {
return resp.json();
if (oResp?.ok) {
return Promise.all([resp.json(), await oResp.json()]);
}
return Promise.all([resp.json(), {}]);
}
return {};
})
.then((json) => {

.then(([json, oJson]) => {
const placeholders = {};
// build placeholders object
json.data.forEach(({ Key, Value }) => {
// check for overrides
if (oJson?.data) {
const overrideItem = oJson.data.find((item) => item.Key === Key);
if (overrideItem) {
// eslint-disable-next-line no-param-reassign
Value = overrideItem.Value;
}
}
if (Key) {
const keys = Key.split('.');
const lastKey = keys.pop();
Expand All @@ -527,10 +542,13 @@ async function fetchPlaceholders(prefix = 'default') {
target[lastKey] = Value;
}
});
// cache placeholders
window.placeholders[prefix] = placeholders;
// return placeholders
resolve(window.placeholders[prefix]);
})
.catch(() => {
.catch((error) => {
console.error('error loading placeholders', error);
// error loading placeholders
window.placeholders[prefix] = {};
resolve(window.placeholders[prefix]);
Expand Down
25 changes: 19 additions & 6 deletions scripts/configs.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/* eslint-disable import/no-cycle */

import { getRootPath } from './scripts.js';

const ALLOWED_CONFIGS = ['prod', 'stage', 'dev'];

/**
Expand Down Expand Up @@ -29,21 +33,22 @@ export const calcEnvironment = () => {
return environment;
};

function buildConfigURL(environment) {
function buildConfigURL(environment, root = '/') {
const env = environment || calcEnvironment();
let fileName = 'configs.json';
if (env !== 'prod') {
fileName = `configs-${env}.json`;
}
const configURL = new URL(`${window.location.origin}/${fileName}`);
const configURL = new URL(`${window.location.origin}${root}${fileName}`);
return configURL;
}

const getConfigForEnvironment = async (environment) => {
const env = environment || calcEnvironment();
const root = getRootPath() || '/';

try {
const configJSON = window.sessionStorage.getItem(`config:${env}`);
const configJSON = window.sessionStorage.getItem(`config:${env}:${root}`);
fnhipster marked this conversation as resolved.
Show resolved Hide resolved
if (!configJSON) {
throw new Error('No config in session storage');
}
Expand All @@ -55,13 +60,13 @@ const getConfigForEnvironment = async (environment) => {

return parsedConfig;
} catch (e) {
let configJSON = await fetch(buildConfigURL(env));
let configJSON = await fetch(buildConfigURL(env, root));
if (!configJSON.ok) {
throw new Error(`Failed to fetch config for ${env}`);
}
configJSON = await configJSON.json();
configJSON[':expiry'] = Math.round(Date.now() / 1000) + 7200;
window.sessionStorage.setItem(`config:${env}`, JSON.stringify(configJSON));
window.sessionStorage.setItem(`config:${env}:${root}`, JSON.stringify(configJSON));
return configJSON;
}
};
Expand All @@ -87,13 +92,21 @@ export const getConfigValue = async (configParam, environment) => {
export const getHeaders = async (scope, environment) => {
const env = environment || calcEnvironment();
const config = await getConfigForEnvironment(env);
const configElements = config.data.filter((el) => el?.key.includes(`headers.${scope}`));
const configElements = config.data.filter((el) => el?.key.includes('headers.all') || el?.key.includes(`headers.${scope}`));

return configElements.reduce((obj, item) => {
let { key } = item;

// global values
if (key.includes('commerce.headers.all.')) {
herzog31 marked this conversation as resolved.
Show resolved Hide resolved
key = key.replace('commerce.headers.all.', '');
}

// scoped values
if (key.includes(`commerce.headers.${scope}.`)) {
key = key.replace(`commerce.headers.${scope}.`, '');
}

return { ...obj, [key]: item.value };
}, {});
};
Expand Down
2 changes: 1 addition & 1 deletion scripts/initializers/pdp.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable import/no-cycle */
/* eslint-disable import/prefer-default-export */
/* eslint import/no-cycle: [2, { maxDepth: 1 }] */

import { initializers } from '@dropins/tools/initializer.js';
import { Image, provider as UI } from '@dropins/tools/components.js';
Expand Down
40 changes: 40 additions & 0 deletions scripts/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export function decorateMain(main) {
buildAutoBlocks(main);
decorateSections(main);
decorateBlocks(main);
decorateLinks(main);
}

function preloadFile(href, as) {
Expand Down Expand Up @@ -356,6 +357,45 @@ export async function fetchIndex(indexFile, pageSize = 500) {
return newIndex;
}

/**
* Get root path
*/
export function getRootPath() {
window.ROOT_PATH = window.rootPath || getMetadata('root') || '/';
fnhipster marked this conversation as resolved.
Show resolved Hide resolved
return window.ROOT_PATH;
}

/**
* Decorates links.
* @param {Element} main The main element
*/
export function decorateLinks(main) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be needed once the content was updated accordingly. There shouldn't be any links in the content that point to a URL that does not include the root.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about links added to the document? How would those be relative to the root defined?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You would link to a document like /us/en/welcome.docx, so it matches the actual content structure.

Copy link
Collaborator Author

@fnhipster fnhipster Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. @anthoula, can you try removing decorateLinks? Document links, such as those in the nav fragment, should be updated and localized.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decorateLinks is now disabled for the default experience. Document links for the en and en_us language folders now have localized paths that match the content structure.

const root = getRootPath();
if (root === '/') return;
const links = main.querySelectorAll('a');

links.forEach((link) => {
if (link.href.startsWith('//' || link.href.startsWith(root))) return;
fnhipster marked this conversation as resolved.
Show resolved Hide resolved

if (
link.href.startsWith('/')
|| link.href.startsWith(window.location.origin)
) {
const url = new URL(link.href, window.location.origin);
link.href = `${root}${url.pathname.substring(1)}${url.search}${url.hash}`;
}
});
}

/**
* Decorates links.
* @param {string} [url] url to be localized
*/
export function localizeLink(link) {
const root = getRootPath().replace(/\/$/, '');
return `${root}${link}`;
}

/**
* Check if consent was given for a specific topic.
* @param {*} topic Topic identifier
Expand Down