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
@vue/server-renderer doesn't have support for component-level caching #1791
Comments
I wonder if it makes sense to support this in a form of a built-in component instead of a component option? <template>
<server-cache :key="cacheKey">
<!-- rendered on cache miss, otherwise cached stringified component is used -->
<heavy-component v-bind="$props" />
</server-cache>
</template>
<script>
export default {
async setup(props) {
const cacheKey = ref(null);
cacheKey.value = await CachingService.get(props.id);
return { cacheKey }
}
}
</script> It also makes caching more versatile because it's not bound to the component. |
Hi, had any progress on this?? or any plan to implement this in the future or not? |
Hi everybody and @yyx990803.
The second solution seems likely to me, but at this time I can't figure out how to get the rendered string in the wrapper's render function without modifying the renderToString function in the server renderer... EDIT : to give a better understanding, here are some measures on the on the landing page of galerieslafaytette.com (a big french department store). these measures were made on the webapp deployed on a GKE kubernetes workload, with it's autoscaler setup for the test to give always only one pod. We fire it it with
As you can see, migrating to Vue 3 has a benefit, but not enough regarding the micro-caching available on the Vue 2 server-renderer... |
@CyberAP Your idea is very good, and I think I'll try to implement it this way, and maybe I will not have to modify the server-renderer package, if I'm able to call the renderToString of the server renderer function from the render function of this cache wrapper on the default slot content... |
I am using The implementation could look like this: const app = createApp({
ssrCache: {
get(key) {
if (!canStream) return resolveItem(key) // resolves to string
else return getItemStream(key) // resolves to ReadableStream
},
set(key, value) { cacheItem(key, value) },
},
}); |
Any progress on this request? I guess there are tons of applications use this feature at Vue 2 but it's missing in Vue 3 strangely. I don't know if it's not implemented on purpose. @yyx990803 |
Any progress on any of the mentioned solutions? we are facing the same problem. The second solution is indeed a great idea! |
Like others I was also looking for a solution for component caching with Vue 3 server-renderer. I maintain nuxt-multi-cache that among other things offers a seamless integration for component caching in Nuxt 2. Currently rewriting the module for Nuxt 3 and had to find a solution for component caching. Looked into various options but then tried out the idea suggested in one of the comments here: Using a wrapper component that caches the contents of the default slot. After some fiddling around I managed to make it work as part of the rewrite for my module. Essentially you can use the Currently you'll need to copy paste some code from server-renderer that handles buffers. But I have created a feature request at #7414 that would export two methods so the copy pasting isn't needed anymore. In the issue you'll also find an example that shows the basic idea of this approach. |
Any update on this ? Does component-level-caching support (with I can't find any information in documentation about this for Vue3/Nuxt3 as of today but this issue. It would be nice to get feedback from the core team about this topic. |
Anyone has a solution for this ? |
Would also like to see a solution for this |
Not sure if this is relevant, but based on suggestion from @CyberAP I have the following working example: <script>
import { renderToString } from '@vue/server-renderer';
import { h, createStaticVNode, getCurrentInstance, createApp } from 'vue';
// Implement your own cache service, pass to the component using provide/inject etc.
const dummyCache = {};
export default {
name: 'ServerCache',
props: {
cacheKey: {
type: String,
required: true,
},
cacheName: {
type: [ String, Symbol ],
required: true,
},
},
computed: {
cacheEntryKey() {
return `${this.cacheName}-${this.cacheKey}`;
}
},
async beforeCreate() {
const isClient = typeof window !== 'undefined';
if (!this.$slots.default || isClient || typeof dummyCache[this.cacheEntryKey] !== 'undefined') {
return;
}
const vNode = h(this.$slots.default);
/*
* wrap vNode into a temporary app and assign original context
* so that children have access to provides, plugins, etc.
*/
const tempApp = createApp({ render: () => vNode })
tempApp._context = getCurrentInstance().appContext;
const renderedString = await renderToString(tempApp);
dummyCache[this.cacheEntryKey] = renderedString;
},
render() {
const cachedEntry = dummyCache[this.cacheEntryKey];
if (typeof cachedEntry !== 'undefined') {
return createStaticVNode(cachedEntry)
}
if (this.$slots.default) {
return h(this.$slots.default);
}
return null;
},
};
</script> Then use as
So far the prototype worked for me. Yes, it is using vue internals, but only within itself. And it is not messing with main app instance and hooks. If anything changes you just have to update the implementation of this one component. Or if it broke completely due to change in vue internal APIs, simply remove cache wrapper, yes your app will become slow again, but it won't break. |
@dmytro-grablov nice implementation. I think you don't even need to create a new app instance for this. We can re-use the internal method. export default {
created() {
let res = '';
const push = (val) => { res += val };
this.$.type.ssrRender(this.$.proxy, push, this.$.parent, this.$.attrs);
console.log(res); // rendered markup
}
} Of course this would need some additional handling in case you have an async child. |
hm, I don't have |
What problem does this feature solve?
ServerCacheKey is useful feature for large projects with SSR. Will it be added to @vue/server-renderer?
What does the proposed API look like?
https://ssr.vuejs.org/guide/caching.html#component-level-caching
The text was updated successfully, but these errors were encountered: