diff --git a/netlify.toml b/netlify.toml index b55707ebb..948b3748f 100644 --- a/netlify.toml +++ b/netlify.toml @@ -7,3 +7,29 @@ [functions] directory = "netlify/functions" + +# Cache headers for static assets +[[headers]] + for = "/fonts/*" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "/logos/*" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "/assets/*.js" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "/assets/*.css" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "/*.woff2" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" diff --git a/src/components/ShowcaseCard.tsx b/src/components/ShowcaseCard.tsx index 6fd3a58cc..a557dbba6 100644 --- a/src/components/ShowcaseCard.tsx +++ b/src/components/ShowcaseCard.tsx @@ -46,6 +46,7 @@ export function ShowcaseCard({ {showcase.name} {/* Logo overlay */} @@ -54,6 +55,7 @@ export function ShowcaseCard({ diff --git a/src/components/TrustedByMarquee.tsx b/src/components/TrustedByMarquee.tsx index e3fa602c2..b1dfacf62 100644 --- a/src/components/TrustedByMarquee.tsx +++ b/src/components/TrustedByMarquee.tsx @@ -53,6 +53,7 @@ export function TrustedByMarquee({ key={i} src={logoSrc} alt={brand} + loading="lazy" className="max-w-24 max-h-14 w-auto h-auto object-contain opacity-50 grayscale hover:opacity-100 transition-all duration-200 dark:invert dark:opacity-70 shrink-0" /> ) : ( diff --git a/src/routes/admin/banners.$id.tsx b/src/routes/admin/banners.$id.tsx index 4857f1682..cee381463 100644 --- a/src/routes/admin/banners.$id.tsx +++ b/src/routes/admin/banners.$id.tsx @@ -1,11 +1,17 @@ import { createFileRoute, useNavigate } from '@tanstack/react-router' import { useQuery } from '@tanstack/react-query' -import { BannerEditor } from '~/components/admin/BannerEditor' +import { lazy, Suspense } from 'react' import { getBanner, type BannerWithMeta } from '~/utils/banner.functions' import { useCapabilities } from '~/hooks/useCapabilities' import { useCurrentUserQuery } from '~/hooks/useCurrentUser' import * as v from 'valibot' +const BannerEditor = lazy(() => + import('~/components/admin/BannerEditor').then((m) => ({ + default: m.BannerEditor, + })), +) + export const Route = createFileRoute('/admin/banners/$id')({ component: BannerEditorPage, validateSearch: (search) => v.parse(v.object({}), search), @@ -75,11 +81,19 @@ function BannerEditorPage() { return (
- navigate({ to: '/admin/banners' })} - onCancel={() => navigate({ to: '/admin/banners' })} - /> + +
Loading editor...
+
+ } + > + navigate({ to: '/admin/banners' })} + onCancel={() => navigate({ to: '/admin/banners' })} + /> +
) diff --git a/src/routes/admin/feed.$id.tsx b/src/routes/admin/feed.$id.tsx index 5b62ddd2b..ac25babd8 100644 --- a/src/routes/admin/feed.$id.tsx +++ b/src/routes/admin/feed.$id.tsx @@ -1,11 +1,18 @@ import { createFileRoute, useNavigate } from '@tanstack/react-router' import { useQuery } from '@tanstack/react-query' -import { FeedEntryEditor } from '~/components/admin/FeedEntryEditor' +import { lazy, Suspense } from 'react' import type { FeedEntry } from '~/components/FeedEntry' import { useCapabilities } from '~/hooks/useCapabilities' import { useCurrentUserQuery } from '~/hooks/useCurrentUser' import { getFeedEntryQueryOptions } from '~/queries/feed' import * as v from 'valibot' + +const FeedEntryEditor = lazy(() => + import('~/components/admin/FeedEntryEditor').then((m) => ({ + default: m.FeedEntryEditor, + })), +) + export const Route = createFileRoute('/admin/feed/$id')({ component: FeedEditorPage, validateSearch: (search) => v.parse(v.object({}), search), @@ -73,13 +80,23 @@ function FeedEditorPage() { return (
- +
Loading editor...
+
} - onSave={() => navigate({ to: '/admin/feed' })} - onCancel={() => navigate({ to: '/admin/feed' })} - /> + > + navigate({ to: '/admin/feed' })} + onCancel={() => navigate({ to: '/admin/feed' })} + /> +
) diff --git a/vite.config.ts b/vite.config.ts index f64cbee54..0dddc6a75 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -37,6 +37,24 @@ export default defineConfig({ ) { return 'search' } + // Syntax highlighting (lazy-loaded via mermaid/shiki) + if (id.includes('shiki') || id.includes('mermaid')) { + return 'syntax-highlight' + } + // Radix UI components (used throughout) + if (id.includes('@radix-ui/')) { + return 'radix-ui' + } + // Markdown processing (unified/remark/rehype) + if ( + id.includes('unified') || + id.includes('remark') || + id.includes('rehype') || + id.includes('hast-') || + id.includes('mdast-') + ) { + return 'markdown-processing' + } // Charting deps (only loaded on stats/admin pages) if ( id.includes('@observablehq/plot') ||