import { defineComponent, getCurrentInstance, onErrorCaptured, shallowRef, useId } from "vue"; import { ssrRenderAttrs, ssrRenderSlot, ssrRenderVNode } from "vue/server-renderer"; import { isPromise } from "@vue/shared"; import { useState } from "../composables/state.js"; import { createBuffer } from "./utils.js"; const NuxtClientFallbackServer = defineComponent({ name: "NuxtClientFallback", inheritAttrs: false, props: { fallbackTag: { type: String, default: () => "div" }, fallback: { type: String, default: () => "" }, placeholder: { type: String }, placeholderTag: { type: String }, keepFallback: { type: Boolean, default: () => false } }, emits: { "ssr-error"(_error) { return true; } }, async setup(_, ctx) { const vm = getCurrentInstance(); const ssrFailed = shallowRef(false); const error = useState(useId()); onErrorCaptured((err) => { error.value = true; ssrFailed.value = true; ctx.emit("ssr-error", err); return false; }); try { const defaultSlot = ctx.slots.default?.(); const ssrVNodes = createBuffer(); if (defaultSlot) { for (let i = 0; i < defaultSlot.length; i++) { ssrRenderVNode(ssrVNodes.push, defaultSlot[i], vm); } } const buffer = ssrVNodes.getBuffer(); if (buffer.hasAsync) { await Promise.all(buffer.filter(isPromise)); } return { ssrFailed, ssrVNodes }; } catch (ssrError) { error.value = true; ctx.emit("ssr-error", ssrError); return { ssrFailed: true, ssrVNodes: [] }; } }, ssrRender(ctx, push, parent) { if (ctx.ssrFailed) { const { fallback, placeholder } = ctx.$slots; if (fallback || placeholder) { ssrRenderSlot(ctx.$slots, fallback ? "fallback" : "placeholder", {}, null, push, parent); } else { const content = ctx.placeholder || ctx.fallback; const tag = ctx.placeholderTag || ctx.fallbackTag; push(`<${tag}${ssrRenderAttrs(ctx.$attrs)}>${content}`); } } else { push(""); push(ctx.ssrVNodes.getBuffer()); push(""); } } }); export default NuxtClientFallbackServer;