Skip to content

Commit

Permalink
Avoid top level await to fix execution and full module initialization…
Browse files Browse the repository at this point in the history
… race condition
  • Loading branch information
Andarist committed Jan 21, 2025
1 parent cd66283 commit 11df75d
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 34 deletions.
17 changes: 12 additions & 5 deletions app/components/chat/Artifact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,24 @@ import { workbenchStore } from '~/lib/stores/workbench';
import { classNames } from '~/utils/classNames';
import { cubicEasingFn } from '~/utils/easings';
import { WORK_DIR } from '~/utils/constants';
import { createAsyncSuspenseValue } from '~/lib/asyncSuspenseValue';

const highlighterOptions = {
langs: ['shell'],
themes: ['light-plus', 'dark-plus'],
};

const shellHighlighter: HighlighterGeneric<BundledLanguage, BundledTheme> =
import.meta.hot?.data.shellHighlighter ?? (await createHighlighter(highlighterOptions));
const shellHighlighter = createAsyncSuspenseValue(async () => {
const shellHighlighterPromise: Promise<HighlighterGeneric<BundledLanguage, BundledTheme>> =
import.meta.hot?.data.shellHighlighterPromise ?? createHighlighter(highlighterOptions);
if (import.meta.hot) {
import.meta.hot.data.shellHighlighterPromise = shellHighlighterPromise;
}
return shellHighlighterPromise;
});

if (import.meta.hot) {
import.meta.hot.data.shellHighlighter = shellHighlighter;
if (typeof document !== 'undefined') {
shellHighlighter.preload();
}

interface ArtifactProps {
Expand Down Expand Up @@ -134,7 +141,7 @@ function ShellCodeBlock({ classsName, code }: ShellCodeBlockProps) {
<div
className={classNames('text-xs', classsName)}
dangerouslySetInnerHTML={{
__html: shellHighlighter.codeToHtml(code, {
__html: shellHighlighter.read().codeToHtml(code, {
lang: 'shell',
theme: 'dark-plus',
}),
Expand Down
65 changes: 36 additions & 29 deletions app/components/chat/Messages.client.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Message } from 'ai';
import React, { useState } from 'react';
import React, { Suspense, useState } from 'react';
import { classNames } from '~/utils/classNames';
import { AssistantMessage, getAnnotationsTokensUsage } from './AssistantMessage';
import { UserMessage } from './UserMessage';
Expand All @@ -8,7 +8,7 @@ import { db, chatId } from '~/lib/persistence/useChatHistory';
import { forkChat } from '~/lib/persistence/db';
import { toast } from 'react-toastify';
import WithTooltip from '~/components/ui/Tooltip';
import { assert, sendCommandDedicatedClient } from "~/lib/replay/ReplayProtocolClient";
import { assert, sendCommandDedicatedClient } from '~/lib/replay/ReplayProtocolClient';

interface MessagesProps {
id?: string;
Expand Down Expand Up @@ -64,35 +64,42 @@ export const Messages = React.forwardRef<HTMLDivElement, MessagesProps>((props:
'mt-4': !isFirst,
})}
>
{isUserMessage && (
<div className="flex items-center justify-center w-[34px] h-[34px] overflow-hidden bg-white text-gray-600 rounded-full shrink-0 self-start">
<div className="i-ph:user-fill text-xl"></div>
</div>
)}
<div className="grid grid-col-1 w-full">
{isUserMessage ? (
<UserMessage content={content} />
) : (
<AssistantMessage content={content} annotations={message.annotations} />
<Suspense
fallback={
// TODO: this fallback could be improved
<div className="text-center w-full text-bolt-elements-textSecondary i-svg-spinners:3-dots-fade text-4xl mt-4"></div>
}
>
{isUserMessage && (
<div className="flex items-center justify-center w-[34px] h-[34px] overflow-hidden bg-white text-gray-600 rounded-full shrink-0 self-start">
<div className="i-ph:user-fill text-xl"></div>
</div>
)}
</div>
{!isUserMessage && messageId && getLastMessageProjectContents(index) && EnableRewindButton && (
<div className="flex gap-2 flex-col lg:flex-row">
<WithTooltip tooltip="Rewind to this message">
<button
onClick={() => {
const contents = getLastMessageProjectContents(index);
assert(contents);
}}
key="i-ph:arrow-u-up-left"
className={classNames(
'i-ph:arrow-u-up-left',
'text-xl text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary transition-colors',
)}
/>
</WithTooltip>
<div className="grid grid-col-1 w-full">
{isUserMessage ? (
<UserMessage content={content} />
) : (
<AssistantMessage content={content} annotations={message.annotations} />
)}
</div>
)}
{!isUserMessage && messageId && getLastMessageProjectContents(index) && EnableRewindButton && (
<div className="flex gap-2 flex-col lg:flex-row">
<WithTooltip tooltip="Rewind to this message">
<button
onClick={() => {
const contents = getLastMessageProjectContents(index);
assert(contents);
}}
key="i-ph:arrow-u-up-left"
className={classNames(
'i-ph:arrow-u-up-left',
'text-xl text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary transition-colors',
)}
/>
</WithTooltip>
</div>
)}
</Suspense>
</div>
);
})
Expand Down
58 changes: 58 additions & 0 deletions app/lib/asyncSuspenseValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
type SuspenseRecord<T> =
| {
status: 'resolved';
value: T;
}
| {
status: 'rejected';
error: Error;
}
| {
status: 'pending';
promise: Promise<T>;
};

export function createAsyncSuspenseValue<T>(getValue: () => Promise<T>) {
let record: SuspenseRecord<T> | undefined;

const load = () => {
const promise = getValue().then(
(value) => {
record = { status: 'resolved', value };
return value;
},
(error) => {
record = { status: 'rejected', error };
throw error;
},
);

record = { status: 'pending', promise };
return promise;
};

const asyncValue = {
read() {
if (!record) {
throw load();
}

switch (record.status) {
case 'pending':
throw record.promise;
case 'resolved':
return record.value;
case 'rejected':
throw record.error;
}
},
preload() {
if (record) {
return;
}
load().catch(() => {});
},
};

return asyncValue;
}

0 comments on commit 11df75d

Please sign in to comment.