diff --git a/apps/web/src/components/Inspector.tsx b/apps/web/src/components/Inspector.tsx index 9534bf58..f8b1ba20 100644 --- a/apps/web/src/components/Inspector.tsx +++ b/apps/web/src/components/Inspector.tsx @@ -232,6 +232,21 @@ export function Inspector() { }} /> +
+ + { + updateFlags({ + enableBlockHeightVersioning: e.target.checked, + }); + }} + /> +
diff --git a/packages/application/src/hooks/useCompiler.ts b/packages/application/src/hooks/useCompiler.ts index 1502a6a8..0869bd14 100644 --- a/packages/application/src/hooks/useCompiler.ts +++ b/packages/application/src/hooks/useCompiler.ts @@ -34,12 +34,14 @@ export function useCompiler({ action: 'init', localComponents, preactVersion: config.preactVersion, + enableBlockHeightVersioning: config.flags?.enableBlockHeightVersioning, }); }, [ compiler, config.flags?.bosLoaderUrl, config.preactVersion, localComponents, + config.flags?.enableBlockHeightVersioning, ]); return compiler; diff --git a/packages/application/src/hooks/useWebEngineSandbox.ts b/packages/application/src/hooks/useWebEngineSandbox.ts index 73269e8f..b97c3ad6 100644 --- a/packages/application/src/hooks/useWebEngineSandbox.ts +++ b/packages/application/src/hooks/useWebEngineSandbox.ts @@ -13,6 +13,7 @@ export function useWebEngineSandbox({ }: UseWebEngineSandboxParams) { const [nonce, setNonce] = useState(''); const preactVersion = config.preactVersion; + const enableBlockHeightVersioning = config.flags?.enableBlockHeightVersioning; const { appendStylesheet, resetContainerStylesheet } = useCss(); const compiler = useCompiler({ config, localComponents }); @@ -50,6 +51,7 @@ export function useWebEngineSandbox({ action: 'init', localComponents, preactVersion, + enableBlockHeightVersioning, }); compiler?.postMessage({ @@ -63,6 +65,7 @@ export function useWebEngineSandbox({ preactVersion, rootComponentPath, setComponents, + enableBlockHeightVersioning, ]); return { diff --git a/packages/application/src/types.ts b/packages/application/src/types.ts index 5f00bbde..b49e4459 100644 --- a/packages/application/src/types.ts +++ b/packages/application/src/types.ts @@ -147,4 +147,5 @@ export interface WebEngineConfiguration { export interface WebEngineFlags { bosLoaderUrl?: string; showContainerBoundaries?: boolean; + enableBlockHeightVersioning?: boolean; } diff --git a/packages/compiler/src/compiler.ts b/packages/compiler/src/compiler.ts index e8056319..d2561e9f 100644 --- a/packages/compiler/src/compiler.ts +++ b/packages/compiler/src/compiler.ts @@ -31,6 +31,7 @@ export class ComponentCompiler { private compiledSourceCache: Map; private readonly sendWorkerMessage: SendMessageCallback; private preactVersion?: string; + private enableBlockHeightVersioning?: boolean; private social: SocialDb; private readonly cssParser: CssParser; @@ -45,8 +46,13 @@ export class ComponentCompiler { }); } - init({ localComponents, preactVersion }: CompilerInitAction) { + init({ + localComponents, + preactVersion, + enableBlockHeightVersioning, + }: CompilerInitAction) { this.preactVersion = preactVersion; + this.enableBlockHeightVersioning = enableBlockHeightVersioning; this.bosSourceCache.clear(); this.compiledSourceCache.clear(); @@ -68,7 +74,11 @@ export class ComponentCompiler { (componentPath) => !this.bosSourceCache.has(componentPath) ); if (unfetchedPaths.length > 0) { - const pathsFetch = fetchComponentSources(this.social, unfetchedPaths); + const pathsFetch = fetchComponentSources( + this.social, + unfetchedPaths, + this.enableBlockHeightVersioning + ); unfetchedPaths.forEach((componentPath) => { this.bosSourceCache.set( componentPath, @@ -246,7 +256,15 @@ export class ComponentCompiler { // wait on CSS initialization await this.cssParser.init(); - const componentPath = componentId.split('##')[0]; + let [componentPath] = componentId.split('##'); + const [componentPathWithoutBlockHeight, blockHeight] = + componentPath.split('@'); + if (blockHeight && !this.enableBlockHeightVersioning) { + console.warn( + `${componentPath} has a block height specified, but the "enableBlockHeightVersioning" flag is disabled. The latest version of Component will be used.` + ); + componentPath = componentPathWithoutBlockHeight; + } const moduleEntry = await this.getComponentSources([componentPath]).get( componentPath ); diff --git a/packages/compiler/src/source.ts b/packages/compiler/src/source.ts index 0cb75a41..f4aa66a4 100644 --- a/packages/compiler/src/source.ts +++ b/packages/compiler/src/source.ts @@ -8,7 +8,8 @@ import { ComponentEntry } from './types'; export async function fetchComponentSources( social: SocialDb, - componentPaths: string[] + componentPaths: string[], + enableBlockHeightVersioning?: boolean ) { /* Typically, you'd want to pass a generic to `social.get()`. This generic @@ -25,15 +26,96 @@ export async function fetchComponentSources( }; }; - const keys = componentPaths.map( - (p) => p.split('/').join(`/${SOCIAL_COMPONENT_NAMESPACE}/`) + '/*' - ); + let aggregatedResponses; + + if (enableBlockHeightVersioning) { + /** + * Requested components mapped by the block heights to reduce the amount of social requests + * If no block height specified - the "" key is used + */ + const componentsByBlockHeight = componentPaths.reduce( + (pathsByBlockHeight, componentPath) => { + const [path, blockHeight] = componentPath.split('@'); + const blockHeightKey = blockHeight || ''; + + if (!pathsByBlockHeight[blockHeightKey]) { + pathsByBlockHeight[blockHeightKey] = []; + } + + pathsByBlockHeight[blockHeightKey].push( + path.split('/').join(`/${SOCIAL_COMPONENT_NAMESPACE}/`) + '/*' + ); + + return pathsByBlockHeight; + }, + {} as Record + ); + + const componentsByBlockHeightArr = Object.entries(componentsByBlockHeight); + + const responsesWithBlockHeight = await Promise.all( + componentsByBlockHeightArr.map(async ([blockId, keys]) => { + const response = (await social.get({ + keys, + blockId: Number(blockId), + })) as SocialComponentsByAuthor; + + if (!blockId) { + return response; + } + + return Object.fromEntries( + Object.entries(response).map( + ([author, { [SOCIAL_COMPONENT_NAMESPACE]: componentEntry }]) => [ + author, + { + [SOCIAL_COMPONENT_NAMESPACE]: Object.fromEntries( + Object.entries(componentEntry).map( + ([componentPath, componentSource]) => [ + `${componentPath}@${blockId}`, + componentSource, + ] + ) + ), + }, + ] + ) + ); + }) + ); + + aggregatedResponses = responsesWithBlockHeight.reduce( + (accumulator, response) => { + Object.entries(response).forEach( + ([author, { [SOCIAL_COMPONENT_NAMESPACE]: componentEntry }]) => { + if (accumulator[author]?.[SOCIAL_COMPONENT_NAMESPACE]) { + accumulator[author][SOCIAL_COMPONENT_NAMESPACE] = { + ...accumulator[author][SOCIAL_COMPONENT_NAMESPACE], + ...componentEntry, + }; + } else { + accumulator[author] = { + [SOCIAL_COMPONENT_NAMESPACE]: componentEntry, + }; + } + } + ); + + return accumulator; + }, + {} as SocialComponentsByAuthor + ); + } else { + const keys = componentPaths.map( + (p) => p.split('/').join(`/${SOCIAL_COMPONENT_NAMESPACE}/`) + '/*' + ); - const response = (await social.get({ - keys, - })) as SocialComponentsByAuthor; + aggregatedResponses = (await social.get({ + keys, + })) as SocialComponentsByAuthor; + } - return Object.entries(response).reduce( + return Object.entries(aggregatedResponses).reduce( (sources, [author, { [SOCIAL_COMPONENT_NAMESPACE]: componentEntry }]) => { Object.entries(componentEntry).forEach(([componentName, component]) => { if (component) { diff --git a/packages/compiler/src/transpile.ts b/packages/compiler/src/transpile.ts index 508b9b61..de326366 100644 --- a/packages/compiler/src/transpile.ts +++ b/packages/compiler/src/transpile.ts @@ -23,7 +23,7 @@ import type { ImportExpression, ModuleExport, ModuleImport } from './types'; /** * Derive a BOS Component path from a relative import - * @param componentPath poth of the Component importing another BOS Component via relative path + * @param componentPath path of the Component importing another BOS Component via relative path * @param componentImport import metadata for the relative import */ export function deriveComponentPath( diff --git a/packages/compiler/src/types.ts b/packages/compiler/src/types.ts index 64749305..43498e24 100644 --- a/packages/compiler/src/types.ts +++ b/packages/compiler/src/types.ts @@ -15,6 +15,7 @@ export interface CompilerInitAction { action: 'init'; localComponents?: LocalComponentMap; preactVersion: string; + enableBlockHeightVersioning?: boolean; } export interface ComponentCompilerResponse {