Skip to content

Commit

Permalink
fix: 60 min cache, add cache headers
Browse files Browse the repository at this point in the history
  • Loading branch information
harlan-zw committed Jul 7, 2023
1 parent 5e22203 commit 271abbe
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 59 deletions.
2 changes: 1 addition & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export default defineNuxtModule<ModuleOptions>({
defaults: {
enabled: true,
credits: true,
cacheTtl: 1000 * 60, // cache for 60 minutes
cacheTtl: 1000 * 60 * 60, // cache for 60 minutes
debug: false,
autoLastmod: true,
inferStaticPagesAsRoutes: true,
Expand Down
24 changes: 6 additions & 18 deletions src/runtime/middleware/[sitemap]-sitemap.xml.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { defineEventHandler, setHeader } from 'h3'
import { parseURL } from 'ufo'
import { prefixStorage } from 'unstorage'
import type { ModuleRuntimeConfig, SitemapRenderCtx } from '../types'
import { buildSitemap } from '../sitemap/builder'
import { createSitePathResolver, useNitroApp, useRuntimeConfig, useStorage } from '#imports'
import { setupCache } from '../util/cache'
import { createSitePathResolver, useNitroApp, useRuntimeConfig } from '#imports'
import { getRouteRulesForPath } from '#internal/nitro/route-rules'
import pages from '#nuxt-simple-sitemap/pages.mjs'

Expand All @@ -12,7 +12,7 @@ export default defineEventHandler(async (e) => {
if (!path.endsWith('-sitemap.xml'))
return

const { moduleConfig, buildTimeMeta, version } = useRuntimeConfig()['nuxt-simple-sitemap'] as any as ModuleRuntimeConfig
const { moduleConfig, buildTimeMeta } = useRuntimeConfig()['nuxt-simple-sitemap'] as any as ModuleRuntimeConfig
if (!moduleConfig.sitemaps) {
/// maybe the user is handling their own sitemap?
return
Expand All @@ -22,19 +22,8 @@ export default defineEventHandler(async (e) => {
if (moduleConfig.sitemaps !== true && !moduleConfig.sitemaps[sitemapName])
return

const useCache = moduleConfig.runtimeCacheStorage && !process.dev && moduleConfig.cacheTtl && moduleConfig.cacheTtl > 0
const baseCacheKey = moduleConfig.runtimeCacheStorage === 'default' ? `/cache/nuxt-simple-sitemap${version}` : `/nuxt-simple-sitemap/${version}`
const cache = prefixStorage(useStorage(), `${baseCacheKey}/sitemaps`)
// cache will invalidate if the options change
const key = sitemapName
let sitemap: string
if (useCache && await cache.hasItem(key)) {
const { value, expiresAt } = await cache.getItem(key) as any
if (expiresAt > Date.now())
sitemap = value as string
else
await cache.removeItem(key)
}
const { cachedSitemap, cache } = await setupCache(e, sitemapName)
let sitemap = cachedSitemap

if (!sitemap) {
const nitro = useNitroApp()
Expand All @@ -61,8 +50,7 @@ export default defineEventHandler(async (e) => {
await nitro.hooks.callHook('sitemap:output', ctx)
sitemap = ctx.sitemap

if (useCache)
await cache.setItem(key, { value: sitemap, expiresAt: Date.now() + (moduleConfig.cacheTtl || 0) })
await cache(sitemap)
}

// need to clone the config object to make it writable
Expand Down
29 changes: 8 additions & 21 deletions src/runtime/routes/sitemap.xml.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,24 @@
import { defineEventHandler, sendRedirect, setHeader } from 'h3'
import { defineEventHandler, getQuery, sendRedirect, setHeader } from 'h3'
import { withBase } from 'ufo'
import { prefixStorage } from 'unstorage'
import type { ModuleRuntimeConfig, SitemapRenderCtx } from '../types'
import { buildSitemap } from '../sitemap/builder'
import { createSitePathResolver, useRuntimeConfig, useStorage } from '#imports'
import { setupCache } from '../util/cache'
import { createSitePathResolver, useRuntimeConfig } from '#imports'
import { useNitroApp } from '#internal/nitro'
import { getRouteRulesForPath } from '#internal/nitro/route-rules'
import pages from '#nuxt-simple-sitemap/pages.mjs'

export default defineEventHandler(async (e) => {
const { moduleConfig, buildTimeMeta, version } = useRuntimeConfig()['nuxt-simple-sitemap'] as any as ModuleRuntimeConfig
const { moduleConfig, buildTimeMeta } = useRuntimeConfig()['nuxt-simple-sitemap'] as any as ModuleRuntimeConfig
// we need to check if we're rendering multiple sitemaps from the index sitemap
if (moduleConfig.sitemaps) {
// redirect to sitemap_index.xml (302 in dev to avoid caching issues)
return sendRedirect(e, withBase('/sitemap_index.xml', useRuntimeConfig().app.baseURL), process.dev ? 302 : 301)
}

const useCache = moduleConfig.runtimeCacheStorage && !process.dev && moduleConfig.cacheTtl && moduleConfig.cacheTtl > 0
const baseCacheKey = moduleConfig.runtimeCacheStorage === 'default' ? `/cache/nuxt-simple-sitemap${version}` : `/nuxt-simple-sitemap/${version}`
const cache = prefixStorage(useStorage(), `${baseCacheKey}/sitemaps`)
// cache will invalidate if the options change
const key = 'sitemap'
let sitemap: string
if (useCache && await cache.hasItem(key)) {
const { value, expiresAt } = await cache.getItem(key) as any
if (expiresAt > Date.now())
sitemap = value as string
else
await cache.removeItem(key)
}

if (!sitemap) {
const { cachedSitemap, cache } = await setupCache(e, 'sitemap', getQuery(e).purge)
let sitemap = cachedSitemap
if (!cachedSitemap) {
const nitro = useNitroApp()
const callHook = async (ctx: SitemapRenderCtx) => {
await nitro.hooks.callHook('sitemap:resolved', ctx)
Expand All @@ -51,8 +39,7 @@ export default defineEventHandler(async (e) => {
await nitro.hooks.callHook('sitemap:output', ctx)
sitemap = ctx.sitemap

if (useCache)
await cache.setItem(key, { value: sitemap, expiresAt: Date.now() + (moduleConfig.cacheTtl || 0) })
await cache(sitemap)
}
// need to clone the config object to make it writable
setHeader(e, 'Content-Type', 'text/xml; charset=UTF-8')
Expand Down
26 changes: 7 additions & 19 deletions src/runtime/routes/sitemap_index.xml.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,17 @@
import { defineEventHandler, setHeader } from 'h3'
import { prefixStorage } from 'unstorage'
import { buildSitemapIndex } from '../sitemap/builder'
import type { ModuleRuntimeConfig, SitemapRenderCtx } from '../types'
import { createSitePathResolver, useRuntimeConfig, useStorage } from '#imports'
import { setupCache } from '../util/cache'
import { createSitePathResolver, useRuntimeConfig } from '#imports'
import { getRouteRulesForPath } from '#internal/nitro/route-rules'
import pages from '#nuxt-simple-sitemap/pages.mjs'
import { useNitroApp } from '#internal/nitro'

export default defineEventHandler(async (e) => {
const { moduleConfig, buildTimeMeta, version } = useRuntimeConfig()['nuxt-simple-sitemap'] as any as ModuleRuntimeConfig

const useCache = moduleConfig.runtimeCacheStorage && !process.dev && moduleConfig.cacheTtl && moduleConfig.cacheTtl > 0
const baseCacheKey = moduleConfig.runtimeCacheStorage === 'default' ? `/cache/nuxt-simple-sitemap${version}` : `/nuxt-simple-sitemap/${version}`
const cache = prefixStorage(useStorage(), `${baseCacheKey}`)
// cache will invalidate if the options change
const key = 'sitemap_index'
let sitemap: string
if (useCache && await cache.hasItem(key)) {
const { value, expiresAt } = await cache.getItem(key) as any
if (expiresAt > Date.now())
sitemap = value as string
else
await cache.removeItem(key)
}
const { moduleConfig, buildTimeMeta } = useRuntimeConfig()['nuxt-simple-sitemap'] as any as ModuleRuntimeConfig

const { cachedSitemap, cache } = await setupCache(e, 'sitemap_index')
let sitemap = cachedSitemap

const nitro = useNitroApp()
const callHook = async (ctx: SitemapRenderCtx) => {
Expand All @@ -47,8 +36,7 @@ export default defineEventHandler(async (e) => {
await nitro.hooks.callHook('sitemap:output', ctx)
sitemap = ctx.sitemap

if (useCache)
await cache.setItem(key, { value: sitemap, expiresAt: Date.now() + (moduleConfig.cacheTtl || 0) })
await cache(sitemap)
}

setHeader(e, 'Content-Type', 'text/xml; charset=UTF-8')
Expand Down
46 changes: 46 additions & 0 deletions src/runtime/util/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { prefixStorage } from 'unstorage'
import type { H3Event } from 'h3'
import { getQuery, setHeader } from 'h3'
import type { ModuleRuntimeConfig } from '../types'
import { useRuntimeConfig, useStorage } from '#imports'

export async function setupCache(e: H3Event, key: string) {
const { moduleConfig, buildTimeMeta } = useRuntimeConfig()['nuxt-simple-sitemap'] as any as ModuleRuntimeConfig

const useCache = moduleConfig.runtimeCacheStorage && moduleConfig.cacheTtl && moduleConfig.cacheTtl > 0
const baseCacheKey = moduleConfig.runtimeCacheStorage === 'default' ? `/cache/nuxt-simple-sitemap${buildTimeMeta.version}` : `/nuxt-simple-sitemap/${buildTimeMeta.version}`
const cache = prefixStorage(useStorage(), `${baseCacheKey}/sitemaps`)
let xSitemapCacheHeader = 'MISS'
let xSitemapCacheExpires = 0
const purge = typeof getQuery(e).purge !== 'undefined'
// cache will invalidate if the options change
let cachedSitemap: string | false = false
if (useCache && await cache.hasItem(key)) {
const { value, expiresAt } = await cache.getItem(key) as any
if (expiresAt > Date.now()) {
if (purge) {
xSitemapCacheHeader = 'PURGE'
await cache.removeItem(key)
}
else {
xSitemapCacheHeader = 'HIT'
xSitemapCacheExpires = expiresAt
cachedSitemap = value as string
}
}
else {
await cache.removeItem(key)
}
}
// append the headers
setHeader(e, 'x-sitemap-cache', xSitemapCacheHeader)
setHeader(e, 'x-sitemap-cache-expires', xSitemapCacheExpires.toString())

return {
cachedSitemap,
cache: async (sitemap: string) => {
if (useCache)
await cache.setItem(key, { value: sitemap, expiresAt: Date.now() + (moduleConfig.cacheTtl || 0) })
},
}
}

0 comments on commit 271abbe

Please sign in to comment.