mirror of
https://github.com/getAsterisk/claudia.git
synced 2025-07-07 18:15:00 +00:00
refactor(ui): improve message visibility filtering and optimize bundle
- Refactor message filtering logic across AgentExecution, ClaudeCodeSession, SessionOutputViewer, and StreamMessage components to better handle visibility of user messages with tool results - Replace inefficient every() loop with for-loop for better performance when checking message content visibility - Add renderedSomething tracking in StreamMessage to prevent rendering empty components - Optimize SessionOutputViewer with useMemo for displayableMessages filtering - Remove unused GitHub API response fields (url, html_url, git_url) in Rust agents command - Add Vite build configuration with manual code splitting for better bundle optimization - Remove TypeScript expect-error comment for process global variable These changes improve UI performance by reducing unnecessary re-renders and bundle size through better code splitting.
This commit is contained in:
parent
e0a0ddf6ba
commit
5d69b449be
6 changed files with 176 additions and 88 deletions
|
@ -1952,9 +1952,6 @@ struct GitHubApiResponse {
|
|||
path: String,
|
||||
sha: String,
|
||||
size: i64,
|
||||
url: String,
|
||||
html_url: String,
|
||||
git_url: String,
|
||||
download_url: Option<String>,
|
||||
#[serde(rename = "type")]
|
||||
file_type: String,
|
||||
|
|
|
@ -103,45 +103,54 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
|
|||
|
||||
// Skip empty user messages
|
||||
if (message.type === "user" && message.message) {
|
||||
if (message.isMeta) return false;
|
||||
|
||||
const msg = message.message;
|
||||
if (!msg.content || (Array.isArray(msg.content) && msg.content.length === 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this is a user message with only tool results that are already displayed
|
||||
// Check if user message has visible content by checking its parts
|
||||
if (Array.isArray(msg.content)) {
|
||||
const hasOnlyHiddenToolResults = msg.content.every((content: any) => {
|
||||
if (content.type !== "tool_result") return false;
|
||||
|
||||
// Check if this tool result should be hidden
|
||||
let hasCorrespondingWidget = false;
|
||||
if (content.tool_use_id) {
|
||||
// Look for the matching tool_use in previous assistant messages
|
||||
for (let i = index - 1; i >= 0; i--) {
|
||||
const prevMsg = messages[i];
|
||||
if (prevMsg.type === 'assistant' && prevMsg.message?.content && Array.isArray(prevMsg.message.content)) {
|
||||
const toolUse = prevMsg.message.content.find((c: any) =>
|
||||
c.type === 'tool_use' && c.id === content.tool_use_id
|
||||
);
|
||||
if (toolUse) {
|
||||
const toolName = toolUse.name?.toLowerCase();
|
||||
const toolsWithWidgets = [
|
||||
'task', 'edit', 'multiedit', 'todowrite', 'ls', 'read',
|
||||
'glob', 'bash', 'write', 'grep'
|
||||
];
|
||||
if (toolsWithWidgets.includes(toolName) || toolUse.name?.startsWith('mcp__')) {
|
||||
hasCorrespondingWidget = true;
|
||||
let hasVisibleContent = false;
|
||||
for (const content of msg.content) {
|
||||
if (content.type === "text") {
|
||||
hasVisibleContent = true;
|
||||
break;
|
||||
} else if (content.type === "tool_result") {
|
||||
// Check if this tool result will be skipped by a widget
|
||||
let willBeSkipped = false;
|
||||
if (content.tool_use_id) {
|
||||
// Look for the matching tool_use in previous assistant messages
|
||||
for (let i = index - 1; i >= 0; i--) {
|
||||
const prevMsg = messages[i];
|
||||
if (prevMsg.type === 'assistant' && prevMsg.message?.content && Array.isArray(prevMsg.message.content)) {
|
||||
const toolUse = prevMsg.message.content.find((c: any) =>
|
||||
c.type === 'tool_use' && c.id === content.tool_use_id
|
||||
);
|
||||
if (toolUse) {
|
||||
const toolName = toolUse.name?.toLowerCase();
|
||||
const toolsWithWidgets = [
|
||||
'task', 'edit', 'multiedit', 'todowrite', 'ls', 'read',
|
||||
'glob', 'bash', 'write', 'grep'
|
||||
];
|
||||
if (toolsWithWidgets.includes(toolName) || toolUse.name?.startsWith('mcp__')) {
|
||||
willBeSkipped = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!willBeSkipped) {
|
||||
hasVisibleContent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hasCorrespondingWidget && !content.is_error;
|
||||
});
|
||||
}
|
||||
|
||||
if (hasOnlyHiddenToolResults) {
|
||||
if (!hasVisibleContent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,52 +117,57 @@ export const ClaudeCodeSession: React.FC<ClaudeCodeSessionProps> = ({
|
|||
return false;
|
||||
}
|
||||
|
||||
// Skip empty user messages
|
||||
// Skip user messages that only contain tool results that are already displayed
|
||||
if (message.type === "user" && message.message) {
|
||||
if (message.isMeta) return false;
|
||||
|
||||
const msg = message.message;
|
||||
if (!msg.content || (Array.isArray(msg.content) && msg.content.length === 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this is a user message with only tool results that are already displayed
|
||||
|
||||
if (Array.isArray(msg.content)) {
|
||||
const hasOnlyHiddenToolResults = msg.content.every((content: any) => {
|
||||
if (content.type !== "tool_result") return false;
|
||||
|
||||
// Check if this tool result should be hidden
|
||||
let hasCorrespondingWidget = false;
|
||||
if (content.tool_use_id) {
|
||||
// Look for the matching tool_use in previous assistant messages
|
||||
for (let i = index - 1; i >= 0; i--) {
|
||||
const prevMsg = messages[i];
|
||||
if (prevMsg.type === 'assistant' && prevMsg.message?.content && Array.isArray(prevMsg.message.content)) {
|
||||
const toolUse = prevMsg.message.content.find((c: any) =>
|
||||
c.type === 'tool_use' && c.id === content.tool_use_id
|
||||
);
|
||||
if (toolUse) {
|
||||
const toolName = toolUse.name?.toLowerCase();
|
||||
const toolsWithWidgets = [
|
||||
'task', 'edit', 'multiedit', 'todowrite', 'ls', 'read',
|
||||
'glob', 'bash', 'write', 'grep'
|
||||
];
|
||||
if (toolsWithWidgets.includes(toolName) || toolUse.name?.startsWith('mcp__')) {
|
||||
hasCorrespondingWidget = true;
|
||||
let hasVisibleContent = false;
|
||||
for (const content of msg.content) {
|
||||
if (content.type === "text") {
|
||||
hasVisibleContent = true;
|
||||
break;
|
||||
}
|
||||
if (content.type === "tool_result") {
|
||||
let willBeSkipped = false;
|
||||
if (content.tool_use_id) {
|
||||
// Look for the matching tool_use in previous assistant messages
|
||||
for (let i = index - 1; i >= 0; i--) {
|
||||
const prevMsg = messages[i];
|
||||
if (prevMsg.type === 'assistant' && prevMsg.message?.content && Array.isArray(prevMsg.message.content)) {
|
||||
const toolUse = prevMsg.message.content.find((c: any) =>
|
||||
c.type === 'tool_use' && c.id === content.tool_use_id
|
||||
);
|
||||
if (toolUse) {
|
||||
const toolName = toolUse.name?.toLowerCase();
|
||||
const toolsWithWidgets = [
|
||||
'task', 'edit', 'multiedit', 'todowrite', 'ls', 'read',
|
||||
'glob', 'bash', 'write', 'grep'
|
||||
];
|
||||
if (toolsWithWidgets.includes(toolName) || toolUse.name?.startsWith('mcp__')) {
|
||||
willBeSkipped = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!willBeSkipped) {
|
||||
hasVisibleContent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hasCorrespondingWidget && !content.is_error;
|
||||
});
|
||||
|
||||
if (hasOnlyHiddenToolResults) {
|
||||
}
|
||||
if (!hasVisibleContent) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}, [messages]);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useState, useEffect, useRef, useMemo } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { X, Maximize2, Minimize2, Copy, RefreshCw, RotateCcw, ChevronDown } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
@ -282,6 +282,47 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||
loadOutput();
|
||||
}, [session.id]);
|
||||
|
||||
const displayableMessages = useMemo(() => {
|
||||
return messages.filter((message, index) => {
|
||||
if (message.isMeta && !message.leafUuid && !message.summary) return false;
|
||||
|
||||
if (message.type === "user" && message.message) {
|
||||
if (message.isMeta) return false;
|
||||
|
||||
const msg = message.message;
|
||||
if (!msg.content || (Array.isArray(msg.content) && msg.content.length === 0)) return false;
|
||||
|
||||
if (Array.isArray(msg.content)) {
|
||||
let hasVisibleContent = false;
|
||||
for (const content of msg.content) {
|
||||
if (content.type === "text") { hasVisibleContent = true; break; }
|
||||
if (content.type === "tool_result") {
|
||||
let willBeSkipped = false;
|
||||
if (content.tool_use_id) {
|
||||
for (let i = index - 1; i >= 0; i--) {
|
||||
const prevMsg = messages[i];
|
||||
if (prevMsg.type === 'assistant' && prevMsg.message?.content && Array.isArray(prevMsg.message.content)) {
|
||||
const toolUse = prevMsg.message.content.find((c: any) => c.type === 'tool_use' && c.id === content.tool_use_id);
|
||||
if (toolUse) {
|
||||
const toolName = toolUse.name?.toLowerCase();
|
||||
const toolsWithWidgets = ['task','edit','multiedit','todowrite','ls','read','glob','bash','write','grep'];
|
||||
if (toolsWithWidgets.includes(toolName) || toolUse.name?.startsWith('mcp__')) {
|
||||
willBeSkipped = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!willBeSkipped) { hasVisibleContent = true; break; }
|
||||
}
|
||||
}
|
||||
if (!hasVisibleContent) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, [messages]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -432,7 +473,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||
) : (
|
||||
<>
|
||||
<AnimatePresence>
|
||||
{messages.map((message: ClaudeStreamMessage, index: number) => (
|
||||
{displayableMessages.map((message: ClaudeStreamMessage, index: number) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
|
@ -556,7 +597,7 @@ export function SessionOutputViewer({ session, onClose, className }: SessionOutp
|
|||
) : (
|
||||
<>
|
||||
<AnimatePresence>
|
||||
{messages.map((message: ClaudeStreamMessage, index: number) => (
|
||||
{displayableMessages.map((message: ClaudeStreamMessage, index: number) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
|
|
|
@ -100,7 +100,9 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
if (message.type === "assistant" && message.message) {
|
||||
const msg = message.message;
|
||||
|
||||
return (
|
||||
let renderedSomething = false;
|
||||
|
||||
const renderedCard = (
|
||||
<Card className={cn("border-primary/20 bg-primary/5", className)}>
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-start gap-3">
|
||||
|
@ -114,6 +116,7 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
? content.text
|
||||
: (content.text?.text || JSON.stringify(content.text || content));
|
||||
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="prose prose-sm dark:prose-invert max-w-none">
|
||||
<ReactMarkdown
|
||||
|
@ -157,56 +160,67 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
const renderToolWidget = () => {
|
||||
// Task tool - for sub-agent tasks
|
||||
if (toolName === "task" && input) {
|
||||
renderedSomething = true;
|
||||
return <TaskWidget description={input.description} prompt={input.prompt} result={toolResult} />;
|
||||
}
|
||||
|
||||
// Edit tool
|
||||
if (toolName === "edit" && input?.file_path) {
|
||||
renderedSomething = true;
|
||||
return <EditWidget {...input} result={toolResult} />;
|
||||
}
|
||||
|
||||
// MultiEdit tool
|
||||
if (toolName === "multiedit" && input?.file_path && input?.edits) {
|
||||
renderedSomething = true;
|
||||
return <MultiEditWidget {...input} result={toolResult} />;
|
||||
}
|
||||
|
||||
// MCP tools (starting with mcp__)
|
||||
if (content.name?.startsWith("mcp__")) {
|
||||
renderedSomething = true;
|
||||
return <MCPWidget toolName={content.name} input={input} result={toolResult} />;
|
||||
}
|
||||
|
||||
// TodoWrite tool
|
||||
if (toolName === "todowrite" && input?.todos) {
|
||||
renderedSomething = true;
|
||||
return <TodoWidget todos={input.todos} result={toolResult} />;
|
||||
}
|
||||
|
||||
// LS tool
|
||||
if (toolName === "ls" && input?.path) {
|
||||
renderedSomething = true;
|
||||
return <LSWidget path={input.path} result={toolResult} />;
|
||||
}
|
||||
|
||||
// Read tool
|
||||
if (toolName === "read" && input?.file_path) {
|
||||
renderedSomething = true;
|
||||
return <ReadWidget filePath={input.file_path} result={toolResult} />;
|
||||
}
|
||||
|
||||
// Glob tool
|
||||
if (toolName === "glob" && input?.pattern) {
|
||||
renderedSomething = true;
|
||||
return <GlobWidget pattern={input.pattern} result={toolResult} />;
|
||||
}
|
||||
|
||||
// Bash tool
|
||||
if (toolName === "bash" && input?.command) {
|
||||
renderedSomething = true;
|
||||
return <BashWidget command={input.command} description={input.description} result={toolResult} />;
|
||||
}
|
||||
|
||||
// Write tool
|
||||
if (toolName === "write" && input?.file_path && input?.content) {
|
||||
renderedSomething = true;
|
||||
return <WriteWidget filePath={input.file_path} content={input.content} result={toolResult} />;
|
||||
}
|
||||
|
||||
// Grep tool
|
||||
if (toolName === "grep" && input?.pattern) {
|
||||
renderedSomething = true;
|
||||
return <GrepWidget pattern={input.pattern} include={input.include} path={input.path} exclude={input.exclude} result={toolResult} />;
|
||||
}
|
||||
|
||||
|
@ -217,10 +231,12 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
// Render the tool widget
|
||||
const widget = renderToolWidget();
|
||||
if (widget) {
|
||||
renderedSomething = true;
|
||||
return <div key={idx}>{widget}</div>;
|
||||
}
|
||||
|
||||
// Fallback to basic tool display
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -252,6 +268,8 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
if (!renderedSomething) return null;
|
||||
return renderedCard;
|
||||
}
|
||||
|
||||
// User message
|
||||
|
@ -261,12 +279,9 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
|
||||
const msg = message.message;
|
||||
|
||||
// Skip empty user messages
|
||||
if (!msg.content || (Array.isArray(msg.content) && msg.content.length === 0)) {
|
||||
return null;
|
||||
}
|
||||
let renderedSomething = false;
|
||||
|
||||
return (
|
||||
const renderedCard = (
|
||||
<Card className={cn("border-muted-foreground/20 bg-muted/20", className)}>
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-start gap-3">
|
||||
|
@ -276,6 +291,8 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
{typeof msg.content === 'string' && (
|
||||
(() => {
|
||||
const contentStr = msg.content as string;
|
||||
if (contentStr.trim() === '') return null;
|
||||
renderedSomething = true;
|
||||
|
||||
// Check if it's a command message
|
||||
const commandMatch = contentStr.match(/<command-name>(.+?)<\/command-name>[\s\S]*?<command-message>(.+?)<\/command-message>[\s\S]*?<command-args>(.*?)<\/command-args>/);
|
||||
|
@ -310,27 +327,16 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
{Array.isArray(msg.content) && msg.content.map((content: any, idx: number) => {
|
||||
// Tool result
|
||||
if (content.type === "tool_result") {
|
||||
// Skip rendering tool results that are already displayed by tool widgets
|
||||
// We need to check if this result corresponds to a tool that has its own widget
|
||||
|
||||
// Find the corresponding tool use for this result
|
||||
// Skip duplicate tool_result if a dedicated widget is present
|
||||
let hasCorrespondingWidget = false;
|
||||
if (content.tool_use_id && streamMessages) {
|
||||
// Look for the matching tool_use in previous assistant messages
|
||||
for (let i = streamMessages.length - 1; i >= 0; i--) {
|
||||
const prevMsg = streamMessages[i];
|
||||
if (prevMsg.type === 'assistant' && prevMsg.message?.content && Array.isArray(prevMsg.message.content)) {
|
||||
const toolUse = prevMsg.message.content.find((c: any) =>
|
||||
c.type === 'tool_use' && c.id === content.tool_use_id
|
||||
);
|
||||
const toolUse = prevMsg.message.content.find((c: any) => c.type === 'tool_use' && c.id === content.tool_use_id);
|
||||
if (toolUse) {
|
||||
const toolName = toolUse.name?.toLowerCase();
|
||||
// List of tools that display their own results
|
||||
const toolsWithWidgets = [
|
||||
'task', 'edit', 'multiedit', 'todowrite', 'ls', 'read',
|
||||
'glob', 'bash', 'write', 'grep'
|
||||
];
|
||||
// Also check for MCP tools
|
||||
const toolsWithWidgets = ['task','edit','multiedit','todowrite','ls','read','glob','bash','write','grep'];
|
||||
if (toolsWithWidgets.includes(toolName) || toolUse.name?.startsWith('mcp__')) {
|
||||
hasCorrespondingWidget = true;
|
||||
}
|
||||
|
@ -339,9 +345,8 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the tool has its own widget that displays results, skip rendering the duplicate
|
||||
if (hasCorrespondingWidget && !content.is_error) {
|
||||
|
||||
if (hasCorrespondingWidget) {
|
||||
return null;
|
||||
}
|
||||
// Extract the actual content string
|
||||
|
@ -370,6 +375,7 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
const beforeReminder = contentText.substring(0, reminderMatch.index || 0).trim();
|
||||
const afterReminder = contentText.substring((reminderMatch.index || 0) + reminderMatch[0].length).trim();
|
||||
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -404,6 +410,7 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
const isEditResult = contentText.includes("has been updated. Here's the result of running `cat -n`");
|
||||
|
||||
if (isEditResult) {
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -421,6 +428,7 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
contentText.includes("Applied multiple edits to");
|
||||
|
||||
if (isMultiEditResult) {
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -470,6 +478,7 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
})();
|
||||
|
||||
if (isLSResult) {
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -508,6 +517,7 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
}
|
||||
}
|
||||
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -521,6 +531,7 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
|
||||
// Handle empty tool results
|
||||
if (!contentText || contentText.trim() === '') {
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -534,6 +545,7 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
);
|
||||
}
|
||||
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
@ -560,6 +572,7 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
? content.text
|
||||
: (content.text?.text || JSON.stringify(content.text));
|
||||
|
||||
renderedSomething = true;
|
||||
return (
|
||||
<div key={idx} className="text-sm">
|
||||
{textContent}
|
||||
|
@ -574,6 +587,8 @@ const StreamMessageComponent: React.FC<StreamMessageProps> = ({ message, classNa
|
|||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
if (!renderedSomething) return null;
|
||||
return renderedCard;
|
||||
}
|
||||
|
||||
// Result message - render with markdown
|
||||
|
|
|
@ -3,7 +3,6 @@ import react from "@vitejs/plugin-react";
|
|||
import tailwindcss from "@tailwindcss/vite";
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
|
||||
// @ts-expect-error process is a nodejs global
|
||||
const host = process.env.TAURI_DEV_HOST;
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
|
@ -38,4 +37,26 @@ export default defineConfig(async () => ({
|
|||
ignored: ["**/src-tauri/**"],
|
||||
},
|
||||
},
|
||||
|
||||
// Build configuration for code splitting
|
||||
build: {
|
||||
// Increase chunk size warning limit to 2000 KB
|
||||
chunkSizeWarningLimit: 2000,
|
||||
|
||||
rollupOptions: {
|
||||
output: {
|
||||
// Manual chunks for better code splitting
|
||||
manualChunks: {
|
||||
// Vendor chunks
|
||||
'react-vendor': ['react', 'react-dom'],
|
||||
'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu', '@radix-ui/react-select', '@radix-ui/react-tabs', '@radix-ui/react-tooltip', '@radix-ui/react-switch', '@radix-ui/react-popover'],
|
||||
'editor-vendor': ['@uiw/react-md-editor'],
|
||||
'syntax-vendor': ['react-syntax-highlighter'],
|
||||
// Tauri and other utilities
|
||||
'tauri': ['@tauri-apps/api', '@tauri-apps/plugin-dialog', '@tauri-apps/plugin-shell'],
|
||||
'utils': ['date-fns', 'clsx', 'tailwind-merge'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue