summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/web/app/reader/_components/entry-list.tsx15
-rw-r--r--apps/web/app/sw.ts22
-rw-r--r--apps/web/lib/hooks/use-prefetch-entry-details.ts45
3 files changed, 75 insertions, 7 deletions
diff --git a/apps/web/app/reader/_components/entry-list.tsx b/apps/web/app/reader/_components/entry-list.tsx
index acc0990..65e35f7 100644
--- a/apps/web/app/reader/_components/entry-list.tsx
+++ b/apps/web/app/reader/_components/entry-list.tsx
@@ -1,12 +1,13 @@
"use client"
-import { useRef, useEffect } from "react"
+import { useRef, useEffect, useMemo } from "react"
import { useVirtualizer } from "@tanstack/react-virtual"
import { useTimeline } from "@/lib/queries/use-timeline"
import { useSavedEntries } from "@/lib/queries/use-saved-entries"
import { useCustomFeedTimeline } from "@/lib/queries/use-custom-feed-timeline"
import { useUserInterfaceStore } from "@/lib/stores/user-interface-store"
import { EntryListItem } from "./entry-list-item"
+import { usePrefetchEntryDetails } from "@/lib/hooks/use-prefetch-entry-details"
interface EntryListProperties {
feedFilter: "all" | "saved"
@@ -77,11 +78,15 @@ export function EntryList({
const firstEntryIdentifier = allEntries[0]?.entryIdentifier
const lastEntryIdentifier = allEntries[allEntries.length - 1]?.entryIdentifier
+ const prefetchIdentifiers = useMemo(
+ () => allEntries.map((entry) => entry.entryIdentifier),
+ [firstEntryIdentifier, lastEntryIdentifier, allEntries.length]
+ )
+ usePrefetchEntryDetails(prefetchIdentifiers)
+
useEffect(() => {
- setNavigableEntryIdentifiers(
- allEntries.map((entry) => entry.entryIdentifier)
- )
- }, [firstEntryIdentifier, lastEntryIdentifier, allEntries.length, setNavigableEntryIdentifiers])
+ setNavigableEntryIdentifiers(prefetchIdentifiers)
+ }, [prefetchIdentifiers, setNavigableEntryIdentifiers])
function getEstimatedItemSize() {
switch (entryListViewMode) {
diff --git a/apps/web/app/sw.ts b/apps/web/app/sw.ts
index 0469377..e18cc5a 100644
--- a/apps/web/app/sw.ts
+++ b/apps/web/app/sw.ts
@@ -1,7 +1,7 @@
/// <reference lib="webworker" />
import { defaultCache } from "@serwist/next/worker"
import type { PrecacheEntry, SerwistGlobalConfig } from "serwist"
-import { Serwist } from "serwist"
+import { Serwist, NetworkFirst, ExpirationPlugin } from "serwist"
declare global {
interface WorkerGlobalScope extends SerwistGlobalConfig {
@@ -27,7 +27,25 @@ const serwist = new Serwist({
skipWaiting: true,
clientsClaim: true,
navigationPreload: true,
- runtimeCaching: sameOriginCache,
+ runtimeCaching: [
+ {
+ matcher: ({ url, request }) =>
+ url.hostname.endsWith(".supabase.co") &&
+ url.pathname.startsWith("/rest/v1/") &&
+ request.method === "GET",
+ handler: new NetworkFirst({
+ cacheName: "supabase-rest-get",
+ networkTimeoutSeconds: 10,
+ plugins: [
+ new ExpirationPlugin({
+ maxEntries: 200,
+ maxAgeSeconds: 60 * 60 * 24,
+ }),
+ ],
+ }),
+ },
+ ...sameOriginCache,
+ ],
})
serwist.addEventListeners()
diff --git a/apps/web/lib/hooks/use-prefetch-entry-details.ts b/apps/web/lib/hooks/use-prefetch-entry-details.ts
new file mode 100644
index 0000000..8b88bb8
--- /dev/null
+++ b/apps/web/lib/hooks/use-prefetch-entry-details.ts
@@ -0,0 +1,45 @@
+"use client"
+
+import { useEffect } from "react"
+import { useQueryClient } from "@tanstack/react-query"
+import { createSupabaseBrowserClient } from "@/lib/supabase/client"
+import { queryKeys } from "@/lib/queries/query-keys"
+
+const PREFETCH_BATCH_SIZE = 10
+
+export function usePrefetchEntryDetails(entryIdentifiers: string[]) {
+ const queryClient = useQueryClient()
+
+ useEffect(() => {
+ if (entryIdentifiers.length === 0) return
+
+ const supabaseClient = createSupabaseBrowserClient()
+ const identifiersToPrefetch = entryIdentifiers.slice(0, PREFETCH_BATCH_SIZE)
+
+ for (const entryIdentifier of identifiersToPrefetch) {
+ const existingData = queryClient.getQueryData(
+ queryKeys.entryDetail.single(entryIdentifier)
+ )
+
+ if (existingData) continue
+
+ queryClient.prefetchQuery({
+ queryKey: queryKeys.entryDetail.single(entryIdentifier),
+ queryFn: async () => {
+ const { data, error } = await supabaseClient
+ .from("entries")
+ .select(
+ "id, title, url, author, content_html, summary, published_at, enclosure_url, feeds!inner(title)"
+ )
+ .eq("id", entryIdentifier)
+ .single()
+
+ if (error) throw error
+
+ return data
+ },
+ staleTime: 5 * 60 * 1000,
+ })
+ }
+ }, [entryIdentifiers, queryClient])
+}