Skip to content

Commit

Permalink
Implemented MVP for reading URL query params as strings in the root c…
Browse files Browse the repository at this point in the history
…omponent (#428)
  • Loading branch information
calebjacob authored May 1, 2024
1 parent ace51a0 commit 2576206
Show file tree
Hide file tree
Showing 18 changed files with 135 additions and 19 deletions.
1 change: 1 addition & 0 deletions apps/sandbox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"react-dom": "^18"
},
"devDependencies": {
"@bos-web-engine/common": "workspace:*",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
Expand Down
27 changes: 27 additions & 0 deletions apps/sandbox/src/hooks/useQueryParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { QueryParams } from '@bos-web-engine/common';
import { useSearchParams } from 'next/navigation';
import { useEffect, useState } from 'react';

export function useQueryParams() {
const searchParams = useSearchParams();
const [queryParams, setQueryParams] = useState<QueryParams>({});

useEffect(() => {
/*
This pattern gives us a more stable reference for queryParams to reduce
re-renders. We only update our state when searchParams changes.
*/

const params: QueryParams = {};

searchParams.forEach((value, key) => {
params[key] = value;
});

setQueryParams(params);
}, [searchParams]);

return {
queryParams,
};
}
8 changes: 7 additions & 1 deletion apps/sandbox/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { Sandbox } from '@bos-web-engine/sandbox';

import { useQueryParams } from '@/hooks/useQueryParams';
import s from '@/styles/home.module.css';

export default function Home() {
const { queryParams } = useQueryParams();

return (
<div className={s.wrapper}>
<Sandbox height="calc(100vh - var(--gateway-header-height))" />
<Sandbox
height="calc(100vh - var(--gateway-header-height))"
queryParams={queryParams}
/>
</div>
);
}
5 changes: 5 additions & 0 deletions apps/web/src/components/WebEngineVariants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useHotReload } from '@bos-web-engine/hot-reload-client';
import { AccountState } from '@near-wallet-selector/core';
import { useCallback, useEffect, useState } from 'react';

import { useQueryParams } from '@/hooks/useQueryParams';
import { useComponentSourcesStore } from '@/stores/component-sources';
import { useContainerMessagesStore } from '@/stores/container-messages';
import { LocalFetchStatus, useDevToolsStore } from '@/stores/dev-tools';
Expand All @@ -25,6 +26,7 @@ export function WebEngine({
rootComponentPath,
flags,
}: WebEnginePropsVariantProps) {
const { queryParams } = useQueryParams();
const addSource = useComponentSourcesStore((store) => store.addSource);
const addMessage = useContainerMessagesStore((store) => store.addMessage);

Expand All @@ -41,6 +43,7 @@ export function WebEngine({
},
},
rootComponentPath,
queryParams,
});

return (
Expand Down Expand Up @@ -131,6 +134,7 @@ function PreparedLocalSandbox({
flags,
localComponents,
}: WebEnginePropsVariantProps & { localComponents: any }) {
const { queryParams } = useQueryParams();
const addSource = useComponentSourcesStore((store) => store.addSource);
const addMessage = useContainerMessagesStore((store) => store.addMessage);

Expand All @@ -148,6 +152,7 @@ function PreparedLocalSandbox({
},
localComponents,
rootComponentPath,
queryParams,
});

return (
Expand Down
27 changes: 27 additions & 0 deletions apps/web/src/hooks/useQueryParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { QueryParams } from '@bos-web-engine/common';
import { useSearchParams } from 'next/navigation';
import { useEffect, useState } from 'react';

export function useQueryParams() {
const searchParams = useSearchParams();
const [queryParams, setQueryParams] = useState<QueryParams>({});

useEffect(() => {
/*
This pattern gives us a more stable reference for queryParams to reduce
re-renders. We only update our state when searchParams changes.
*/

const params: QueryParams = {};

searchParams.forEach((value, key) => {
params[key] = value;
});

setQueryParams(params);
}, [searchParams]);

return {
queryParams,
};
}
11 changes: 9 additions & 2 deletions packages/application/src/components/ComponentTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@ export default function ComponentTree({
.map(
([
componentId,
{ trust, props, componentSource, parentId, moduleImports },
{
trust,
props,
componentSource,
parentId,
moduleImports,
queryParams,
},
]) => (
/*
NOTE: Including currentUserAccountId as part of the key forces the entire tree
Expand All @@ -48,7 +55,7 @@ export default function ComponentTree({
id={getIframeId(componentId)}
trust={trust}
scriptSrc={componentSource}
componentProps={props}
componentProps={{ ...queryParams, ...props }}
parentContainerId={parentId}
moduleImports={moduleImports}
/>
Expand Down
39 changes: 26 additions & 13 deletions packages/application/src/hooks/useComponents.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ComponentCompilerResponse } from '@bos-web-engine/compiler';
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';

import { UseComponentsParams } from '../types';

Expand All @@ -15,6 +15,7 @@ export function useComponents({
compiler,
config,
rootComponentPath,
queryParams,
}: UseComponentsParams) {
const [components, setComponents] = useState<{ [key: string]: any }>({});
const [isValidRootComponentPath, setIsValidRootComponentPath] =
Expand Down Expand Up @@ -42,8 +43,6 @@ export function useComponents({
[components]
);

const hooks = { ...config?.hooks } || {};

useEffect(() => {
setIsValidRootComponentPath(
!!rootComponentPath &&
Expand All @@ -53,16 +52,22 @@ export function useComponents({
);
}, [rootComponentPath]);

hooks.componentRendered = (componentId: string) => {
config?.hooks?.componentRendered?.(componentId);
setComponents((currentComponents) => ({
...currentComponents,
[componentId]: {
...currentComponents[componentId],
renderCount: currentComponents?.[componentId]?.renderCount + 1 || 0,
},
}));
};
const hooks = useMemo(() => {
const result = { ...config?.hooks } || {};

result.componentRendered = (componentId: string) => {
config?.hooks?.componentRendered?.(componentId);
setComponents((currentComponents) => ({
...currentComponents,
[componentId]: {
...currentComponents[componentId],
renderCount: currentComponents?.[componentId]?.renderCount + 1 || 0,
},
}));
};

return result;
}, [config?.hooks]);

useEffect(() => {
if (!rootComponentPath || !isValidRootComponentPath || !compiler) {
Expand All @@ -78,6 +83,7 @@ export function useComponents({
containerStyles,
error: loadError,
importedModules,
queryParams,
} = data;

if (loadError) {
Expand All @@ -96,6 +102,7 @@ export function useComponents({
componentId,
componentSource,
moduleImports: importedModules,
queryParams,
};

if (!rootComponentSource && componentId === rootComponentPath) {
Expand All @@ -108,14 +115,20 @@ export function useComponents({
compiler.postMessage({
action: 'execute',
componentId: rootComponentPath,
queryParams,
});
}, [
addComponent,
appendStylesheet,
components,
hooks,
compiler,
rootComponentPath,
rootComponentSource,
error,
isValidRootComponentPath,
config?.flags?.bosLoaderUrl,
queryParams,
]);

return {
Expand Down
2 changes: 2 additions & 0 deletions packages/application/src/hooks/useWebEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { UseWebEngineParams } from '../types';
export function useWebEngine({
config,
rootComponentPath,
queryParams,
}: UseWebEngineParams) {
const { appendStylesheet } = useCss();
const compiler = useCompiler({ config });
Expand All @@ -16,6 +17,7 @@ export function useWebEngine({
compiler,
config,
rootComponentPath,
queryParams,
});

useComponentTree({
Expand Down
2 changes: 2 additions & 0 deletions packages/application/src/hooks/useWebEngineSandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export function useWebEngineSandbox({
localComponents,
config,
rootComponentPath,
queryParams,
}: UseWebEngineSandboxParams) {
const [nonce, setNonce] = useState('');

Expand All @@ -27,6 +28,7 @@ export function useWebEngineSandbox({
compiler,
config,
rootComponentPath,
queryParams,
});

const { domRoots } = useComponentTree({
Expand Down
2 changes: 2 additions & 0 deletions packages/application/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
ComponentChildMetadata,
ComponentTrust,
MessagePayload,
QueryParams,
SerializedArgs,
SerializedNode,
} from '@bos-web-engine/common';
Expand Down Expand Up @@ -119,6 +120,7 @@ export interface CompilerWorker extends Omit<Worker, 'postMessage'> {
export interface UseWebEngineParams {
config?: WebEngineConfiguration;
rootComponentPath?: string;
queryParams?: QueryParams;
}

export interface UseComponentsParams extends UseWebEngineParams {
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './plugins';
export * from './render';
export * from './serialization';
export * from './trust';
export * from './url';
1 change: 1 addition & 0 deletions packages/common/src/types/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type QueryParams = Record<string, string | undefined>;
4 changes: 3 additions & 1 deletion packages/compiler/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ export class ComponentCompiler {
* Build the source for a container rooted at the target Component
* @param componentId ID for the new container's root Component
*/
async compileComponent({ componentId }: CompilerExecuteAction) {
async compileComponent({ componentId, queryParams }: CompilerExecuteAction) {
// wait on CSS initialization
await this.cssParser.init();

Expand Down Expand Up @@ -299,6 +299,7 @@ export class ComponentCompiler {
rawSource: moduleEntry.component,
componentPath,
importedModules: retrievedData.importedModules,
queryParams,
});

return;
Expand Down Expand Up @@ -354,6 +355,7 @@ export class ComponentCompiler {
rawSource: moduleEntry.component,
componentPath,
importedModules,
queryParams,
});
}
}
4 changes: 3 additions & 1 deletion packages/compiler/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { BOSModule } from '@bos-web-engine/common';
import type { BOSModule, QueryParams } from '@bos-web-engine/common';
import type {
BLOCK_HEIGHT_KEY,
SOCIAL_COMPONENT_NAMESPACE,
Expand All @@ -12,6 +12,7 @@ export type ComponentCompilerRequest =
export interface CompilerExecuteAction {
action: 'execute';
componentId: string;
queryParams?: QueryParams;
}

export type LocalComponentMap = { [path: string]: BOSModule };
Expand All @@ -35,6 +36,7 @@ export interface ComponentCompilerResponse {
componentPath: string;
error?: Error;
importedModules: Map<string, string>;
queryParams?: QueryParams;
}

export type SendMessageCallback = (res: ComponentCompilerResponse) => void;
Expand Down
2 changes: 2 additions & 0 deletions packages/sandbox/src/components/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type WebEngineLocalComponents = { [path: string]: BOSModule };

export function Preview() {
const { account } = useWallet();
const queryParams = useSandboxStore((store) => store.queryParams);
const containerElement = useSandboxStore((store) => store.containerElement);
const activeFilePath = useSandboxStore((store) => store.activeFilePath);
const pinnedPreviewFilePath = useSandboxStore(
Expand All @@ -43,6 +44,7 @@ export function Preview() {
const { components, nonce } = useWebEngineSandbox({
localComponents,
rootComponentPath,
queryParams,
});

useEffect(() => {
Expand Down
9 changes: 8 additions & 1 deletion packages/sandbox/src/components/Sandbox.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { QueryParams } from '@bos-web-engine/common';
import { useEffect, useRef, useState } from 'react';

import { Layout } from './Layout';
Expand All @@ -8,13 +9,15 @@ import { useSourceAccountReplace } from '../hooks/useSourceAccountReplace';

type Props = {
height: string;
queryParams?: QueryParams;
};

export function Sandbox({ height }: Props) {
export function Sandbox({ height, queryParams }: Props) {
const containerRef = useRef<HTMLDivElement | null>(null);
const setContainerElement = useSandboxStore(
(store) => store.setContainerElement
);
const setQueryParams = useSandboxStore((store) => store.setQueryParams);
const [shouldRender, setShouldRender] = useState(false);

usePublishedFilesSync();
Expand All @@ -34,6 +37,10 @@ export function Sandbox({ height }: Props) {
}
});

useEffect(() => {
setQueryParams(queryParams);
}, [setQueryParams, queryParams]);

if (!shouldRender) return null;

return (
Expand Down
Loading

0 comments on commit 2576206

Please sign in to comment.