Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

feat(nuxt): add onNuxtReady composable #9478

Merged
merged 4 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/content/1.docs/3.api/3.utils/on-nuxt-ready.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: "onNuxtReady"
description: The onNuxtReady composable allows running a callback after your app has finished initializing.
---

# `onNuxtReady`

The `onNuxtReady` composable allows running a callback after your app has finished initializing. It is ideal for running code that should not block the initial rendering of your app.

```ts
export default defineNuxtPlugin(() => {
onNuxtReady(async () => {
const myAnalyticsLibrary = await import('my-big-analytics-library')
// do something with myAnalyticsLibrary
})
})
```

It is 'safe' to run even after your app has initialized. In this case, then the code will be registered to run in the next idle callback.
16 changes: 16 additions & 0 deletions packages/nuxt/src/app/compat/idle-callback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Polyfills for Safari support
// https://caniuse.com/requestidlecallback
export const requestIdleCallback: Window['requestIdleCallback'] = process.server
? undefined as any
: (globalThis.requestIdleCallback || ((cb) => {
const start = Date.now()
const idleDeadline = {
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
}
return setTimeout(() => { cb(idleDeadline) }, 1)
}))

export const cancelIdleCallback: Window['cancelIdleCallback'] = process.server
? null as any
: (globalThis.cancelIdleCallback || ((id) => { clearTimeout(id) }))
28 changes: 4 additions & 24 deletions packages/nuxt/src/app/components/nuxt-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import type { RouteLocationRaw } from 'vue-router'
import { hasProtocol } from 'ufo'

import { preloadRouteComponents } from '../composables/preload'
import { onNuxtReady } from '../composables/ready'
import { navigateTo, useRouter } from '../composables/router'
import { useNuxtApp } from '../nuxt'
import { cancelIdleCallback, requestIdleCallback } from '../compat/idle-callback'

const firstNonUndefined = <T> (...args: (T | undefined)[]) => args.find(arg => arg !== undefined)

Expand Down Expand Up @@ -42,23 +44,6 @@ export type NuxtLinkProps = {
ariaCurrentValue?: string
}

// Polyfills for Safari support
// https://caniuse.com/requestidlecallback
const requestIdleCallback: Window['requestIdleCallback'] = process.server
? undefined as any
: (globalThis.requestIdleCallback || ((cb) => {
const start = Date.now()
const idleDeadline = {
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
}
return setTimeout(() => { cb(idleDeadline) }, 1)
}))

const cancelIdleCallback: Window['cancelIdleCallback'] = process.server
? null as any
: (globalThis.cancelIdleCallback || ((id) => { clearTimeout(id) }))

export function defineNuxtLink (options: NuxtLinkOptions) {
const componentName = options.componentName || 'NuxtLink'

Expand Down Expand Up @@ -197,7 +182,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
let unobserve: Function | null = null
onMounted(() => {
const observer = useObserver()
function registerCallback () {
onNuxtReady(() => {
idleId = requestIdleCallback(() => {
if (el?.value?.tagName) {
unobserve = observer!.observe(el.value, async () => {
Expand All @@ -211,12 +196,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
})
}
})
}
if (nuxtApp.isHydrating) {
nuxtApp.hooks.hookOnce('app:suspense:resolve', registerCallback)
} else {
registerCallback()
}
})
})
onBeforeUnmount(() => {
if (idleId) { cancelIdleCallback(idleId) }
Expand Down
1 change: 1 addition & 0 deletions packages/nuxt/src/app/composables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type { FetchResult, UseFetchOptions } from './fetch'
export { useCookie } from './cookie'
export type { CookieOptions, CookieRef } from './cookie'
export { useRequestHeaders, useRequestEvent, setResponseStatus } from './ssr'
export { onNuxtReady } from './ready'
export { abortNavigation, addRouteMiddleware, defineNuxtRouteMiddleware, onBeforeRouteLeave, onBeforeRouteUpdate, setPageLayout, navigateTo, useRoute, useRouter } from './router'
export type { AddRouteMiddlewareOptions, RouteMiddleware } from './router'
export { preloadComponents, prefetchComponents, preloadRouteComponents } from './preload'
Expand Down
11 changes: 11 additions & 0 deletions packages/nuxt/src/app/composables/ready.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useNuxtApp } from '../nuxt'
import { requestIdleCallback } from '../compat/idle-callback'

export const onNuxtReady = (callback: () => any) => {
const nuxtApp = useNuxtApp()
if (nuxtApp.isHydrating) {
nuxtApp.hooks.hookOnce('app:suspense:resolve', () => { requestIdleCallback(callback) })
} else {
requestIdleCallback(callback)
}
}
1 change: 1 addition & 0 deletions packages/nuxt/src/imports/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const appPreset = defineUnimportPreset({
'useRequestEvent',
'setResponseStatus',
'setPageLayout',
'onNuxtReady',
'useRouter',
'useRoute',
'defineNuxtRouteMiddleware',
Expand Down