-
Notifications
You must be signed in to change notification settings - Fork 15
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
Support latest Nuxt in SSR utils #34
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,42 @@ | ||
import { | ||
onServerPrefetch, | ||
getCurrentInstance, | ||
onBeforeMount, | ||
computed, | ||
} from "./api"; | ||
import { TaskInstance } from "../TaskInstance"; | ||
import { Task } from "../Task"; | ||
} from "@nuxtjs/composition-api"; | ||
|
||
async function wrap (func, catcher, finaliser) { | ||
try { | ||
return await func(); | ||
} catch (e) { | ||
if (catcher) await catcher(e); | ||
} finally { | ||
if (finaliser) await finaliser(); | ||
} | ||
} | ||
|
||
function getNuxtTask (key) { | ||
const ssrContext = process.client && window['__NUXT__']; | ||
|
||
if (!ssrContext) | ||
throw Error(`Could not access window.__NUXT__ or not operating client-side`); | ||
|
||
if (!ssrContext.vueConcurrency || !ssrContext.vueConcurrency[key]) | ||
return undefined; | ||
|
||
return ssrContext.vueConcurrency[key].value; | ||
} | ||
|
||
function setNuxtTask (vm, key, task) { | ||
const { nuxt: ssrContext } = vm.$ssrContext; | ||
|
||
const isServer = () => typeof window === "undefined"; | ||
if (!ssrContext.vueConcurrency) | ||
ssrContext.vueConcurrency = {}; | ||
|
||
export function reviveTaskInstance(instance: TaskInstance<any>) { | ||
ssrContext.vueConcurrency[key] = computed(() => task._instances); | ||
} | ||
|
||
export function reviveTaskInstance (instance) { | ||
if (instance.isError) { | ||
instance._deferredObject.promise = Promise.reject(instance.error); | ||
} else { | ||
|
@@ -26,84 +54,33 @@ export function reviveTaskInstance(instance: TaskInstance<any>) { | |
instance._deferredObject.promise.finally(...params); | ||
} | ||
|
||
export function useTaskPrefetch<T>( | ||
key: string, | ||
task: Task<T, any> | ||
): TaskInstance<T> { | ||
/* Server */ | ||
if (isServer()) { | ||
// perform, add to prefetch, add to ssrContext | ||
const taskInstance = task.perform(); | ||
onServerPrefetch(async () => { | ||
try { | ||
await taskInstance; | ||
saveTaskToNuxtState(key, task); | ||
} catch (e) { | ||
// no need for extra handling | ||
} | ||
}); | ||
return taskInstance; | ||
} | ||
|
||
/* Client */ | ||
const [last] = reviveTaskInstances(key, task).reverse(); | ||
function reviveTaskInstances (key, task) { | ||
const taskCache = getNuxtTask(key); | ||
|
||
if (last) { | ||
return last; | ||
} else { | ||
return task.perform(); | ||
} | ||
} | ||
|
||
function saveTaskToNuxtState(key: string, task: Task<any, any>) { | ||
const { $root } = getCurrentInstance() as any; | ||
const nuxtState = $root && $root.context && $root.context.nuxtState; | ||
if (!nuxtState) { | ||
throw new Error("Could not access $root.context.nuxtState"); | ||
} | ||
|
||
if (!nuxtState.vueConcurrency) { | ||
nuxtState.vueConcurrency = {}; | ||
} | ||
|
||
nuxtState.vueConcurrency[key] = computed(() => ({ | ||
instances: task._instances, | ||
})); | ||
} | ||
|
||
function reviveTaskInstances(key: string, task: Task<any, any>) { | ||
const taskCache = getTaskFromContext(key); | ||
if (taskCache) { | ||
task._instances = taskCache.instances || []; | ||
task._instances = taskCache || []; | ||
task._instances.forEach(reviveTaskInstance); | ||
deleteTaskCache(key); | ||
} | ||
|
||
return task._instances; | ||
} | ||
|
||
function getNuxtData() { | ||
return (window as any).__NUXT__; | ||
} | ||
export function useTaskPrefetch (key, task) { | ||
const vm = getCurrentInstance(); | ||
|
||
function getTaskFromContext(key) { | ||
if (!getNuxtData()) { | ||
throw Error(`Could not access window.__NUXT__`); | ||
} | ||
onServerPrefetch(async () => { | ||
await wrap(task.perform); | ||
setNuxtTask(vm, key, task); | ||
}); | ||
|
||
return getNuxtData().vueConcurrency[key].value; | ||
} | ||
if (process.client) { | ||
onBeforeMount(async () => !task._instances.length && task.perform()); | ||
reviveTaskInstances(key, task); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the revive happens after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case it's irrelevant because of |
||
} | ||
|
||
function deleteTaskCache(key) { | ||
const nuxtData = getNuxtData(); | ||
delete nuxtData.vueConcurrency[key]; | ||
return task; | ||
} | ||
|
||
export function useSSRPersistance(key: string, task: Task<any, any>) { | ||
if (isServer()) { | ||
saveTaskToNuxtState(key, task); | ||
return; | ||
} | ||
|
||
reviveTaskInstances(key, task); | ||
export function useSSRPersistance (key, task) { | ||
const vm = getCurrentInstance(); | ||
if (process.server) setNuxtTask(vm, key, task); | ||
else reviveTaskInstances(key, task); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is
onBeforeMount
needed here? shouldn'tif (process.client)
be enough?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is personal preference and is analogous to how
@nuxtjs/composition-api
handles these sorts of cases internally. The alternative you propose should work, I imagine (but this hasn't been battle-tested like my implementation).