Allow disabling or clearing of compile cache in SSR render
What problem does this feature solve?
We are using a NodeJS process for SSR rendering of vue snippets in an ASP.NET Core application. Over time we noticed that the memory of the NodeJS process increases, forcing us to terminate the process periodically. After some investigation we found that all templates and the resulting compiled functions are cached in a "compileCache" object that is used in the ssrCompile function.
While we try as much as possible to send templates to the process that are not changing dynamically, there are still reasons why over time templates change. For example when changes in the CMS occur or if the template contains data with some variation.
We are also employing our own render cache to avoid calling the NodeJS process for known templates.
This means that for our and similar use cases, the compile cache does not provide any benefit, will cache already cached data, and will over time cause out of memory problems.
I'm therefore proposing one of two options:
- Provide an option to disable the compile cache
- Provide and export a function to clear the compile cache
What does the proposed API look like?
Option 1:
compilerOptions: {
disableCompileCache: true
}
Option 2:
import { clearCompileCache } from '@vue/server-renderer'
I'm willing to contribute a PR implementing one of the two options, if accepted.
While this is probably not affecting many people, it is a potential issue for everyone using Vue to to render individual components from other backends and there is currently no good solution to avoid memory issues in this case.
So we've been struggling with a memory leak for quite some time now, and we are getting quite confident that the issue comes from this in particular.
I'm a bit surprised by the tag that is "feature request". Cache should always be bound and have some expiration mechanism, right? De facto if you have to compile endless amounts of templates and your cannot avoid a memory leak, this should be handled as a bug.
As Kenneth Boulding said:
Anyone who believes RAM growth can go on forever in a finite world is either a madman or a Vue developer.
Let me know if you'd like to receive a contribution on this particular issue, I'll gladly do it with proper guidance.
I don’t think this is a complex feature, and perhaps there’s no need to go through an RFC for discussion.
I prefer Option 2 and made a PR, see #12868.
Another idea: allowing the user to specify a custom cache implementation e.g.
// type definition
interface CustomCompileCache {
get: (key: string) => RenderFunction | undefined
set: (key: string, render: RenderFunction) => void
}
compilerOptions: {
customCompileCache?: CustomCompileCache
}
// example implementations
const neverCache: CustomCompileCache = {
get: () => undefined,
set: () => {}
}
const cache = new Map()
const lruCache: CustomCompileCache = {
get: (key) => {
const render = cache.get(key)
if (render) {
markAsUsed(key)
}
return render
},
set: (key, render) => {
if (cache.size >= 10) {
clearLeastUsed(key)
}
cache[key] = render
},
}
compilerOptions: {
customCompileCache: lruCache
}
RenderFunction could just be treated as an opaque type for the user's implementation.