mirror of https://github.com/buster-so/buster.git
Optimize web app performance and memory usage with various improvements
Co-authored-by: natemkelley <natemkelley@gmail.com>
This commit is contained in:
parent
8987ca17a1
commit
567e1ae48c
|
@ -34,3 +34,25 @@ You can check out [the Next.js GitHub repository](https://github.com/vercel/next
|
|||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
|
||||
## Profiling memory and bundles
|
||||
|
||||
- Development without Turbopack (can reduce baseline RAM):
|
||||
|
||||
```bash
|
||||
pnpm --filter @buster-app/web dev:no-turbo
|
||||
```
|
||||
|
||||
- Start with Node inspector and higher old space to capture heap snapshots:
|
||||
|
||||
```bash
|
||||
pnpm --filter @buster-app/web build && pnpm --filter @buster-app/web start:inspect
|
||||
# open chrome://inspect and take heap snapshots at startup and after actions
|
||||
```
|
||||
|
||||
- Analyze client/server bundles:
|
||||
|
||||
```bash
|
||||
pnpm --filter @buster-app/web build:analyze
|
||||
# then open .next/analyze/client.html and server.html
|
||||
```
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "next dev --turbo",
|
||||
"dev:no-turbo": "NEXT_TELEMETRY_DISABLED=1 next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"start:inspect": "NODE_OPTIONS='--inspect --max-old-space-size=4096' next start",
|
||||
"build:analyze": "ANALYZE=true next build",
|
||||
"lint": "next lint && npx prettier --write . '!src/components/ui/icons/**' --log-level error",
|
||||
"lint:eslint": "eslint .",
|
||||
"lint:ci": "npm run lint && npm run typecheck",
|
||||
|
|
|
@ -16,7 +16,11 @@ import { configureMonacoToUseYaml } from './yamlHelper';
|
|||
//import NightOwnTheme from 'monaco-themes/themes/Night Owl.json';
|
||||
//https://github.com/brijeshb42/monaco-ace-tokenizer
|
||||
|
||||
import { Editor } from '@monaco-editor/react';
|
||||
import dynamic from 'next/dynamic';
|
||||
const Editor = dynamic(() => import('@monaco-editor/react').then((m) => m.Editor), {
|
||||
ssr: false,
|
||||
loading: () => null
|
||||
});
|
||||
import { useTheme } from 'next-themes';
|
||||
|
||||
interface AppCodeEditorProps {
|
||||
|
|
|
@ -72,12 +72,8 @@ export const getCodeTokens = async (
|
|||
});
|
||||
};
|
||||
|
||||
// Pre-initialize highlighter on module load for better performance
|
||||
if (typeof window !== 'undefined') {
|
||||
initializeHighlighter().catch((error) => {
|
||||
console.warn('Failed to pre-initialize syntax highlighter:', error);
|
||||
});
|
||||
}
|
||||
// Note: Do not pre-initialize on module load to keep initial memory low. Highlighter will
|
||||
// initialize on first use via getHighlightedCode/getCodeTokens.
|
||||
|
||||
export const getFallbackStyle = (isDarkMode: boolean) => {
|
||||
return {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { z } from 'zod';
|
||||
import { isServer } from '@tanstack/react-query';
|
||||
|
||||
if (!isServer) {
|
||||
// Ensure this file is only evaluated on the server
|
||||
if (typeof window !== 'undefined') {
|
||||
throw new Error('env.mjs is only meant to be used on the server');
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import type { UseSupabaseUserContextType } from '@/lib/supabase';
|
|||
import { BusterAssetsProvider } from './Assets/BusterAssetsProvider';
|
||||
import { AppLayoutProvider } from './BusterAppLayout';
|
||||
import { BusterReactQueryProvider } from './BusterReactQuery/BusterReactQueryAndApi';
|
||||
import { BusterWebSocketProvider } from './BusterWebSocket';
|
||||
import { BusterNewChatProvider } from './Chats';
|
||||
import { BusterPosthogProvider } from './Posthog';
|
||||
import { RoutePrefetcher } from './RoutePrefetcher';
|
||||
|
@ -24,6 +23,7 @@ export const AppProviders: React.FC<
|
|||
queryClient: QueryClient;
|
||||
}>
|
||||
> = ({ children, queryClient, supabaseContext }) => {
|
||||
const enableRoutePrefetch = process.env.NEXT_PUBLIC_ENABLE_ROUTE_PREFETCH !== 'false';
|
||||
return (
|
||||
<SupabaseContextProvider supabaseContext={supabaseContext}>
|
||||
<BusterReactQueryProvider>
|
||||
|
@ -33,7 +33,7 @@ export const AppProviders: React.FC<
|
|||
<BusterAssetsProvider>
|
||||
<BusterNewChatProvider>
|
||||
<BusterPosthogProvider>{children}</BusterPosthogProvider>
|
||||
<RoutePrefetcher />
|
||||
{enableRoutePrefetch && <RoutePrefetcher />}
|
||||
</BusterNewChatProvider>
|
||||
</BusterAssetsProvider>
|
||||
</BusterUserConfigProvider>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export const PREFETCH_STALE_TIME = 1000 * 10; // 10 seconds
|
||||
export const ERROR_RETRY_DELAY = 1 * 1000; // 1 second delay after error
|
||||
export const GC_TIME = 1000 * 60 * 60 * 24 * 3; // 24 hours - matches persistence duration
|
||||
// Reduce browser GC time to 30 minutes to lower memory residency
|
||||
export const GC_TIME = typeof window === 'undefined' ? 1000 * 60 * 60 * 24 * 3 : 1000 * 60 * 30;
|
||||
export const USER_CANCELLED_ERROR = new Error('User cancelled');
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import { isServer } from '@tanstack/react-query';
|
||||
import type { PostHogConfig } from 'posthog-js';
|
||||
import posthog from 'posthog-js';
|
||||
import { PostHogProvider } from 'posthog-js/react';
|
||||
import React, { type PropsWithChildren, useEffect } from 'react';
|
||||
import React, { type PropsWithChildren, useEffect, useMemo, useState } from 'react';
|
||||
import { isDev } from '@/config';
|
||||
import { useUserConfigContextSelector } from '../Users';
|
||||
import type { Team } from '@buster/server-shared/teams';
|
||||
|
@ -21,13 +17,10 @@ export const BusterPosthogProvider: React.FC<PropsWithChildren> = React.memo(({
|
|||
});
|
||||
BusterPosthogProvider.displayName = 'BusterPosthogProvider';
|
||||
|
||||
const options: Partial<PostHogConfig> = {
|
||||
const makeOptions = () => ({
|
||||
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||
person_profiles: 'always',
|
||||
session_recording: {
|
||||
recordBody: true
|
||||
},
|
||||
|
||||
session_recording: { recordBody: true },
|
||||
loaded: () => {
|
||||
console.log(
|
||||
'%c🚀 Welcome to Buster',
|
||||
|
@ -38,27 +31,37 @@ const options: Partial<PostHogConfig> = {
|
|||
'background: #6b21a8; color: white; font-size: 10px; font-weight: normal; padding: 8px; border-radius: 4px;'
|
||||
);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const PosthogWrapper: React.FC<PropsWithChildren> = ({ children }) => {
|
||||
const user = useUserConfigContextSelector((state) => state.user);
|
||||
const userTeams = useUserConfigContextSelector((state) => state.userTeams);
|
||||
const userOrganizations = useUserConfigContextSelector((state) => state.userOrganizations);
|
||||
const team: Team | undefined = userTeams?.[0];
|
||||
const [posthogApi, setPosthogApi] = useState<any | null>(null);
|
||||
const [Provider, setProvider] = useState<React.ComponentType<{ client: any }> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (POSTHOG_KEY && !isServer && user && posthog && team) {
|
||||
posthog.init(POSTHOG_KEY, options);
|
||||
|
||||
let mounted = true;
|
||||
(async () => {
|
||||
if (!POSTHOG_KEY || !user || !team) return;
|
||||
const [{ default: posthog }, { PostHogProvider }] = await Promise.all([
|
||||
import('posthog-js'),
|
||||
import('posthog-js/react')
|
||||
]);
|
||||
if (!mounted) return;
|
||||
posthog.init(POSTHOG_KEY, makeOptions());
|
||||
setPosthogApi(posthog);
|
||||
setProvider(() => PostHogProvider);
|
||||
const email = user.email;
|
||||
posthog.identify(email, {
|
||||
user,
|
||||
organization: userOrganizations,
|
||||
team
|
||||
});
|
||||
posthog.identify(email, { user, organization: userOrganizations, team });
|
||||
posthog.group(team?.id, team?.name);
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, [user?.id, team?.id]);
|
||||
|
||||
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
|
||||
if (!Provider || !posthogApi) return <>{children}</>;
|
||||
return <Provider client={posthogApi}>{children}</Provider>;
|
||||
};
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue