Code Monkey home page Code Monkey logo

nuxt-multi-cache's People

Contributors

applelo avatar blackyuzia avatar dulnan avatar hpawa avatar niddu85 avatar or2e avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

nuxt-multi-cache's Issues

Huge JSON

setItem serializes passed value to JSON string. Also afterwards getItem use JSON.parse to de-serialize value back.

In cases when page size is big, say, 1-2 Megabytes this has significant effect on performance. JSON.parse cause high CPU load and it's event blocking (so server stop doing other stuff like accept incoming requests)

As possible solution is use two records one for page itself other for meta (statusCodes, headers)
page content may by stored by using getItemRaw/setItemRaw which don't do serialization to JSON.

Also is possible to use single record but avoid usage JSON parse and implement own lightweight serialization, ie store record in next way format: {statusCode: 200, headers: []}<DELIMETER><html>...</html>
and extract small JSON

const delimiterPos = record.indexOf('<DELIMETER>')
const meta = JSON.parse(record.substr(0,delimiterPos))
const data = record.substr(delimiterPos)

So we may avoid parsing huge JSONs

Incomplete/incorrectly cached pages?

Hello,

I'm currently testing the plugin in the V1 version, there will still be a Nuxt2 application.

I often have the problem that individual pages are not cached correctly. It appears that certain elements are simply missing, e.g. because a background image or buttons are not displayed correctly. Also the dropdown of the main navigation does not work then.

In Sentry I see the following error:

HierarchyRequestError
Object.appendChild(97f3cfd.modern)
Failed to execute 'appendChild' on 'Node': This node type does not support this method.

We have 4 node instances on our server in parallel operation. Here I can see that the page is displayed correctly in some node instances and the error occurs in other instances. I can see this because as a test I appended a Math.random() to the title of the page.

Unfortunately I can't get any further and I don't know how to solve the problem.

I would be grateful for any tips and help!

Best regards

Timo

bug with consola

in some cases an error occurs when accessing to consola

Cannot read properties of undefined (reading 'withTag')

Shared state between processes ?

Hi,

Today I am facing a problem on my production environment.

Each day I purge the yesterday cache using /__nuxt_multi_cache/purge/all but it looks when we are using pm2 with multiple processes the cache state is not shared : some of my nuxt processes have the cache gone, some not.

Is the cache state is shared between processes on production or specific to a process ?

Thanks.

When depoloying app using nuxt-multi-cache module, cache is not active

after runningnpm run build in my app where nuxt.config.ts file is

export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      ...
    },
  },
  modules: ["nuxt-multi-cache"],
  typescript: { strict: true, typeCheck: true },
  multiCache: {
    route: {
      enabled: true,
      storage: {
        driver: redisDriver({
          db: 2,
          host: "my.redis.server",
          port: 6379,
          base: "My.Site",
        }),
      },
    },
    cacheKeyPrefix: (event): Promise<string> => {
      return new Promise<string>((resolve) => {
        resolve(useSSRHelper().GetAleCacheKeyPrefix(event));
      });
    },
    api: {
      enabled: true,
      prefix: "/__nuxt_multi_cache",
      authorization: process.env.CACHE_PURGE_AUTH, 
      cacheTagInvalidationDelay: 10000,
    },
  },
});

the cache is disabled.

Looking in the dist folder generated by the build, i see the multiCache configuration is taken from [sourceDir]\nuxt.config.ts (eg: c:\mysources\myapp\nuxt.config.ts), which of course does not exists on production server.

The configuration should be bundled during the compile process

Cannot cache same route with different tags

I'm trying to cache a route (the homepage of my website) on redis depending on the language.
The same page responds with different HTMLs depending on the selected language (eg www.site.com is for english, fr.site.com is for french, de.site.com is for german...), but if i cache the page using

const currentLanguage = getCurrentLanguage();

  useRouteCache((helper) => {
    helper
      .setMaxAge(300)
      .setCacheable()
      .addTags([
    `page:homepage`,
    `lang:${currentLanguage}`,
  ]);
  });

only one entry is saved on Redis.

How can i accomplish this?

thanks in advance

No redis connection with DataCache

Hi,

i make some tests with your module and can´t understand the reason why ist does not work.
In nuxt.config.js:

multiCache: {
        data: {
            enabled: true,
            storage: {
                driver: redisDriver({
                    base: "",
                    host: '127.0.0.1',
                    port: 6379,
                    //password: 'REDIS_PASSWORD'
                })
            }
        }
    },

On my serverside endpoint /api/test
import { useDataCache } from '#nuxt-multi-cache/composables';

const { value, addToCache } = await useDataCache('my_data')
    if (value) {
        return value
    }
    const response = await getLiveData()
    addToCache(response)

This has no effect. Nuxt dont connect to the Redis-Server.

A second test with unstoreage works...

import { createStorage } from "unstorage";
import redisDriver from "unstorage/drivers/redis";
const storage = createStorage({
        driver: redisDriver({
            base: "",
            host: '127.0.0.1',
            port: 6379,
            //password: 'REDIS_PASSWORD'
        }),
    });

    const item = await storage.getItem("my_data");
    if(item){
        return item
    }

I check your documentation but i can not see the problem.
Have you any idea how to solve the problem?

SETUP: nuxt 3.2.2; nodejs 18; redis 6.0.9 via Mamp pro on Macbook pro m1

Broken Typescript exports

When trying to import types from either the package directly or from /dist/runtime/serverOptions i get the following typeerror:

Could not find a declaration file for module 'nuxt-multi-cache'. 'xxx/node_modules/nuxt-multi-cache/dist/module.mjs' implicitly has an 'any' type.
  There are types at '/xxx/node_modules/nuxt-multi-cache/dist/types.d.ts', but this result could not be resolved when respecting package.json "exports". The 'nuxt-multi-cache' library may need to update its package.json or typings.ts(7016)

I will try to provide a minimal reproduction later today

Preventing caching globally

Currently setting enabledForRequest to false only prevents caching of pages. The idea was that this prevents anything from being cached, including components. The use case being that for example logged in users should not put anything in the cache.

The problem is that there is no way to achieve that using vue-server-renderer: It will always call the serverCacheKey() method on a component and expects it to return a string, which is then passed to the component cache instance. At that point this module is unable to tell if it should write it in the cache or not, because no context about the request is available.

Maybe there is a different way to approach this problem, some time should be invested to look for solutions.

Redis TTL

Currently ttl is not passed during setItem call as result TTL is not set for Redis.

This causes that Redis can't remove records in different circumstances, for instance when no free memory left and to add new record Redis have to remove some old records. Having TTL redis could remove records which have lower TTL which expire anyway soon.

Basically, having TTL in Redis record may increase efficiency of Redis usage and memory usage by better cleanup.

Add should not be complicated since setItem support third parameter

https://github.com/dulnan/nuxt-multi-cache/blob/main/src/runtime/serverHandler/responseSend.ts#L96-L98

Verbose runtime option

Hi ;)
It would be useful to add an option for log management

Scenario: in dev-mode it is necessary to turn off cache components, then we get log messages

Log

image

Temporary solution: use prop :noCache

Example
export const useCacheEnabled = () => {
    const { isServer } = useProcess();
    const noCache = computed(
        () => isServer && useRuntimeConfig().multiCache.component === false
    );

    return {
        noCache,
    };
};

...
const { noCache } = useCacheEnabled();
...
RenderCacheable(:noCache='noCache')

Unfortunately, I couldn't make a wrapper for the RenderCacheable component, because of this part

Problem using Vue alias

I'm using vue3-runtime-template and according to the documentation I must use the with-compiler Vue.js version:

// nuxt.config.js
{
 (...)

 hooks: {
      'vite:extendConfig': (config, { isClient, isServer }) => {
        if (isClient) {
          config.resolve.alias.vue = 'vue/dist/vue.esm-bundler'
        }
      },
    },

  (...)

But when using along with nuxt-multi-cache an error occurs:
[14:52:35] ERROR Failed to load url vue/dist/vue.esm-bundler/server-renderer (resolved id: vue/dist/vue.esm-bundler/server-renderer) in /home/project/frontend/node_modules/nuxt-multi-cache/dist/runtime/components/RenderCacheable/helpers/index.mjs. Does the file exist?

Is it possible to solve this somehow?

@dulnan

Cannot find module 'nuxt-graphql-middleware/dist/runtime/serverOptions' or its corresponding type declarations.

When I do an import of this function 'import { defineGraphqlServerOptions } from 'nuxt-graphql-middleware/dist/runtime/serverOptions', typescript is throwing the following error:
Cannot find module 'nuxt-graphql-middleware/dist/runtime/serverOptions' or its corresponding type declarations.

I think it is related to "moduleResolution": "Bundler" added in nuxt with typescript 5 (see https://publint.dev/rules#types_not_exported).

Hangs after build with module @nuxt/content

Edit: Reproduced with a new nuxt app, it seems that when [email protected] is installed with @nuxt/[email protected] then the build hangs

As it says, hangs after ✔ You can preview this build using node .output/server/index.mjs which prevents my build pipelines from completing.
But works fine during dev

Nuxi info:

- Operating System: `Linux`
- Node Version:     `v18.17.1`
- Nuxt Version:     `3.7.4`
- CLI Version:      `3.9.0`
- Nitro Version:    `2.6.3`
- Package Manager:  `[email protected]`
- Builder:          `-`
- User Config:      `devtools`, `ssr`, `modules`, `multiCache`, `i18n`, `build`, `nitro`, `loading`, `app`, `content`, `server`, `runtimeConfig`, `delayHydration`, `image`, `css`, `tailwindcss`, `postcss`, `vite`
- Runtime Modules:  `[email protected]`, `@nuxtjs/[email protected]`, `@nuxtjs/[email protected]`, `[email protected]`, `@nuxtjs/[email protected]`, `@nuxt/[email protected]`, `[email protected]`, `@pinia/[email protected]`, `@pinia-plugin-persistedstate/[email protected]`, `[email protected]`
- Build Modules:    `-`

my nuxt.config:

export default defineNuxtConfig({
  devtools: {
    enabled: true,

    timeline: {
      enabled: true,
    },
  },

  ssr: true,

  modules: [
    "nuxt-graphql-client",
    "@nuxtjs/tailwindcss",
    "@nuxtjs/device",
    "nuxt-schema-org",
    "@nuxtjs/i18n",
    "@nuxt/content",
    "nuxt-swiper",
    "@pinia/nuxt",
    "@pinia-plugin-persistedstate/nuxt",
    "nuxt-multi-cache"
  ],

  multiCache: {
    component: {
      enabled: true,
    },
    data: {
      enabled: true,
    },
    route: {
      enabled: true,
    },
    // Purge or inspect api [read more](https://nuxt-multi-cache.dulnan.net/features/api)
    api: {
      enabled: process.env.VIATU_ENV !== 'prod',
      prefix: '/__cache',
      authorization: false,
      cacheTagInvalidationDelay: 60000
    },
    debug: true
  },
});

My multiCache.serverOptions.ts

export default defineMultiCacheOptions({
  data: {
    storage: {
      driver: redisDriver({
        base: 'data:',
        host: process.env.CACHE_HOST,
        port: parseInt(process.env.CACHE_PORT ? process.env.CACHE_PORT : '6379'),
      }),
    },
  },

  component: {
    storage: {
      driver: redisDriver({
        base: 'component:',
        host: process.env.CACHE_HOST,
        port: parseInt(process.env.CACHE_PORT ? process.env.CACHE_PORT : '6379'),
      }),
    },
  },
  route: {
    storage: {
      driver: redisDriver({
        base: 'route:',
        host: process.env.CACHE_HOST,
        port: parseInt(process.env.CACHE_PORT ? process.env.CACHE_PORT : '6379'),
      }),
    }
  },
})

Data cache outside component

Hello )

I am trying to make data caching work when called in a server plugin or server middleware
As far as I understand, there must be a vue component where useDataCache is called

My scenario:
In plugins/init.server.ts I do a global data load. Unfortunately, doing it in app.vue is not working for me, coz I need this data in several middleware, and they are processed after app.vue ref: https://miro.medium.com/v2/resize:fit:828/format:webp/1*v-pnTrIP-Kq29k52BIGp8g.png

CORS setup for API route

Hey @dulnan, great project here 🙌

I'm running into an issue where I'm calling the purge API from another server. For that, I had to configure CORS for my purge route.

This is what I added:

// ~/server/middleware/cors.ts

export default defineEventHandler((event) => {
  if (!event.req.url?.startsWith('/__cache/')) return

  setResponseHeaders(event, {
    'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Credentials': 'true',
    'Access-Control-Allow-Headers': '*',
    'Access-Control-Expose-Headers': '*',
  })

  if (event.method === 'OPTIONS') {
    event.node.res.statusCode = 204
    event.node.res.statusMessage = 'No Content.'
    return 'OK'
  }
})

I can add it to docs if you agree. It might be useful to other people.

Bug: $cache.route.setCacheable() instead $cache.page.setCacheable()

Hello,

First, thanks for this awesome plugin, I started making my own cache plugin because none of the ecosystem was good enough, but finally I found yours and he is perfect :)

The bug :
I tried to use the page cache using $cache.page.setCacheable() as described on the documentation but it looks that you changed to API to $cache.route.setCacheable() ?

Conditionally set cache driver

Is there a option to conditionally change the cache driver depending on the runtime config.

I'm currently using the nitro route cache and there I can mount different drivers depending on my runtime config:

export default defineNitroPlugin(() => {
  const {
    useRedisCache,
  } = useRuntimeConfig();

  const storage = useStorage();
  if (!!useRedisCache ) {
    storage.mount(
      'cache',
      redisDriver({
        ...
      }),
    );
  } else {
    ...
  }
});

Is there a way to achieve this with your package? As far as I can see there is no option to pass a function instead of an config object to defineMultiCacheOptions.

Caching Pages Question

Hi There! I just started using this module and was curious if theres a setting I am possibly missing. I have the following configuration in my nuxt config:

multiCache: {
    enabled: true,
    outputDir: '~/cache',
    server: {
      auth: {
        username: 'admin',
        password: 'hunter2'
      },
    },
    pageCache: {
      enabled: true,
      lruOptions: {
        max: 100,
        maxSize: 5000,
        ttl: 1000 * 60 * 1, // 1 Minutes
        allowStale: false,
      },
    },
  },

Since I have the TTL set for 1 minute I was expecting that after 1 minute, the /__nuxt_multi_cache/stats/page API endpoint wouldn't returned a cached page that was expired. Is a cached page supposed to be removed from the API response after it expires? Currently this is my response for simply my homepage:

{
    "rows": [
        {
            "tags": [],
            "timestamp": 1675953158830,
            "key": "/"
        }
    ],
    "total": 1
}

But the page expired already (at least I think it should have lol).

Any insight would be awesome! thanks and so far this module looks great/exactly what I was looking for!!

Exclude cookies from route caching headers

Caching the cookies with a request is very problematic, as tracking cookies are then cached and breaks tracking.
Any user selection around privacy cookie or settings is overwritten.

Please can we exclude caching Cookie headers

useCachedAsyncData composable

I may be wrong, but most often we have to deal with asyncData
To avoid routine, I suggest creating a wrap-composable useCachedAsyncData

Example
import type { NuxtApp, AsyncDataOptions } from 'nuxt/app';
import type { KeysOf } from 'nuxt/dist/app/composables/asyncData';

export function useCachedAsyncData<
    ResT,
    DataT = ResT,
    PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
    DefaultT = null
>(
    key: string,
    handler: (ctx?: NuxtApp) => Promise<ResT>,
    options: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT> & {
        cacheKey: string;
        cacheTags: string[];
        cacheExpires?: number;
    }
) {
    // We need to cache transformed value to prevent value from being transformed every time.
    const transform = options?.transform;
    // Remove transform from options, so useAsyncData doesn't transform it again
    const optionsWithoutTransform = { ...options, transform: undefined };

    return useAsyncData(
        key,
        async () => {
            const { value, addToCache } = await useDataCache<
                DataT | Awaited<ResT>
            >(options.cacheKey);

            if (value) {
                return value;
            }

            const _result = await handler();
            const result = transform ? transform(_result) : _result;

            addToCache(result, options.cacheTags, options.cacheExpires);

            return result;
        },
        optionsWithoutTransform
    );
}

Route cache not working

After creating a blank nuxt project with
npx nuxi@latest init my-app

and enabling route caching on redis, it doesn't work

package.json

{
  "name": "nuxt-app",
  "private": true,
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare"
  },
  "devDependencies": {
    "@types/node": "^18",
    "nuxt": "^3.4.3"
  },
  "dependencies": {
    "nuxt-multi-cache": "^3.0.0"
  }
}

nuxt.config.ts

export default defineNuxtConfig({
  modules: ["nuxt-multi-cache"],
  multiCache: {
    route: {
      enabled: true,
    },
  },
});

app\multiCache.serverOptions.ts

import redisDriver from "unstorage/drivers/redis";
import { defineMultiCacheOptions } from "nuxt-multi-cache";

export default defineMultiCacheOptions({
  route: {
    storage: {
      driver: redisDriver({
        db: 4,
        host: "127.0.0.1",
        port: 6379,
        base: "route:",
      }),
    },
  },
});

app.vue

<script setup lang="ts">
useRouteCache((helper) => {
  helper.setCacheable().setMaxAge(9000);
});
</script>

<template>
  <div>
    <NuxtWelcome />
  </div>
</template>

Route Caching: ERR_CONTENT_DECODING_FAILED 200 (OK)

I am currently running nuxt v.3.10.3 and nuxt-multi-cache v3.1.1 and am having problems with the route cache.
I get the following error in the browser console when I try to access a simple cached page (index.vue) with only text on it:

GET http://localhost:3000/de net::ERR_CONTENT_DECODING_FAILED 200 (OK)

index.vue

<script setup lang="ts">
// page caching
useRouteCache((helper) => {
  helper.setMaxAge(10).setCacheable().addTags(['page:1'])
})
</script>

<template>
  Test
</template>

The route is successfully cached and I can view the data in my redis database, but when I try to access the cached page in the browser, I get this error and no content is displayed.

Page cache enabled but not really caching the page.

Thank you for this awesome module!
I'm trying to cache the entire page, inside the page (in fetch hook), I call the API to get product details.
Then when I enable the page cache, I see it's actually caching it by the route as the key. I see it is cached by checking localhost:3000/__nuxt_multi_cache/stats/page. Even can see the logs in nuxtjs server that says the page cached...

But seems it's still calling the API every time when I refresh the page, I'm seeing the request logs in backend. Also lighthouse scores not changed in local, so no performance increase.

So as I understood, it must directly load the html file from cache with populated data, so no call to API, am I correct? If yes, how can I debug this issue? I see no errors in browser console or nuxtjs server.

I call the this.$cache.route.setCacheable() inside fetch() after getting product from API.
This is my config:

  modules: [
    '@nuxtjs/i18n',
    '@nuxtjs/axios',
    '@nuxtjs/auth-next',
    '@nuxtjs/pwa',
    'nuxt-multi-cache',
  ],
  
multiCache: {
    enabled: true,
    outputDir: './cache',
    debug: true,
    server: {
      auth(req) {
        return true
      },
    },
    pageCache: {
      enabled: true
    },
    dataCache: {
      enabled: true,
    },

    componentCache: {
      enabled: true,
      lruOptions: {
        max: 1000,
        maxAge: 24 * 60 * 60 * 1000, // 24 hours
      },
    },
  },

Mismatching documentation

I tried to use nuxt-multi-cache with my project and found the different usage and the documentation.

  1. the object name of module on nuxt.config.js
    Documentation told to use multiCache for object name
    But I have to use routeCache to make it works.

  2. the server auth config
    Documentation told to use serverAuth for server auth config
    But I have to use

server: {
  auth: {
    username: ''
    password: ''
  }
}

nuxtjs version: 2.15.7
nuxt-mult-cache version: 1.0.5

This is the config I use

routeCache: {
  enabled: true,
  debug: true,
  outputDir: '~/cache',
  server: {
    auth: {
      username: 'admin',
      password: 'hunter2'
    }
  },
  pageCache: {
    enabled: true
  },
  dataCache: {
    enabled: true
  }
}

Route caching is not working correctly in Nuxt 3

I am having issues using this module with version 3 of nuxt. I have added the enable and store parameters in the nuxt.config.ts file to use cacheRoute. In each page, inside the <script setup> tag, I have added the function

useRouteCache((route) => {
route
.setMaxAge(3600)
.setCacheable()
.addTags([“tag”])
})

When I navigate on my site, the cache files are not stored, but if I manually reload the page, the files are created. How is this possible?
The routing is dynamic and the structure is as follows:

Schermata 2023-03-24 alle 10 28 01

I also tried to include the useRouteCache function inside the <script> tag within created(), but importing useRouteCache gives me the following issue:
ERROR Internal server error: Missing "./dist/runtime/composables" specifier in "nuxt-multi-cache" package

How to set expiration time for data cache?

Hi,
I want to ask how to set expiration time for data cache, I can't find it in the documentation.
Currently the only way to clear manually is to call the API.

Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.