From 8fe636db51945300e143699d9f001f3a46bfe816 Mon Sep 17 00:00:00 2001 From: Raghav Sharma Date: Fri, 21 Feb 2025 11:50:20 +0530 Subject: [PATCH 1/6] load georoutingv2.json in parallel with georoutingv2.js --- libs/features/georoutingv2/georoutingv2.js | 36 ++++++++++------------ libs/utils/utils.js | 8 ++++- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/libs/features/georoutingv2/georoutingv2.js b/libs/features/georoutingv2/georoutingv2.js index 7213696f63..480e614e3e 100644 --- a/libs/features/georoutingv2/georoutingv2.js +++ b/libs/features/georoutingv2/georoutingv2.js @@ -271,6 +271,7 @@ export default async function loadGeoRouting( getMetadataFunc, loadBlockFunc, loadStyleFunc, + v2jsonPromise, ) { if (getGeoroutingOverride()) return; config = conf; @@ -279,25 +280,22 @@ export default async function loadGeoRouting( loadBlock = loadBlockFunc; loadStyle = loadStyleFunc; - const urls = [ - `${config.contentRoot ?? ''}/georoutingv2.json`, - `${config.contentRoot ?? ''}/georouting.json`, - `${getFederatedContentRoot()}/federal/georouting/georoutingv2.json`, - ]; - let resp; - for (const url of urls) { - resp = await fetch(url); - if (resp.ok) { - if (url.includes('georouting.json')) { - const json = await resp.json(); - // eslint-disable-next-line import/no-cycle - const { default: loadGeoRoutingOld } = await import('../georouting/georouting.js'); - loadGeoRoutingOld(config, createTag, getMetadata, json); - } - break; - } - } - const json = await resp.json(); + const loadOldGeorouting = async (json) => { + const { default: loadGeoRoutingOld } = await import('../georouting/georouting.js'); + await loadGeoRoutingOld(config, createTag, getMetadata, json); + return 'use-old-georouting'; + }; + const oldGeorouting = () => fetch(`${config.contentRoot ?? ''}/georouting.json`) + .then((r) => r.json()) + .then(loadOldGeorouting) + .catch(() => null); + const federatedJSON = () => fetch(`${getFederatedContentRoot()}/federal/georouting/georoutingv2.json`) + .then((r) => r.json()) + .catch(() => null); + + const json = (await v2jsonPromise) ?? (await oldGeorouting()) ?? (await federatedJSON()); + if (json === 'use-old-georouting') return; + const { locale } = config; const urlLocale = locale.prefix.replace('/', ''); diff --git a/libs/utils/utils.js b/libs/utils/utils.js index 63411d2291..00a6c497ff 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1190,10 +1190,16 @@ async function loadPostLCP(config) { if (enablePersonalizationV2() && !isMartechLoaded) loadMartech(); } else if (!isMartechLoaded) loadMartech(); + performance.mark('georouting-start'); const georouting = getMetadata('georouting') || config.geoRouting; if (georouting === 'on') { + const jsonPromise = fetch(`${config.contentRoot ?? ''}/georoutingv2.json`) + .then((r) => r.json()) + .catch(() => null); const { default: loadGeoRouting } = await import('../features/georoutingv2/georoutingv2.js'); - await loadGeoRouting(config, createTag, getMetadata, loadBlock, loadStyle); + await loadGeoRouting(config, createTag, getMetadata, loadBlock, loadStyle, jsonPromise); + performance.mark('georouting-end'); + console.log(performance.measure('georouting', 'georouting-start', 'georouting-end')); } const header = document.querySelector('header'); if (header) { From 5312882dca39b9bdd70055531a5a3aa5c7665f38 Mon Sep 17 00:00:00 2001 From: Raghav Sharma Date: Fri, 21 Feb 2025 12:09:14 +0530 Subject: [PATCH 2/6] remove performance marks --- libs/utils/utils.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/libs/utils/utils.js b/libs/utils/utils.js index 00a6c497ff..65ba4c26a8 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1190,7 +1190,6 @@ async function loadPostLCP(config) { if (enablePersonalizationV2() && !isMartechLoaded) loadMartech(); } else if (!isMartechLoaded) loadMartech(); - performance.mark('georouting-start'); const georouting = getMetadata('georouting') || config.geoRouting; if (georouting === 'on') { const jsonPromise = fetch(`${config.contentRoot ?? ''}/georoutingv2.json`) @@ -1198,8 +1197,6 @@ async function loadPostLCP(config) { .catch(() => null); const { default: loadGeoRouting } = await import('../features/georoutingv2/georoutingv2.js'); await loadGeoRouting(config, createTag, getMetadata, loadBlock, loadStyle, jsonPromise); - performance.mark('georouting-end'); - console.log(performance.measure('georouting', 'georouting-start', 'georouting-end')); } const header = document.querySelector('header'); if (header) { From 4629c38df5818bfd97780ae605dc6ca7ac51df88 Mon Sep 17 00:00:00 2001 From: Raghav Sharma Date: Fri, 21 Feb 2025 12:09:42 +0530 Subject: [PATCH 3/6] fixed unit tests --- .../georoutingv2/georoutingv2.test.js | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/test/features/georoutingv2/georoutingv2.test.js b/test/features/georoutingv2/georoutingv2.test.js index bab9b39c14..ebf970a334 100644 --- a/test/features/georoutingv2/georoutingv2.test.js +++ b/test/features/georoutingv2/georoutingv2.test.js @@ -204,6 +204,10 @@ const ogInnerHeight = window.innerHeight; const ogFetch = window.fetch; window.fetch = stub(); +const v2JSONPromise = () => fetch('/georoutingv2.json') + .then((r) => r.json()) + .catch(() => null); + function stubHeadRequestToReturnVal(prefix, val) { const path = window.location.href.replace(`${window.location.origin}`, ''); window.fetch.withArgs(`${prefix}${path}`, { method: 'HEAD' }).returns( @@ -305,7 +309,7 @@ describe('GeoRouting', () => { it('Does create a modal if detected country from IP is CH and url prefix is US', async () => { // prepare - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.not.be.null; @@ -315,7 +319,7 @@ describe('GeoRouting', () => { // prepare setUserCountryFromIP('US'); document.cookie = 'international=us;path=/;'; - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.be.null; @@ -326,7 +330,7 @@ describe('GeoRouting', () => { it('Shows no modal if aiming for CH page and IP in Switzerland', async () => { // prepare mockConfig.locale.prefix = 'ch_de'; - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.be.null; @@ -336,7 +340,7 @@ describe('GeoRouting', () => { it('If aiming for US page but IP in Switzerland shows CH links and US continue', async () => { // prepare - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.not.be.null; @@ -368,7 +372,7 @@ describe('GeoRouting', () => { it('If aiming for US page but IP in Egypt arabic content in geo routing modal is in rtl', async () => { // prepare setUserCountryFromIP('EG'); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.not.be.null; @@ -388,7 +392,7 @@ describe('GeoRouting', () => { it('If aiming for US page but IP in Egypt english content in geo routing modal is in ltr', async () => { // prepare setUserCountryFromIP('EG'); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.not.be.null; @@ -409,7 +413,7 @@ describe('GeoRouting', () => { // prepare mockConfig.locale.prefix = 'eg_ar'; setUserCountryFromIP('US'); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); const wrapper = document.querySelector('.georouting-wrapper'); // assert @@ -426,7 +430,7 @@ describe('GeoRouting', () => { mockConfig.locale.prefix = '/ch_fr'; setUserCountryFromIP('US'); document.cookie = 'international=de;path=/;'; - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const wrapper = document.querySelector('.georouting-wrapper'); // assert const swissFrenchData = mockGeoroutingJson.georouting.data.find((d) => d.prefix === 'ch_fr'); @@ -444,7 +448,7 @@ describe('GeoRouting', () => { // prepare mockConfig.locale.prefix = 'mena_en'; setUserCountryFromIP('BW'); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const wrapper = document.querySelector('.georouting-wrapper'); // assert const tabs = wrapper.querySelectorAll('.tabpanel'); @@ -465,7 +469,7 @@ describe('GeoRouting', () => { mockConfig.locale.prefix = 'mena_en'; setUserCountryFromIP('BW'); document.cookie = 'international=ch_de;path=/'; - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const wrapper = document.querySelector('.georouting-wrapper'); // assert const tabs = wrapper.querySelectorAll('.tabpanel'); @@ -485,7 +489,7 @@ describe('GeoRouting', () => { // prepare mockConfig.locale.prefix = 'ch_de'; document.cookie = 'international=ch_fr;path=/;'; - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert mockConfig.locale.prefix = ''; @@ -495,7 +499,7 @@ describe('GeoRouting', () => { it('If IP is from an unknown country no modal is show', async () => { // prepare setUserCountryFromIP('NOEXIST'); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.be.null; @@ -507,7 +511,7 @@ describe('GeoRouting', () => { // prepare stubFallbackMetadata('off'); stubHeadRequestToReturnVal('/ch_it', false); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert const tabs = modal.querySelectorAll('.tabpanel'); @@ -534,7 +538,7 @@ describe('GeoRouting', () => { it('Will show fallback links if fallbackrouting is on and page exist request fails', async () => { // prepare stubHeadRequestToReturnVal('/ch_it', false); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.not.be.null; @@ -550,7 +554,7 @@ describe('GeoRouting', () => { stubHeadRequestToReturnVal('/ch_de', false); stubHeadRequestToReturnVal('/ch_it', false); stubHeadRequestToReturnVal('/ch_fr', false); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.be.null; @@ -562,7 +566,7 @@ describe('GeoRouting', () => { }); it('Closes picker if picker open and then clicking somewhere else within the modal', async () => { - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); const cookie = getCookie('international'); // assert @@ -583,7 +587,7 @@ describe('GeoRouting', () => { it('Add class .top to picker when there is no space to render below the trigger button', async () => { await setViewport({ width: 600, height: 100 }); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); const links = modal.querySelectorAll('a'); links[0].click(); @@ -594,7 +598,7 @@ describe('GeoRouting', () => { it('Sets international and georouting_presented cookies on link click in modal', async () => { // prepare - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); const cookie = getCookie('international'); // assert @@ -610,7 +614,7 @@ describe('GeoRouting', () => { it('Does not open georouting modal if georouting hide is active', async () => { // prepare setGeorouting('off'); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); // assert expect(modal).to.be.null; @@ -622,7 +626,7 @@ describe('GeoRouting', () => { stubFetchForGeorouting(false); stubFetchForGeoroutingOld(false); stubFetchForFederalGeorouting(); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); expect(modal).to.not.be.null; }); @@ -630,7 +634,7 @@ describe('GeoRouting', () => { it('Will load old georouting modal if georoutingv2 is not found', async () => { stubFetchForGeorouting(false); stubFetchForGeoroutingOld(true); - await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle); + await init(mockConfig, createTag, getMetadata, loadBlock, loadStyle, v2JSONPromise()); const modal = document.querySelector('.dialog-modal'); expect(modal).to.not.be.null; }); From cb338ee13051cf2817c21f9bbe68ab7ecb160cc6 Mon Sep 17 00:00:00 2001 From: Raghav Sharma Date: Thu, 27 Feb 2025 14:46:06 +0530 Subject: [PATCH 4/6] Small refactoring --- libs/features/georoutingv2/georoutingv2.js | 13 +++++++++---- libs/utils/utils.js | 4 +--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libs/features/georoutingv2/georoutingv2.js b/libs/features/georoutingv2/georoutingv2.js index a1360d7956..e95b76bc91 100644 --- a/libs/features/georoutingv2/georoutingv2.js +++ b/libs/features/georoutingv2/georoutingv2.js @@ -1,5 +1,7 @@ import { getFederatedContentRoot } from '../../utils/utils.js'; +const OLD_GEOROUTING = 'oldgeorouting'; + let config; let createTag; let getMetadata; @@ -271,7 +273,7 @@ export default async function loadGeoRouting( getMetadataFunc, loadBlockFunc, loadStyleFunc, - v2jsonPromise, + v2jsonPromise = import(`${conf.contentRoot ?? ''}/georoutingv2.json`), ) { if (getGeoroutingOverride()) return; config = conf; @@ -280,10 +282,13 @@ export default async function loadGeoRouting( loadBlock = loadBlockFunc; loadStyle = loadStyleFunc; + const v2JSON = v2jsonPromise + .then((r) => r.json()) + .catch(() => null); const loadOldGeorouting = async (json) => { const { default: loadGeoRoutingOld } = await import('../georouting/georouting.js'); await loadGeoRoutingOld(config, createTag, getMetadata, json); - return 'use-old-georouting'; + return OLD_GEOROUTING; }; const oldGeorouting = () => fetch(`${config.contentRoot ?? ''}/georouting.json`) .then((r) => r.json()) @@ -293,8 +298,8 @@ export default async function loadGeoRouting( .then((r) => r.json()) .catch(() => null); - const json = (await v2jsonPromise) ?? (await oldGeorouting()) ?? (await federatedJSON()); - if (json === 'use-old-georouting') return; + const json = (await v2JSON) ?? (await oldGeorouting()) ?? (await federatedJSON()); + if (json === OLD_GEOROUTING) return; const { locale } = config; diff --git a/libs/utils/utils.js b/libs/utils/utils.js index 7f650b035f..4ae4a23c30 100644 --- a/libs/utils/utils.js +++ b/libs/utils/utils.js @@ -1250,9 +1250,7 @@ async function loadPostLCP(config) { const georouting = getMetadata('georouting') || config.geoRouting; if (georouting === 'on') { - const jsonPromise = fetch(`${config.contentRoot ?? ''}/georoutingv2.json`) - .then((r) => r.json()) - .catch(() => null); + const jsonPromise = fetch(`${config.contentRoot ?? ''}/georoutingv2.json`); const { default: loadGeoRouting } = await import('../features/georoutingv2/georoutingv2.js'); await loadGeoRouting(config, createTag, getMetadata, loadBlock, loadStyle, jsonPromise); } From 540339bbf082b5734ba8cf06e5761079ef23a2d4 Mon Sep 17 00:00:00 2001 From: Raghav Sharma Date: Thu, 27 Feb 2025 14:55:29 +0530 Subject: [PATCH 5/6] fallback for the jsonPromise --- libs/features/georoutingv2/georoutingv2.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/features/georoutingv2/georoutingv2.js b/libs/features/georoutingv2/georoutingv2.js index e95b76bc91..d6c0ad8683 100644 --- a/libs/features/georoutingv2/georoutingv2.js +++ b/libs/features/georoutingv2/georoutingv2.js @@ -273,7 +273,7 @@ export default async function loadGeoRouting( getMetadataFunc, loadBlockFunc, loadStyleFunc, - v2jsonPromise = import(`${conf.contentRoot ?? ''}/georoutingv2.json`), + v2jsonPromise = null, ) { if (getGeoroutingOverride()) return; config = conf; @@ -282,7 +282,7 @@ export default async function loadGeoRouting( loadBlock = loadBlockFunc; loadStyle = loadStyleFunc; - const v2JSON = v2jsonPromise + const v2JSON = (v2jsonPromise ?? import(`${conf.contentRoot ?? ''}/georoutingv2.json`)) .then((r) => r.json()) .catch(() => null); const loadOldGeorouting = async (json) => { From f29227f044b2a9af83f979a13ae1593b34e48cc4 Mon Sep 17 00:00:00 2001 From: Raghav Sharma Date: Thu, 27 Feb 2025 15:05:28 +0530 Subject: [PATCH 6/6] fix unit tests --- test/features/georoutingv2/georoutingv2.test.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/features/georoutingv2/georoutingv2.test.js b/test/features/georoutingv2/georoutingv2.test.js index b8fda88cde..ba831e875d 100644 --- a/test/features/georoutingv2/georoutingv2.test.js +++ b/test/features/georoutingv2/georoutingv2.test.js @@ -203,9 +203,7 @@ const ogInnerHeight = window.innerHeight; const ogFetch = window.fetch; window.fetch = stub(); -const v2JSONPromise = () => fetch('/georoutingv2.json') - .then((r) => r.json()) - .catch(() => null); +const v2JSONPromise = () => fetch('/georoutingv2.json'); function stubHeadRequestToReturnVal(prefix, val) { const path = window.location.href.replace(`${window.location.origin}`, '');