-
Notifications
You must be signed in to change notification settings - Fork 514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support serializable options to configure caching route rules #1048
Comments
I am concerned that |
I believe this is something that I need but I may be misunderstanding so sorry if I am. My use case is that I'm using ISR to keep my site cached as I'm using a headless CMS to serve content. I'm using ISR as a way to serve the content ASAP. However, I'd also like it if a user publishes new content/changes in Storyblok (CMS), i could selectively/programmatically invalidate the cache so that the published changes are reflected in the live site. Not sure if the above use case is related to this but it was something I've been searching for and this seemed the closest. |
This comment was marked as off-topic.
This comment was marked as off-topic.
We are exploring solutions to bypass caching for logged-in users within our Nuxt 3 application. It would be ideal to have a feature that allows specifying conditions under which route caching should be bypassed, such as the presence of an authentication cookie. @pi0 Is there currently any method or workaround available to selectively disable caching under certain conditions? For instance, could we leverage Nitro server middleware to achieve this? |
@jony1993 Not with route rules yet but you can simply replace route rule with defineCachedEventHandler with |
@jony1993 I just wrote a nitro plugin that imports the nuxt handler and manually wraps it with a cachedEventHandler call and pass the options that way |
@pi0 Thanks for the quick response. You mean something like this? (for example in
|
@MiniDigger Could you share the code of your plugin you mentioned above? |
@swissmexxa its, uhhm, not pretty but it works, lol export default defineNitroPlugin((nitroApp) => {
// find our handler
const h = (eval("handlers") as HandlerDefinition[]).find((ha) => ha.route === "/**");
if (!h) {
nitroLog("Not enabling ISG cause we didn't find a matching handler");
return;
}
const handler = cachedEventHandler(lazyEventHandler(h.handler), {
group: "pages",
swr: false,
maxAge: 30 * 60,
name: "pagecache",
getKey,
shouldInvalidateCache,
shouldBypassCache,
} as CacheOptions);
nitroLog("installing handler", h.route);
nitroApp.router.use(h.route, handler, h.method); and then I just have methods like this: function shouldInvalidateCache(e: H3Event)
function shouldBypassCache(e: H3Event)
function getKey(e: H3Event) bascially, I rely on nitro packaging the handles and my plugin into the same file and that nitro defines a |
Please forgive me for not understanding the example you wrote. In which folder is this example written? What if I want to customize the cache key based on the full URL of the current page, or non-parameters in the URL? I tried printing the path information, but unfortunately, it didn't output anything. |
@MiniDigger Thank you very much for your example @lxccc812 This file would be placed inside the server/plugins folder. The defineCachedEventHandler function has an option object as second parameter where you can set a getKey function. This function will receive the event object as parameter where you can get the request URL and Query parameter as follow:
Then you can create your own logic for creating a string key and return it inside the getKey function. I have found a quite simple solution to just disable the generation of the Nuxt cache under certain conditions in Nuxt 3 with routeRules if this already helps you: server/plugins/nuxt-cache-invalidator.ts
nuxt.config.ts
|
@lxccc812 Define your routeRules directly in the root of your nuxt.config object and not under nitro. I made a stackblitz example for you: https://stackblitz.com/edit/github-v24i7v-dipodp You can call any sub route (ex. My solution is only to prevent the generation of a cache entry by Nuxt under certain conditions (for example when a user is logged in or you are in preview mode of a CMS with query params). If you want to also change the structure of the generated cache key you will have to have a look at the solution of MiniDigger. Hope it helps |
Thank you for your patient answer, but for me, what I need more is how to customize the cache key name.
Thanks again, I also learned a lot from your answers. |
@lxccc812 I made you another stackblitz including an example of MiniDigger: https://stackblitz.com/edit/github-v24i7v-kkln93 You have the same behavior from the stackblitz of the previous comment but now there is additional code in |
@swissmexxa Thank you for your example. When I tested the example you gave me, I found that if I have multiple routes that need to be cached, how should I accurately obtain the handler relative to the page route? I printed the handlerList, which includes all routes with cache declared in routeRules. I modified your example a little bit, the address is here Example Now I can only customize the cache key name of route a |
@lxccc812 with this
you search an element in a list where route is either /a or /b. So it will stop at /a because it comes first in the list and return it. Therefore it will always return the handler for /a and not /b. You will have to define code for every route you define in routeRules. rough example:
For the example of an earlier comment above with these pages:
The routeRules would be
and would get handlers as follow:
or you could just add one routeRule /** with one handler and decide in the getKey method of the one handler how the key should be created based on the path which you can get with the H3Event parameter of the getKey function. |
@swissmexxa Thank you again for your patient answer. The sign to generate cache is to enter the getKey function, so what is the sign to use cache?In this example, when I click on any link, it goes into the function getKey and returns the custom string. Does this mean that I create the cache on each click instead of using the cache generated on the first click on the second click. Does this mean that the cache has been used? If I have two or more users accessing page/a on different devices, then when the different users access the page again (a second request to the server), will they retrieve it from cache? Return a response to reduce server pressure. |
I found a new problem. If I access ?t=2 and successfully generate cache with t variable, then when I access ?t=2&x=1 again, it will automatically jump to ?t=2, which is not what I want. What I need is access to ?t=2&x=1 or other similar links with multiple indeterminate parameters. It will return the cache of ?t=2 and keep the original link without redirecting or jumping to the ?t=2 link. You can see a related demo here I also wrote a workaround, but I'm not sure if it will bypass the cache and access the server directly. shouldBypassCache: (event: H3Event) => {
const queries = getQuery(event);
const cacheKeys = ['t'];
const queryKeys = Object.keys(queries);
const hasOtherQuery = queryKeys.some(
(queryKey) => !cacheKeys.includes(queryKey)
);
return hasOtherQuery;
}, |
in lieu of an official solution - I thought I'd add what I've done (building on other contributors' insights here): // nuxt.config.ts
...
routeRules: {
'/your-path/**': {
cache: {} // just a placeholder that we can augment in our server-plugin
}
} // server/plugins/your-handler.ts
import { parseURL } from 'ufo'
import { hash } from 'ohash'
// @ts-expect-error virtual file
import { handlers } from '#internal/nitro/virtual/server-handlers' // eslint-disable-line import/no-unresolved
import type { HandlerDefinition } from 'nitropack/runtime/virtual/server-handlers'
function escapeKey(key: string | string[]) {
return String(key).replace(/\W/g, '')
}
export default defineNitroPlugin(nitroApp => {
const foundHandler = (handlers as HandlerDefinition[]).find(
ha => ha.route === '/your-path/**' // < Whatever pattern you're looking to cache
)
if (!foundHandler) return
const handler = cachedEventHandler(lazyEventHandler(foundHandler.handler), {
swr: true,
maxAge: 3600,
getKey: async event => {
// This is mainly yoinked from the default nitro `getKey`
// (https://github.com/unjs/nitro/blob/v2/src/runtime/internal/cache.ts - pathname + hashed props)
const path =
event.node.req.originalUrl || event.node.req.url || event.path
const decodedPath = decodeURI(parseURL(path).pathname)
const pathname =
escapeKey(decodeURI(parseURL(path).pathname)).slice(0, 16) || 'index'
const hashedPath = `${pathname}.${hash(path)}.${ANYTHING_ELSE_YOU_WANT_HERE_USING_HEADERS_OR_WHATEVER}`
return hashedPath
},
})
nitroApp.router.use(foundHandler.route, handler, foundHandler.method)
console.info('installed routeRules cache handler', foundHandler.route)
}) |
Related: #977
Since route rules only accept serializable options, and for best DX, we can introduce a configuration API that defines caching route rules as an alternative to non-serializable options (
shouldInvalidateCache
~>invalidateHeaders
,getKey
~>keyTemplate
)The text was updated successfully, but these errors were encountered: