Skip to content

Commit

Permalink
Add block height versioning (#377)
Browse files Browse the repository at this point in the history
* Add block height versioning proposal

* Fix format issues

* Refactor the responses with the block height

* Add enableBlockHeightVersioning feature flag

* Display a warning in the console if there is block height but no feature flag
  • Loading branch information
pavelisnear authored Mar 21, 2024
1 parent dcb3975 commit 07226ef
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 12 deletions.
15 changes: 15 additions & 0 deletions apps/web/src/components/Inspector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,21 @@ export function Inspector() {
}}
/>
</div>
<div className={s.flag}>
<label htmlFor="blockHeight">
Enable block height versioning
</label>
<input
type="checkbox"
id="blockHeight"
checked={flags?.enableBlockHeightVersioning}
onChange={(e) => {
updateFlags({
enableBlockHeightVersioning: e.target.checked,
});
}}
/>
</div>
</div>
</Tabs.Content>
</Tabs.Root>
Expand Down
2 changes: 2 additions & 0 deletions packages/application/src/hooks/useCompiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions packages/application/src/hooks/useWebEngineSandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down Expand Up @@ -50,6 +51,7 @@ export function useWebEngineSandbox({
action: 'init',
localComponents,
preactVersion,
enableBlockHeightVersioning,
});

compiler?.postMessage({
Expand All @@ -63,6 +65,7 @@ export function useWebEngineSandbox({
preactVersion,
rootComponentPath,
setComponents,
enableBlockHeightVersioning,
]);

return {
Expand Down
1 change: 1 addition & 0 deletions packages/application/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,5 @@ export interface WebEngineConfiguration {
export interface WebEngineFlags {
bosLoaderUrl?: string;
showContainerBoundaries?: boolean;
enableBlockHeightVersioning?: boolean;
}
24 changes: 21 additions & 3 deletions packages/compiler/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class ComponentCompiler {
private compiledSourceCache: Map<string, TranspiledCacheEntry | null>;
private readonly sendWorkerMessage: SendMessageCallback;
private preactVersion?: string;
private enableBlockHeightVersioning?: boolean;
private social: SocialDb;
private readonly cssParser: CssParser;

Expand All @@ -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();
Expand All @@ -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,
Expand Down Expand Up @@ -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
);
Expand Down
98 changes: 90 additions & 8 deletions packages/compiler/src/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<MyType>()`. This generic
Expand All @@ -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<string, string[]>
);

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) {
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler/src/transpile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions packages/compiler/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface CompilerInitAction {
action: 'init';
localComponents?: LocalComponentMap;
preactVersion: string;
enableBlockHeightVersioning?: boolean;
}

export interface ComponentCompilerResponse {
Expand Down

0 comments on commit 07226ef

Please sign in to comment.