import { customRef , onServerPrefetch , ref , shallowRef , } from '@vue/composition-api' ; import type { Ref } from '@vue/composition-api' ; import { globalContext , globalNuxt , } from '@nuxtjs/composition-api/dist/runtime/globals' ; import { getCurrentInstance , validateKey } from './utils' ; function getValue < T > ( value ) { if ( value instanceof Function ) return value ( ) ; return value ; } let globalRefs = { } ; export function setSSRContext ( app ) { globalRefs = Object . assign ( { } , { } ) ; app . context . ssrContext . nuxt . globalRefs = globalRefs ; } const useServerData = ( ) => { const vm = getCurrentInstance ( ) ; const type = vm ? 'ssrRefs' : 'globalRefs' ; let ssrRefs ; if ( vm && process . server ) { const ssrContext = ( vm ! [ globalNuxt ] || vm ! . $options ) . context . ssrContext ! ; ssrRefs = ( ssrContext . nuxt as any ) . ssrRefs = ( ssrContext . nuxt as any ) . ssrRefs || { } ; } const setData = ( key , val ) => { const refs = ssrRefs || globalRefs ; refs [ key ] = sanitise ( val ) ; } ; return { type , setData } ; } ; const isProxyable = ( val ) : val is Record < string , unknown > => ! ! val && typeof val === 'object' ; export const sanitise = ( val ) => ( val && JSON . parse ( JSON . stringify ( val ) ) ) || val ; const ssrValue = < T > ( value , key , type = 'globalRefs' ) : T => { if ( process . client ) { if ( process . env . NODE_ENV === 'development' && window [ globalNuxt ] ?. context . isHMR ) { return getValue ( value ) ; } return ( window as any ) [ globalContext ] ?. [ type ] ?. [ key ] ?? getValue ( value ) ; } return getValue ( value ) ; } ; param value param key example export const ssrRef = < T > ( value , key ? ) : Ref < T > => { validateKey ( key ) ; const { type , setData } = useServerData ( ) ; let val = ssrValue ( value , key , type ) ; if ( process . client ) return ref ( val ) as Ref < T > ; if ( value instanceof Function ) setData ( key , val ) ; const getProxy = < T extends Record < string | number , any > > ( track , trigger , observable ) : T => new Proxy ( observable , { get ( target , prop ) { track ( ) ; if ( isProxyable ( target [ prop ] ) ) return getProxy ( track , trigger , target [ prop ] ) ; const value = Reflect . get ( target , prop ) ; return typeof value === 'function' ? value . bind ( target ) : value ; } , set ( obj , prop , newVal ) { const result = Reflect . set ( obj , prop , newVal ) ; setData ( key , val ) ; trigger ( ) ; return result ; } , } ) ; const proxy = customRef ( ( track , trigger ) => ( { get : ( ) => { track ( ) ; if ( isProxyable ( val ) ) return getProxy ( track , trigger , val ) ; return val ; } , set : ( v ) => { setData ( key , v ) ; val = v ; trigger ( ) ; } , } ) ) ; return proxy ; } ; param value param key example export const shallowSsrRef = < T > ( value , key ? ) : Ref < T > => { validateKey ( key ) ; const { type , setData } = useServerData ( ) ; if ( process . client ) return shallowRef ( ssrValue ( value , key , type ) ) ; const _val = getValue ( value ) ; if ( value instanceof Function ) { setData ( key , _val ) ; } return customRef ( ( track , trigger ) => ( { get ( ) { track ( ) ; return _val ; } , set ( newValue ) { setData ( key , newValue ) ; value = newValue ; trigger ( ) ; } , } ) ) ; } ; param value param key example export const ssrPromise = < T > ( value , key ? ) : Promise < T > => { validateKey ( key ) ; const { type , setData } = useServerData ( ) ; const val = ssrValue ( value , key , type ) ; if ( process . client ) return Promise . resolve ( val ) ; onServerPrefetch ( async ( ) => { setData ( key , await val ) ; } ) ; return val ; } ;