nuxt-multi-cache
Version:
SSR route, component and data cache for Nuxt.js
304 lines (303 loc) • 10.3 kB
TypeScript
/// <reference types="node" />
import type { OutgoingHttpHeaders } from 'node:http';
import type { CreateStorageOptions, Storage } from 'unstorage';
import type { H3Event } from 'h3';
import type { NuxtMultiCacheRouteCacheHelper } from './helpers/RouteCacheHelper.js';
import type { NuxtMultiCacheCDNHelper } from './helpers/CDNHelper.js';
import type { MultiCacheState } from './helpers/MultiCacheState.js';
interface CacheConfigOptions {
/**
* Set if the cache is enabled.
*
* While the cache will be disabled during the app's runtime, all the
* corresponding code (components, composables, etc.) will still be added,
* even if the value is `false` here. This is so that it's possible to
* disable caching without having to refactor your code.
*
* If you wish to completely disable a feature so that no code is added just
* leave the entire configuration property undefined.
*/
enabled?: boolean;
}
export type CDNOptions = {
/**
* Enable the CDN headers feature.
*/
enabled: boolean;
/**
* The header to use for the cache-control settings.
*/
cacheControlHeader?: string;
/**
* The header to use for the cache tags header.
*/
cacheTagHeader?: string;
};
export interface NuxtMultiCacheOptions {
/**
* Component cache.
*
* When enabled you can use the <RenderCacheable> wrapper component to cache
* the generated markup of its slot children. Each subsequent request will
* load the markup from cache and bypass rendering entirely.
*
* This is generally used for global components like navigation or footer,
* but it can also be used to cache an entire page when used in a layout
* component. It also supports caching payloads.
*
* The performance improvements are most noticeable if you have complex
* components and a lot of pages.
*/
component?: CacheConfigOptions;
/**
* Generic data cache.
*
* Can be used for anything: Caching API responses, expensive calculations,
* slow external APIs, etc.
*/
data?: CacheConfigOptions;
/**
* Route cache.
*
* Caches routes based on the path. Works for both rendered Nuxt pages and
* server API routes.
*/
route?: CacheConfigOptions;
/**
* Configuration for the CDN headers feature.
*
* This feature allows you to manage special HTTP headers used by
* Cloudflare, Fastly, Varnish and other caching services. These headers
* control how long a page should be cached, how long stale cache entries
* should be served, what the cache tags are, etc.
*
* Note that this is fundamentally different to the route cache: This
* feature only sets response headers, while the route cache actually caches
* pages.
*
* In addition, these headers are never sent to the client. They are
* intercepted by the CDN/HTTP cache and only used internally.
*
* It's possible to use both the CDN feature and the route cache at the same
* time. Note that they each have independent state; e.g. if you set a max
* age for the route cache it doesn't affect the max age value for the CDN
* headers.
*/
cdn?: CDNOptions;
/**
* Settings for the API endpoints.
*/
api?: {
/**
* Enable the API endpoints for cache management.
*/
enabled?: boolean;
/**
* The prefix used for the API endpoints.
*
* @default '/__nuxt_multi_cache'
*/
prefix?: string;
/**
* The authorization for the API endpoints.
*
* If a string is provided, the auth check will be done using the
* `x-nuxt-multi-cache-token` header.
*
* If a function is provided you can implement a custom auth check that
* should return a Promise that resolves to true or false.
*
* If `false` is provided then authorization check is skipped. Only do
* this if you made sure that the API endpoints are not public, since this
* can potentially leak sensitive information via cached data or allow
* anyone to purge cache entries!
*/
authorization: string | false;
/**
* Delay for invalidating cache tags.
*
* Since purging by cache tag requires looping over all cache entries this
* action is debounced. The value (in milliseconds) will be the amount of
* delay that is used to buffer incoming tag invalidations. The delay is
* fixed and starts when the first invalidation request comes in, then all
* requests are added to the buffer. Once the delay is over, the cache
* entries for all the tags are purged and the timeout is reset.
*/
cacheTagInvalidationDelay?: number;
};
/**
* Log detailled messages to the console.
*/
debug?: boolean;
}
export interface NuxtMultiCacheSSRContext {
/**
* The component cache instance.
*/
component?: Storage;
/**
* The data cache instance.
*/
data?: Storage;
/**
* The route cache instance.
*/
route?: Storage;
}
export interface CacheItem {
data: string;
expires?: number;
cacheTags?: string[];
}
export interface RouteCacheItem extends CacheItem {
headers: Record<string, any>;
statusCode: number;
staleWhileRevalidate: boolean;
staleIfErrorExpires?: number;
}
export interface ComponentCacheItem extends CacheItem {
payload?: Record<string, any>;
}
export type ComponentCacheEntry = ComponentCacheItem | string;
export type MultiCacheServerOptions = {
component?: {
storage?: CreateStorageOptions;
};
data?: {
storage?: CreateStorageOptions;
};
route?: {
storage?: CreateStorageOptions;
/**
* Provide a custom function that builds the cache key for a route.
*/
buildCacheKey?: (event: H3Event) => string;
/**
* Alter the headers that are stored in the cache.
*
* You can use this to prevent certain headers from ever being cached,
* such as Set-Cookie.
*/
alterCachedHeaders?: (headers: OutgoingHttpHeaders) => OutgoingHttpHeaders | Record<string, any>;
/**
* A function to determine whether route caching is potentially possible.
*
* In order to minimize the number of calls to get routes from the cache,
* it makes sense to already exclude certain paths, such as `/_nuxt` or static assets like .css, .js, .png, .jpg, etc.
*/
applies?: (path: string) => boolean;
};
/**
* Determine if caching should be used for the given request.
*
* If the method resolves to `false` the cache context singleton is not
* attached to the request, which prevents getting and setting cache entries
* for the duration of the request.
*
* This does not affect the CDN feature.
*
* One use case might be to prevent caching for requests coming from
* authenticated users to make it impossible to cache sensitive data.
* Or to offer a quick way to disable caching based on local or remote
* configuration.
*/
enabledForRequest?: (event: H3Event) => Promise<boolean>;
/**
* Define a global cache key prefix.
*
* Can be a string or a method that returns a promise that resolves to a
* string given the H3 request event.
*
* This is useful if you have multiple Nuxt instances running on the same
* code base but with a different global context. For example in a
* multi-domain setup you might have one instance per domain, but each
* instance uses the same cache backend (e.g. redis). Setting a global prefix
* will make sure that each instance is scoped.
*/
cacheKeyPrefix?: string | ((event: H3Event) => Promise<string>);
api?: {
/**
* The authorization for the API endpoints.
*
* should return a Promise that resolves to true or false.
*/
authorization?: (event: H3Event) => Promise<boolean>;
};
};
export type MutliCacheServerOptions = MultiCacheServerOptions;
export type MultiCacheRuntimeConfig = {
cdn: {
enabled: boolean;
cacheControlHeader: string;
cacheTagHeader: string;
};
component: boolean;
data: boolean;
route: boolean;
api: {
enabled: boolean;
prefix: string;
cacheTagInvalidationDelay: number;
authorizationToken: string;
authorizationDisabled: boolean;
};
};
export interface MultiCacheApp {
/**
* The cache singleton.
*/
cache: NuxtMultiCacheSSRContext;
/**
* The server options.
*/
serverOptions: MultiCacheServerOptions;
/**
* The runtime configuration.
*/
config: MultiCacheRuntimeConfig;
/**
* The state.
*/
state: MultiCacheState;
}
declare module 'nitropack' {
interface NitroApp {
/**
* The nuxt-multi-cache cache context.
*/
multiCache: MultiCacheApp;
}
}
declare module 'h3' {
interface H3Event {
/**
* The nuxt-multi-cache cache context.
*/
__MULTI_CACHE?: NuxtMultiCacheSSRContext;
/**
* The nuxt-multi-cache route cache helper.
*/
__MULTI_CACHE_ROUTE?: NuxtMultiCacheRouteCacheHelper;
/**
* The nuxt-multi-cache CDN helper.
*/
__MULTI_CACHE_CDN?: NuxtMultiCacheCDNHelper;
/**
* The nuxt-multi-cache global cache prefix that is applied to all caches.
*/
__MULTI_CACHE_PREFIX?: string;
/**
* Contains the already fetched cached route, if it exists.
*/
__MULTI_CACHE_DECODED_CACHED_ROUTE?: RouteCacheItem;
/**
* The route cache key that is currently being revalidated.
*/
__MULTI_CACHE_REVALIDATION_KEY?: string;
/**
* Whether the current request has already been served from cache.
*/
__MULTI_CACHE_SERVED_FROM_CACHE?: boolean;
}
}
export {};