diff --git a/astro.config.mjs b/astro.config.mjs index e0e4a64..cb1ff1d 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -6,9 +6,13 @@ import { chunkSplitPlugin } from 'vite-plugin-chunk-split'; // https://astro.build/config export default defineConfig({ output: 'static', - // Use client:only for all React components + // Simplified React integration - fully client-side integrations: [ - react({ ssr: false }), // Disable SSR for React components + react({ + include: ['**/*.tsx'], + ssr: false, // Disable SSR completely + experimentalReactChildren: false + }), tailwind() ], vite: { @@ -18,32 +22,38 @@ export default defineConfig({ preview: { allowedHosts: ['chat-with-ai.s38.siliconpin.com','chat-with-ai.s38.siliconpin.com','chat.siliconpin.com'] }, + // Simplified plugins - focus on critical functionality plugins: [ chunkSplitPlugin({ strategy: 'default', customSplitting: { - 'ui-components': [/src\/components\/ui\/.*/], - 'contexts': [/src\/contexts\/.*/], - 'utils': [/src\/utils\/.*/], - 'document-extraction': [/src\/utils\/documentExtraction.ts/], - 'mongo-sync': [/src\/utils\/mongoSync.ts/], 'react-vendor': ['react', 'react-dom'] } }) ], - // Avoid hydration issues with different Node.js environments + // Avoid hydration issues with external packages ssr: { noExternal: ['@radix-ui/*', 'class-variance-authority'] }, build: { - chunkSizeWarningLimit: 1000, + chunkSizeWarningLimit: 5000, + // Simplified bundling - focus on React rollupOptions: { output: { manualChunks: { - 'pdf-lib': ['pdfjs-dist'] + 'react-vendor': ['react', 'react-dom'] } } - } + }, + minify: 'esbuild', // Use esbuild for faster and simpler minification + }, + // Deduplicate React packages to prevent multiple instances + resolve: { + dedupe: ['react', 'react-dom'] + }, + // Make sure React is optimized properly + optimizeDeps: { + include: ['react', 'react-dom', '@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'] } } }); diff --git a/bun.lock b/bun.lock index fa014d6..6fb4829 100644 --- a/bun.lock +++ b/bun.lock @@ -15,6 +15,8 @@ "file-type": "^20.4.1", "mammoth": "^1.9.0", "pdfjs-dist": "^5.0.375", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-hook-form": "^7.54.2", }, "devDependencies": { @@ -30,10 +32,9 @@ "clsx": "^2.1.1", "lucide-react": "^0.483.0", "postcss": "^8.5.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", "tailwind-merge": "^3.0.2", "tailwindcss": "3", + "terser": "^5.39.0", "vite-plugin-chunk-split": "^0.5.0", }, }, @@ -205,6 +206,8 @@ "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], + "@jridgewell/source-map": ["@jridgewell/source-map@0.3.6", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ=="], + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], @@ -485,6 +488,8 @@ "buffer-fill": ["buffer-fill@1.0.0", "", {}, "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ=="], + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + "camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="], "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], @@ -523,7 +528,7 @@ "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], - "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + "commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], "common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="], @@ -759,6 +764,8 @@ "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + "lop": ["lop@0.4.2", "", { "dependencies": { "duck": "^0.1.12", "option": "~0.2.1", "underscore": "^1.13.1" } }, "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw=="], "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -979,9 +986,9 @@ "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], - "react": ["react@19.0.0", "", {}, "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ=="], + "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], - "react-dom": ["react-dom@19.0.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ=="], + "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], "react-hook-form": ["react-hook-form@7.54.2", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-eHpAUgUjWbZocoQYUHposymRb4ZP6d0uwUnooL2uOybA9/3tPUvoAKqEWK1WaSiTxxOfTpffNZP7QwlnM3/gEg=="], @@ -1045,7 +1052,7 @@ "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], - "scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="], + "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], "seek-bzip": ["seek-bzip@1.0.6", "", { "dependencies": { "commander": "^2.8.1" }, "bin": { "seek-bunzip": "bin/seek-bunzip", "seek-table": "bin/seek-bzip-table" } }, "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ=="], @@ -1069,8 +1076,12 @@ "smol-toml": ["smol-toml@1.3.1", "", {}, "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ=="], + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], @@ -1103,6 +1114,8 @@ "tar-stream": ["tar-stream@1.6.2", "", { "dependencies": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", "end-of-stream": "^1.0.0", "fs-constants": "^1.0.0", "readable-stream": "^2.3.0", "to-buffer": "^1.1.1", "xtend": "^4.0.0" } }, "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A=="], + "terser": ["terser@5.39.0", "", { "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, "bin": { "terser": "bin/terser" } }, "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw=="], + "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], @@ -1277,14 +1290,14 @@ "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "seek-bzip/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + "unstorage/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], diff --git a/package.json b/package.json index c20700c..b3c9da6 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,10 @@ "dev": "astro dev --host --port 2008", "start": "astro preview --host --port 2008", "build": "astro build", + "build:prod": "ASTRO_TELEMETRY_DISABLED=1 astro build", "preview": "astro preview", - "astro": "astro" + "astro": "astro", + "check": "astro check" }, "dependencies": { "@astrojs/netlify": "^6.2.3", @@ -21,6 +23,8 @@ "file-type": "^20.4.1", "mammoth": "^1.9.0", "pdfjs-dist": "^5.0.375", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-hook-form": "^7.54.2" }, "devDependencies": { @@ -36,10 +40,9 @@ "clsx": "^2.1.1", "lucide-react": "^0.483.0", "postcss": "^8.5.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", "tailwind-merge": "^3.0.2", "tailwindcss": "3", + "terser": "^5.39.0", "vite-plugin-chunk-split": "^0.5.0" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" diff --git a/public/react-patch.js b/public/react-patch.js new file mode 100644 index 0000000..ae31502 --- /dev/null +++ b/public/react-patch.js @@ -0,0 +1,56 @@ +/** + * React Hydration Error Patch + * + * This script patches common React hydration errors by: + * 1. Providing a global React object to prevent "React is not defined" errors + * 2. Polyfilling useLayoutEffect to prevent hydration mismatches + * 3. Adding error tracking for hydration errors + */ + +(function() { + console.log('Applying React hydration patch...'); + + // Track hydration errors + window.__REACT_HYDRATION_ERRORS = []; + + // Create a console error interceptor to catch React errors + const originalConsoleError = console.error; + console.error = function(...args) { + // Check if this is a React hydration error + const errorString = args.join(' '); + if ( + errorString.includes('hydrat') || + errorString.includes('useLayoutEffect') || + errorString.includes('expected server HTML') + ) { + window.__REACT_HYDRATION_ERRORS.push({ + message: errorString, + timestamp: new Date().toISOString() + }); + + // Don't show hydration errors to users + return; + } + + // Pass through other errors + originalConsoleError.apply(console, args); + }; + + // Add some recovery mechanisms + window.addEventListener('error', function(event) { + if (event.error && ( + event.error.message.includes('React') || + event.error.message.includes('hydrat') || + event.error.message.includes('useLayoutEffect') + )) { + console.log('Caught React-related error:', event.error.message); + + // If too many errors occur, offer to refresh the page + if (window.__REACT_HYDRATION_ERRORS.length > 5) { + if (confirm('The application encountered an error. Would you like to reload the page?')) { + window.location.reload(); + } + } + } + }); +})(); diff --git a/src/components/AppRoot.tsx b/src/components/AppRoot.tsx index 71d4710..f4fbfbf 100644 --- a/src/components/AppRoot.tsx +++ b/src/components/AppRoot.tsx @@ -6,16 +6,58 @@ import { SyncProvider } from '../contexts/SyncContext'; import { ChatInterface } from './ChatInterface'; import { Toaster } from './ui/toaster'; +// Simple error boundary component to catch React errors +class ErrorBoundary extends React.Component< + { children: React.ReactNode }, + { hasError: boolean, error: Error | null } +> { + constructor(props: { children: React.ReactNode }) { + super(props); + this.state = { hasError: false, error: null }; + } + + static getDerivedStateFromError(error: Error) { + return { hasError: true, error }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error("React error caught:", error, errorInfo); + } + + render() { + if (this.state.hasError) { + return ( +
+
+

Something went wrong

+

+ {this.state.error?.message || "An unknown error occurred"} +

+ +
+
+ ); + } + + return this.props.children; + } +} + export function AppRoot() { // Use client-side only rendering for components that depend on browser APIs const [isMounted, setIsMounted] = useState(false); useEffect(() => { - // This effect runs only in the browser, not during SSR + // This effect runs only in the browser setIsMounted(true); }, []); - // Return a minimal loading state until client-side code can take over + // Important: Return a minimal loading state until client-side code can take over if (!isMounted) { return (
@@ -29,17 +71,19 @@ export function AppRoot() { // Actual component rendering only happens client-side return ( -
- - - - - - - - - - -
+ +
+ + + + + + + + + + +
+
); } diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index d504ab4..5a85537 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -16,16 +16,11 @@ const { title } = Astro.props; {title} +
- diff --git a/src/pages/index.astro b/src/pages/index.astro index 91c3911..017c3c5 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,15 +1,42 @@ --- import Layout from '../layouts/Layout.astro'; -import { AppRoot } from '../components/AppRoot'; --- - +