mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
feat(nuxt): move loading api behind hooks (#24010)
This commit is contained in:
parent
3be4a5d406
commit
9cd6c922e5
@ -38,3 +38,7 @@ You can pass custom HTML or components through the loading indicator's default s
|
|||||||
This component is optional. :br
|
This component is optional. :br
|
||||||
To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-loading-indicator.ts).
|
To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-loading-indicator.ts).
|
||||||
::
|
::
|
||||||
|
|
||||||
|
::callout
|
||||||
|
You can hook into the underlying indicator instance using [the `useLoadingIndicator` composable](/docs/api/composables/use-loading-indicator), which will allow you to trigger start/finish events yourself.
|
||||||
|
::
|
||||||
|
40
docs/3.api/2.composables/use-loading-indicator.md
Normal file
40
docs/3.api/2.composables/use-loading-indicator.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
title: 'useLoadingIndicator'
|
||||||
|
description: This composable gives you access to the loading state of the app page.
|
||||||
|
links:
|
||||||
|
- label: Source
|
||||||
|
icon: i-simple-icons-github
|
||||||
|
to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/loading-indicator.ts
|
||||||
|
size: xs
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
A composable which returns the loading state of the page. Used by [`<NuxtLoadingIndicator>`](/docs/api/components/nuxt-loading-indicator) and controllable.
|
||||||
|
It hooks into [`page:loading:start`](/docs/api/advanced/hooks#app-hooks-runtime) and [`page:loading:end`](/docs/api/advanced/hooks#app-hooks-runtime) to change its state.
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### `isLoading`
|
||||||
|
|
||||||
|
- **type**: `Ref<boolean>`
|
||||||
|
- **description**: The loading state
|
||||||
|
|
||||||
|
### `progress`
|
||||||
|
|
||||||
|
- **type**: `Ref<number>`
|
||||||
|
- **description**: The progress state. From `0` to `100`.
|
||||||
|
|
||||||
|
## Methods
|
||||||
|
|
||||||
|
### `start()`
|
||||||
|
|
||||||
|
Set `isLoading` to true and start to increase the `progress` value.
|
||||||
|
|
||||||
|
### `finish()`
|
||||||
|
|
||||||
|
Set the `progress` value to `100`, stop all timers and intervals then reset the loading state `500` ms later.
|
||||||
|
|
||||||
|
### `clear()`
|
||||||
|
|
||||||
|
Used by `finish()`. Clear all timers and intervals used by the composable.
|
@ -25,6 +25,8 @@ Hook | Arguments | Environment | Description
|
|||||||
`link:prefetch` | `to` | Client | Called when a `<NuxtLink>` is observed to be prefetched.
|
`link:prefetch` | `to` | Client | Called when a `<NuxtLink>` is observed to be prefetched.
|
||||||
`page:start` | `pageComponent?` | Client | Called on [Suspense](https://vuejs.org/guide/built-ins/suspense.html#suspense) pending event.
|
`page:start` | `pageComponent?` | Client | Called on [Suspense](https://vuejs.org/guide/built-ins/suspense.html#suspense) pending event.
|
||||||
`page:finish` | `pageComponent?` | Client | Called on [Suspense](https://vuejs.org/guide/built-ins/suspense.html#suspense) resolved event.
|
`page:finish` | `pageComponent?` | Client | Called on [Suspense](https://vuejs.org/guide/built-ins/suspense.html#suspense) resolved event.
|
||||||
|
`page:loading:start` | - | Client | Called when the `setup()` of the new page is running.
|
||||||
|
`page:loading:end` | - | Client | Called after `page:finish`
|
||||||
`page:transition:finish`| `pageComponent?` | Client | After page transition [onAfterLeave](https://vuejs.org/guide/built-ins/transition.html#javascript-hooks) event.
|
`page:transition:finish`| `pageComponent?` | Client | After page transition [onAfterLeave](https://vuejs.org/guide/built-ins/transition.html#javascript-hooks) event.
|
||||||
|
|
||||||
## Nuxt Hooks (build time)
|
## Nuxt Hooks (build time)
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
import { computed, defineComponent, h, onBeforeUnmount, ref } from 'vue'
|
import { defineComponent, h } from 'vue'
|
||||||
import { useNuxtApp } from '../nuxt'
|
import { useLoadingIndicator } from '#app/composables/loading-indicator'
|
||||||
import { useRouter } from '../composables/router'
|
|
||||||
import { isChangingPage } from './utils'
|
|
||||||
|
|
||||||
// @ts-expect-error virtual file
|
|
||||||
import { globalMiddleware } from '#build/middleware'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'NuxtLoadingIndicator',
|
name: 'NuxtLoadingIndicator',
|
||||||
@ -26,48 +21,15 @@ export default defineComponent({
|
|||||||
default: 'repeating-linear-gradient(to right,#00dc82 0%,#34cdfe 50%,#0047e1 100%)'
|
default: 'repeating-linear-gradient(to right,#00dc82 0%,#34cdfe 50%,#0047e1 100%)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup (props, { slots }) {
|
setup (props, { slots, expose }) {
|
||||||
// TODO: use computed values in useLoadingIndicator
|
|
||||||
const { progress, isLoading, start, finish, clear } = useLoadingIndicator({
|
const { progress, isLoading, start, finish, clear } = useLoadingIndicator({
|
||||||
duration: props.duration,
|
duration: props.duration,
|
||||||
throttle: props.throttle
|
throttle: props.throttle
|
||||||
})
|
})
|
||||||
|
|
||||||
if (import.meta.client) {
|
expose({
|
||||||
// Hook to app lifecycle
|
progress, isLoading, start, finish, clear
|
||||||
// TODO: Use unified loading API
|
})
|
||||||
const nuxtApp = useNuxtApp()
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
globalMiddleware.unshift(start)
|
|
||||||
router.onError(() => {
|
|
||||||
finish()
|
|
||||||
})
|
|
||||||
router.beforeResolve((to, from) => {
|
|
||||||
if (!isChangingPage(to, from)) {
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
router.afterEach((_to, _from, failure) => {
|
|
||||||
if (failure) {
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const unsubPage = nuxtApp.hook('page:finish', finish)
|
|
||||||
const unsubError = nuxtApp.hook('vue:error', finish)
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
const index = globalMiddleware.indexOf(start)
|
|
||||||
if (index >= 0) {
|
|
||||||
globalMiddleware.splice(index, 1)
|
|
||||||
}
|
|
||||||
unsubPage()
|
|
||||||
unsubError()
|
|
||||||
clear()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => h('div', {
|
return () => h('div', {
|
||||||
class: 'nuxt-loading-indicator',
|
class: 'nuxt-loading-indicator',
|
||||||
@ -90,68 +52,3 @@ export default defineComponent({
|
|||||||
}, slots)
|
}, slots)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function useLoadingIndicator (opts: {
|
|
||||||
duration: number,
|
|
||||||
throttle: number
|
|
||||||
}) {
|
|
||||||
const progress = ref(0)
|
|
||||||
const isLoading = ref(false)
|
|
||||||
const step = computed(() => 10000 / opts.duration)
|
|
||||||
|
|
||||||
let _timer: any = null
|
|
||||||
let _throttle: any = null
|
|
||||||
|
|
||||||
function start () {
|
|
||||||
clear()
|
|
||||||
progress.value = 0
|
|
||||||
if (opts.throttle && import.meta.client) {
|
|
||||||
_throttle = setTimeout(() => {
|
|
||||||
isLoading.value = true
|
|
||||||
_startTimer()
|
|
||||||
}, opts.throttle)
|
|
||||||
} else {
|
|
||||||
isLoading.value = true
|
|
||||||
_startTimer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function finish () {
|
|
||||||
progress.value = 100
|
|
||||||
_hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
function clear () {
|
|
||||||
clearInterval(_timer)
|
|
||||||
clearTimeout(_throttle)
|
|
||||||
_timer = null
|
|
||||||
_throttle = null
|
|
||||||
}
|
|
||||||
|
|
||||||
function _increase (num: number) {
|
|
||||||
progress.value = Math.min(100, progress.value + num)
|
|
||||||
}
|
|
||||||
|
|
||||||
function _hide () {
|
|
||||||
clear()
|
|
||||||
if (import.meta.client) {
|
|
||||||
setTimeout(() => {
|
|
||||||
isLoading.value = false
|
|
||||||
setTimeout(() => { progress.value = 0 }, 400)
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function _startTimer () {
|
|
||||||
if (import.meta.client) {
|
|
||||||
_timer = setInterval(() => { _increase(step.value) }, 100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
progress,
|
|
||||||
isLoading,
|
|
||||||
start,
|
|
||||||
finish,
|
|
||||||
clear
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
134
packages/nuxt/src/app/composables/loading-indicator.ts
Normal file
134
packages/nuxt/src/app/composables/loading-indicator.ts
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import { computed, getCurrentScope, onScopeDispose, ref } from 'vue'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
|
import { useNuxtApp } from '#app/nuxt'
|
||||||
|
|
||||||
|
export type LoadingIndicatorOpts = {
|
||||||
|
/** @default 2000 */
|
||||||
|
duration: number
|
||||||
|
/** @default 200 */
|
||||||
|
throttle: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function _increase (progress: Ref<number>, num: number) {
|
||||||
|
progress.value = Math.min(100, progress.value + num)
|
||||||
|
}
|
||||||
|
|
||||||
|
function _hide (isLoading: Ref<boolean>, progress: Ref<number>) {
|
||||||
|
if (import.meta.client) {
|
||||||
|
setTimeout(() => {
|
||||||
|
isLoading.value = false
|
||||||
|
setTimeout(() => { progress.value = 0 }, 400)
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LoadingIndicator = {
|
||||||
|
_cleanup: () => void
|
||||||
|
progress: Ref<number>
|
||||||
|
isLoading: Ref<boolean>
|
||||||
|
start: () => void
|
||||||
|
set: (value: number) => void
|
||||||
|
finish: () => void
|
||||||
|
clear: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function createLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}) {
|
||||||
|
const { duration = 2000, throttle = 200 } = opts
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
const progress = ref(0)
|
||||||
|
const isLoading = ref(false)
|
||||||
|
const step = computed(() => 10000 / duration)
|
||||||
|
|
||||||
|
let _timer: any = null
|
||||||
|
let _throttle: any = null
|
||||||
|
|
||||||
|
const start = () => set(0)
|
||||||
|
|
||||||
|
function set (at = 0) {
|
||||||
|
if (nuxtApp.isHydrating) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (at >= 100) { return finish() }
|
||||||
|
clear()
|
||||||
|
progress.value = at < 0 ? 0 : at
|
||||||
|
if (throttle && import.meta.client) {
|
||||||
|
_throttle = setTimeout(() => {
|
||||||
|
isLoading.value = true
|
||||||
|
_startTimer()
|
||||||
|
}, throttle)
|
||||||
|
} else {
|
||||||
|
isLoading.value = true
|
||||||
|
_startTimer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function finish () {
|
||||||
|
progress.value = 100
|
||||||
|
clear()
|
||||||
|
_hide(isLoading, progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear () {
|
||||||
|
clearInterval(_timer)
|
||||||
|
clearTimeout(_throttle)
|
||||||
|
_timer = null
|
||||||
|
_throttle = null
|
||||||
|
}
|
||||||
|
|
||||||
|
function _startTimer () {
|
||||||
|
if (import.meta.client) {
|
||||||
|
_timer = setInterval(() => { _increase(progress, step.value) }, 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _cleanup = () => {}
|
||||||
|
if (import.meta.client) {
|
||||||
|
const unsubLoadingStartHook = nuxtApp.hook('page:loading:start', () => {
|
||||||
|
start()
|
||||||
|
})
|
||||||
|
const unsubLoadingFinishHook = nuxtApp.hook('page:loading:end', () => {
|
||||||
|
finish()
|
||||||
|
})
|
||||||
|
const unsubError = nuxtApp.hook('vue:error', finish)
|
||||||
|
|
||||||
|
_cleanup = () => {
|
||||||
|
unsubError()
|
||||||
|
unsubLoadingStartHook()
|
||||||
|
unsubLoadingFinishHook()
|
||||||
|
clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
_cleanup,
|
||||||
|
progress: computed(() => progress.value),
|
||||||
|
isLoading: computed(() => isLoading.value),
|
||||||
|
start,
|
||||||
|
set,
|
||||||
|
finish,
|
||||||
|
clear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* composable to handle the loading state of the page
|
||||||
|
*/
|
||||||
|
export function useLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}): Omit<LoadingIndicator, '_cleanup'> {
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
|
||||||
|
// Initialise global loading indicator if it doesn't exist already
|
||||||
|
const indicator = nuxtApp._loadingIndicator = nuxtApp._loadingIndicator || createLoadingIndicator(opts)
|
||||||
|
if (import.meta.client && getCurrentScope()) {
|
||||||
|
nuxtApp._loadingIndicatorDeps = nuxtApp._loadingIndicatorDeps || 0
|
||||||
|
nuxtApp._loadingIndicatorDeps++
|
||||||
|
onScopeDispose(() => {
|
||||||
|
nuxtApp._loadingIndicatorDeps!--
|
||||||
|
if (nuxtApp._loadingIndicatorDeps === 0) {
|
||||||
|
indicator._cleanup()
|
||||||
|
delete nuxtApp._loadingIndicator
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return indicator
|
||||||
|
}
|
@ -17,6 +17,7 @@ import type { RouteMiddleware } from '../app/composables/router'
|
|||||||
import type { NuxtError } from '../app/composables/error'
|
import type { NuxtError } from '../app/composables/error'
|
||||||
import type { AsyncDataRequestStatus } from '../app/composables/asyncData'
|
import type { AsyncDataRequestStatus } from '../app/composables/asyncData'
|
||||||
import type { NuxtAppManifestMeta } from '../app/composables/manifest'
|
import type { NuxtAppManifestMeta } from '../app/composables/manifest'
|
||||||
|
import type { LoadingIndicator } from '#app/composables/loading-indicator'
|
||||||
|
|
||||||
import type { NuxtAppLiterals } from '#app'
|
import type { NuxtAppLiterals } from '#app'
|
||||||
|
|
||||||
@ -44,6 +45,8 @@ export interface RuntimeNuxtHooks {
|
|||||||
'page:finish': (Component?: VNode) => HookResult
|
'page:finish': (Component?: VNode) => HookResult
|
||||||
'page:transition:start': () => HookResult
|
'page:transition:start': () => HookResult
|
||||||
'page:transition:finish': (Component?: VNode) => HookResult
|
'page:transition:finish': (Component?: VNode) => HookResult
|
||||||
|
'page:loading:start': () => HookResult
|
||||||
|
'page:loading:end': () => HookResult
|
||||||
'vue:setup': () => void
|
'vue:setup': () => void
|
||||||
'vue:error': (...args: Parameters<Parameters<typeof onErrorCaptured>[0]>) => HookResult
|
'vue:error': (...args: Parameters<Parameters<typeof onErrorCaptured>[0]>) => HookResult
|
||||||
}
|
}
|
||||||
@ -112,6 +115,11 @@ interface _NuxtApp {
|
|||||||
status: Ref<AsyncDataRequestStatus>
|
status: Ref<AsyncDataRequestStatus>
|
||||||
} | undefined>
|
} | undefined>
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_loadingIndicator?: LoadingIndicator
|
||||||
|
/** @internal */
|
||||||
|
_loadingIndicatorDeps?: number
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_middleware: {
|
_middleware: {
|
||||||
global: RouteMiddleware[]
|
global: RouteMiddleware[]
|
||||||
|
@ -77,6 +77,10 @@ const granularAppPresets: InlinePreset[] = [
|
|||||||
imports: ['isPrerendered', 'loadPayload', 'preloadPayload', 'definePayloadReducer', 'definePayloadReviver'],
|
imports: ['isPrerendered', 'loadPayload', 'preloadPayload', 'definePayloadReducer', 'definePayloadReviver'],
|
||||||
from: '#app/composables/payload'
|
from: '#app/composables/payload'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
imports: ['useLoadingIndicator'],
|
||||||
|
from: '#app/composables/loading-indicator'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
imports: ['getAppManifest', 'getRouteRules'],
|
imports: ['getAppManifest', 'getRouteRules'],
|
||||||
from: '#app/composables/manifest'
|
from: '#app/composables/manifest'
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Suspense, Transition, defineComponent, h, inject, nextTick, ref } from 'vue'
|
import { Suspense, Transition, defineComponent, h, inject, nextTick, ref, watch } from 'vue'
|
||||||
import type { KeepAliveProps, TransitionProps, VNode } from 'vue'
|
import type { KeepAliveProps, TransitionProps, VNode } from 'vue'
|
||||||
import { RouterView } from '#vue-router'
|
import { RouterView } from '#vue-router'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
@ -48,6 +48,14 @@ export default defineComponent({
|
|||||||
|
|
||||||
const done = nuxtApp.deferHydration()
|
const done = nuxtApp.deferHydration()
|
||||||
|
|
||||||
|
if (props.pageKey) {
|
||||||
|
watch(() => props.pageKey, (next, prev) => {
|
||||||
|
if (next !== prev) {
|
||||||
|
nuxtApp.callHook('page:loading:start')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
return h(RouterView, { name: props.name, route: props.route, ...attrs }, {
|
return h(RouterView, { name: props.name, route: props.route, ...attrs }, {
|
||||||
default: (routeProps: RouterViewSlotProps) => {
|
default: (routeProps: RouterViewSlotProps) => {
|
||||||
@ -93,7 +101,7 @@ export default defineComponent({
|
|||||||
wrapInKeepAlive(keepaliveConfig, h(Suspense, {
|
wrapInKeepAlive(keepaliveConfig, h(Suspense, {
|
||||||
suspensible: true,
|
suspensible: true,
|
||||||
onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
|
onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
|
||||||
onResolve: () => { nextTick(() => nuxtApp.callHook('page:finish', routeProps.Component).finally(done)) }
|
onResolve: () => { nextTick(() => nuxtApp.callHook('page:finish', routeProps.Component).then(() => nuxtApp.callHook('page:loading:end')).finally(done)) }
|
||||||
}, {
|
}, {
|
||||||
default: () => {
|
default: () => {
|
||||||
const providerVNode = h(RouteProvider, {
|
const providerVNode = h(RouteProvider, {
|
||||||
|
@ -142,6 +142,7 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
|
|||||||
|
|
||||||
const initialLayout = nuxtApp.payload.state._layout
|
const initialLayout = nuxtApp.payload.state._layout
|
||||||
router.beforeEach(async (to, from) => {
|
router.beforeEach(async (to, from) => {
|
||||||
|
await nuxtApp.callHook('page:loading:start')
|
||||||
to.meta = reactive(to.meta)
|
to.meta = reactive(to.meta)
|
||||||
if (nuxtApp.isHydrating && initialLayout && !isReadonly(to.meta.layout)) {
|
if (nuxtApp.isHydrating && initialLayout && !isReadonly(to.meta.layout)) {
|
||||||
to.meta.layout = initialLayout as Exclude<PageMeta['layout'], Ref | false>
|
to.meta.layout = initialLayout as Exclude<PageMeta['layout'], Ref | false>
|
||||||
@ -193,7 +194,10 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.onError(() => { delete nuxtApp._processingMiddleware })
|
router.onError(async () => {
|
||||||
|
delete nuxtApp._processingMiddleware
|
||||||
|
await nuxtApp.callHook('page:loading:end')
|
||||||
|
})
|
||||||
|
|
||||||
router.afterEach(async (to, _from, failure) => {
|
router.afterEach(async (to, _from, failure) => {
|
||||||
delete nuxtApp._processingMiddleware
|
delete nuxtApp._processingMiddleware
|
||||||
@ -202,6 +206,9 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
|
|||||||
// Clear any existing errors
|
// Clear any existing errors
|
||||||
await nuxtApp.runWithContext(clearError)
|
await nuxtApp.runWithContext(clearError)
|
||||||
}
|
}
|
||||||
|
if (failure) {
|
||||||
|
await nuxtApp.callHook('page:loading:end')
|
||||||
|
}
|
||||||
if (import.meta.server && failure?.type === 4 /* ErrorTypes.NAVIGATION_ABORTED */) {
|
if (import.meta.server && failure?.type === 4 /* ErrorTypes.NAVIGATION_ABORTED */) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import { setResponseStatus, useRequestEvent, useRequestFetch, useRequestHeaders
|
|||||||
import { clearNuxtState, useState } from '#app/composables/state'
|
import { clearNuxtState, useState } from '#app/composables/state'
|
||||||
import { useRequestURL } from '#app/composables/url'
|
import { useRequestURL } from '#app/composables/url'
|
||||||
import { getAppManifest, getRouteRules } from '#app/composables/manifest'
|
import { getAppManifest, getRouteRules } from '#app/composables/manifest'
|
||||||
|
import { useLoadingIndicator } from '#app/composables/loading-indicator'
|
||||||
|
|
||||||
vi.mock('#app/compat/idle-callback', () => ({
|
vi.mock('#app/compat/idle-callback', () => ({
|
||||||
requestIdleCallback: (cb: Function) => cb()
|
requestIdleCallback: (cb: Function) => cb()
|
||||||
@ -438,6 +439,21 @@ describe('url', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('loading state', () => {
|
||||||
|
it('expect loading state to be changed by hooks', async () => {
|
||||||
|
vi.stubGlobal('setTimeout', vi.fn((cb: Function) => cb()))
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
const { isLoading } = useLoadingIndicator()
|
||||||
|
expect(isLoading.value).toBeFalsy()
|
||||||
|
await nuxtApp.callHook('page:loading:start')
|
||||||
|
expect(isLoading.value).toBeTruthy()
|
||||||
|
|
||||||
|
await nuxtApp.callHook('page:loading:end')
|
||||||
|
expect(isLoading.value).toBeFalsy()
|
||||||
|
vi.mocked(setTimeout).mockRestore()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe.skipIf(process.env.TEST_MANIFEST === 'manifest-off')('app manifests', () => {
|
describe.skipIf(process.env.TEST_MANIFEST === 'manifest-off')('app manifests', () => {
|
||||||
it('getAppManifest', async () => {
|
it('getAppManifest', async () => {
|
||||||
const manifest = await getAppManifest()
|
const manifest = await getAppManifest()
|
||||||
|
Loading…
Reference in New Issue
Block a user