Skip to content

Commit

Permalink
Improve static rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
lemonmade committed Sep 20, 2024
1 parent 685df84 commit c57ebbd
Show file tree
Hide file tree
Showing 18 changed files with 475 additions and 280 deletions.
112 changes: 71 additions & 41 deletions app/server/graphql/resolvers/apps/ClipsExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ export const ClipsExtensionVersion = createResolverWithGid(
assets: ({scriptUrl}) => (scriptUrl ? [{source: scriptUrl}] : []),
translations: ({translations}) =>
translations ? JSON.stringify(translations) : null,
// Database needs to store the exact right shapes in its JSON fields
extends: ({extends: supports}) => (supports as any) ?? [],
settings: ({settings}) => (settings as any) ?? {fields: []},
},
Expand Down Expand Up @@ -435,13 +436,10 @@ export const ClipsExtensionInstallation = createResolverWithGid(

if (loading == null) return null;

const {parseLoadingHtml} = await import('@watching/tools/loading');

return {
ui: loading?.ui
? {
html: loading.ui,
tree: JSON.stringify(parseLoadingHtml(loading.ui)),
}
: null,
};
Expand Down Expand Up @@ -528,6 +526,30 @@ export const WatchThrough = createResolver('WatchThrough', {
},
});

async function parseExtensionPointTarget(extensionPoint: string) {
const {validateExtensionPoint} = await import('@watching/tools/extension');

if (!validateExtensionPoint(extensionPoint)) {
throw new Error(`Unsupported extension point: ${extensionPoint}`);
}

return extensionPoint;
}

async function parseLiveQuery(liveQuery: string) {
const {validateAndNormalizeLiveQuery} = await import(
'@watching/tools/extension'
);
return validateAndNormalizeLiveQuery(liveQuery);
}

async function parseLoadingUI(loadingUI: string) {
const {validateAndNormalizeLoadingUI} = await import(
'@watching/tools/extension'
);
return validateAndNormalizeLoadingUI(loadingUI);
}

async function createStagedClipsVersion({
code,
appId,
Expand Down Expand Up @@ -580,45 +602,53 @@ async function createStagedClipsVersion({
translations: translations && JSON.parse(translations),
extends: supports
? await Promise.all(
supports.map(async ({target, liveQuery, loading, conditions}) => {
return {
target,
liveQuery: liveQuery
? await (async () => {
const [
{parse},
{toGraphQLOperation, cleanGraphQLDocument},
] = await Promise.all([
import('graphql'),
import('@quilted/graphql-tools'),
]);

return toGraphQLOperation(
cleanGraphQLDocument(parse(liveQuery)),
).source;
})()
: undefined,
loading: loading?.ui
? {
ui: await (async () => {
const {parseLoadingHtml, serializeLoadingHtml} =
await import('@watching/tools/loading');

return serializeLoadingHtml(
parseLoadingHtml(loading.ui!),
);
})(),
supports.map(
async ({target, modules, liveQuery, loading, conditions}) => {
const [
parsedTarget,
parsedModules,
parsedLiveQuery,
parsedLoadingUI,
] = await Promise.all([
parseExtensionPointTarget(target),
Promise.all(
(modules ?? []).map(
async ({content, contentType = 'HTML'}) => {
if (content.length > 10_000) {
throw new Error(
`Clip module content for ${target} is too long`,
);
}

// TODO: validate HTML content

return {content, contentType};
},
),
),
liveQuery ? parseLiveQuery(liveQuery) : undefined,
loading?.ui ? parseLoadingUI(loading.ui) : undefined,
]);

return {
target: parsedTarget,
modules: parsedModules,
liveQuery: parsedLiveQuery,
loading: parsedLoadingUI
? {
ui: parsedLoadingUI,
}
: undefined,
conditions: conditions?.map((condition) => {
if (condition?.series?.handle == null) {
throw new Error(`Unknown condition: ${condition}`);
}
: undefined,
conditions: conditions?.map((condition) => {
if (condition?.series?.handle == null) {
throw new Error(`Unknown condition: ${condition}`);
}

return condition;
}),
};
}) as any,

return condition;
}),
};
},
) as any,
)
: [],
settings: settings?.fields
Expand Down
1 change: 0 additions & 1 deletion app/server/graphql/schema.d.ts.map

This file was deleted.

44 changes: 2 additions & 42 deletions app/shared/clips/Clip/Clip.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import type {ComponentType} from 'preact';
import {useEffect, useRef} from 'preact/hooks';

import {type ExtensionPoint} from '@watching/clips';
import {RemoteRootRenderer} from '@remote-dom/preact/host';
import {
Style,
Popover,
Stack,
InlineStack,
BlockStack,
InlineGrid,
View,
Expand All @@ -17,10 +14,6 @@ import {
Icon,
Action,
Section,
SkeletonAction,
SkeletonText,
SkeletonTextBlock,
SkeletonView,
} from '@lemon/zest';
import {classes} from '@lemon/css';
import type {ThreadRendererInstance} from '@watching/thread-render';
Expand All @@ -32,10 +25,10 @@ import {
type ClipsExtensionPoint,
type ClipsExtensionPointInstance,
type ClipsExtensionPointInstanceContext,
type ClipsExtensionPointInstanceLoadingElement,
} from '../extension.ts';

import {ClipSettings} from './ClipSettings.tsx';
import {ClipStaticRenderer} from './ClipStaticRenderer.tsx';

import styles from './Clip.module.css';
import uninstallClipsExtensionFromClipMutation from './graphql/UninstallClipsExtensionFromClipMutation.graphql';
Expand Down Expand Up @@ -215,16 +208,6 @@ function ClipInstanceRenderer<Point extends ExtensionPoint>({
);
}

const LOADING_COMPONENT_MAP = new Map<string, ComponentType<any>>([
['ui-stack', Stack],
['ui-block-stack', BlockStack],
['ui-inline-stack', InlineStack],
['ui-skeleton-action', SkeletonAction],
['ui-skeleton-text', SkeletonText],
['ui-skeleton-text-block', SkeletonTextBlock],
['ui-skeleton-view', SkeletonView],
]);

function ClipsInstanceRendererLoading<Point extends ExtensionPoint>({
instance,
}: {
Expand All @@ -234,28 +217,5 @@ function ClipsInstanceRendererLoading<Point extends ExtensionPoint>({

if (loadingUi == null) return null;

const renderNode = (
child: ClipsExtensionPointInstanceLoadingElement['children'][number],
index: number,
) => {
if (typeof child === 'string') {
return <>{child}</>;
}

const {type, properties, children} = child;

const Component = LOADING_COMPONENT_MAP.get(type);

if (Component == null) {
throw new Error(`Unknown loading component: ${type}`);
}

return (
<Component key={index} {...properties}>
{children.map(renderNode)}
</Component>
);
};

return <>{loadingUi.map(renderNode)}</>;
return <ClipStaticRenderer content={loadingUi} />;
}
Loading

0 comments on commit c57ebbd

Please sign in to comment.