Skip to content

Commit

Permalink
feat: cache something
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Feb 23, 2024
1 parent 3833c80 commit 6848154
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 24 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"@tanstack/react-query": "5.21.2",
"@tanstack/react-query-devtools": "5.21.3",
"@tanstack/react-query-persist-client": "5.21.2",
"@upstash/redis": "1.28.4",
"@vercel/analytics": "1.2.0",
"@vercel/postgres": "0.7.2",
"axios": "1.6.7",
Expand Down
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions src/app/(app)/(home)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,29 @@ import { dehydrate } from '@tanstack/react-query'
import type { PropsWithChildren } from 'react'

import { QueryHydrate } from '~/components/common/QueryHydrate'
import { getOrSetCache } from '~/lib/cache'
import { isShallowEqualArray } from '~/lib/lodash'
import { getQueryClient } from '~/lib/query-client.server'
import { apiClient } from '~/lib/request'
import { requestErrorHandler } from '~/lib/request.server'

import { queryKey } from './query'

export const revalidate = 60
export const revalidate = 600

export default async function HomeLayout(props: PropsWithChildren) {
const queryClient = getQueryClient()
await queryClient
.fetchQuery({
queryKey,
queryFn: async () => {
return (await apiClient.aggregate.getTop(5)).$serialized
return getOrSetCache(
'aggregate-top',
async () => {
return (await apiClient.aggregate.getTop(5)).$serialized
},
revalidate,
)
},
})
.catch(requestErrorHandler)
Expand Down
11 changes: 9 additions & 2 deletions src/app/(app)/feed/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { getQueryClient } from '~/lib/query-client.server'
import { apiClient } from '~/lib/request'

export const dynamic = 'force-dynamic'
export const revalidate = 60 * 10 // 10 min
export const revalidate = 60 * 60 * 24 // 1 day

interface RSSProps {
title: string
Expand Down Expand Up @@ -108,7 +108,11 @@ ${ReactDOM.renderToString(
extendsRules: {
codeBlock: {
react(node, output, state) {
if (node.lang === 'mermaid' || node.lang === 'excalidraw') {
if (
node.lang === 'mermaid' ||
node.lang === 'excalidraw' ||
node.lang === 'component'
) {
return <NotSupportRender />
}
return (
Expand Down Expand Up @@ -151,6 +155,9 @@ ${ReactDOM.renderToString(
return new Response(xml, {
headers: {
'Content-Type': 'application/xml',
'Cache-Control': 'max-age=60',
'CDN-Cache-Control': 'max-age=86400',
'Vercel-CDN-Cache-Control': 'max-age=86400',
},
})
}
Expand Down
43 changes: 23 additions & 20 deletions src/app/(app)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Analytics } from '@vercel/analytics/react'
import { ToastContainer } from 'react-toastify'
import type { AggregateRoot } from '@mx-space/api-client'
import { unstable_cache } from 'next/cache'
import type { Viewport } from 'next'
import type { PropsWithChildren } from 'react'

Expand All @@ -15,6 +14,7 @@ import { AccentColorStyleInjector } from '~/components/modules/shared/AccentColo
import { SearchPanelWithHotKey } from '~/components/modules/shared/SearchFAB'
import { TocAutoScroll } from '~/components/modules/toc/TocAutoScroll'
import { attachUAAndRealIp } from '~/lib/attach-ua'
import { getOrSetCache } from '~/lib/cache'
import { sansFont, serifFont } from '~/lib/fonts'
import { getQueryClient } from '~/lib/query-client.server'
import { AggregationProvider } from '~/providers/root/aggregation-data-provider'
Expand All @@ -26,9 +26,7 @@ import { Analyze } from './analyze'

const { version } = PKG

export const revalidate = 60

let aggregationData: (AggregateRoot & { theme: AppThemeConfig }) | null = null
export const revalidate = 300 // 300s

export function generateViewport(): Viewport {
return {
Expand All @@ -44,14 +42,27 @@ export function generateViewport(): Viewport {
}
}

export const generateMetadata = async () => {
const queryClient = getQueryClient()
const key = 'root-data'
const fetchAggregationData = unstable_cache(
async () => {
const queryClient = getQueryClient()

const fetchedData =
aggregationData ??
(await queryClient.fetchQuery(queries.aggregation.root()))
return getOrSetCache(
key,
async () => {
attachUAAndRealIp()

return queryClient.fetchQuery(queries.aggregation.root())
},
revalidate,
)
},
[key],
{ revalidate },
)
export const generateMetadata = async () => {
const fetchedData = await fetchAggregationData()

aggregationData = fetchedData
const {
seo,
url,
Expand Down Expand Up @@ -124,19 +135,12 @@ export const generateMetadata = async () => {
}

export default async function RootLayout(props: PropsWithChildren) {
attachUAAndRealIp()
const { children } = props

const queryClient = getQueryClient()

const data = await queryClient.fetchQuery({
...queries.aggregation.root(),
})
const data = await fetchAggregationData()

const themeConfig = data.theme

aggregationData = data

return (
<ClerkProvider>
<AppFeatureProvider tmdb={!!process.env.TMDB_API_KEY}>
Expand Down Expand Up @@ -185,7 +189,6 @@ export default async function RootLayout(props: PropsWithChildren) {
<ScrollTop />
</body>
</html>
<Analytics />
</AppFeatureProvider>
</ClerkProvider>
)
Expand Down
81 changes: 81 additions & 0 deletions src/lib/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Redis } from '@upstash/redis'

import { safeJsonParse } from './helper'

const UPSTASH_TOKEN = process.env.UPSTASH_TOKEN
const UPSTASH_URL = process.env.UPSTASH_URL

let redis: Redis
const getRedis = () => {
if (redis) {
return redis
}
if (!UPSTASH_TOKEN || !UPSTASH_URL) {
return null
}
const _redis = new Redis({
url: UPSTASH_URL,
token: UPSTASH_TOKEN,
})

redis = _redis
return _redis
}

export const setCache = async (key: string, value: string, ttl: number) => {
const _redis = getRedis()
if (!_redis) {
return
}
await _redis
.set(key, value, {
ex: ttl,
})
.catch((err) => {
console.error('setCache', err)
})
}

export const getCache = async (key: string) => {
const _redis = getRedis()
if (!_redis) {
return null
}
return await _redis.get(key).catch((err) => {
console.error('getCache', err)

return null
})
}

export const getOrSetCache = async <T>(
key: string,
setFn: () => Promise<T>,
ttl: number,
): Promise<T> => {
const cache = await getCache(key)

if (cache) {
if (typeof cache === 'string') {
const tryParse = safeJsonParse(cache as any)
if (tryParse) {
return tryParse as T
}
} else {
return cache as T
}
}

const fallbackData = await setFn()

await setCache(key, JSON.stringify(fallbackData), ttl)
return fallbackData
}

export const onlyGetOrSetCacheInVercelButFallback: typeof getOrSetCache =
async (key, setFn, ttl) => {
if (process.env.VERCEL || process.env.VERCEL_ENV) {
return getOrSetCache(key, setFn, ttl)
}
return setFn()
}

0 comments on commit 6848154

Please sign in to comment.