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

feat(nuxt): add onBeforeRouteLeave and onBeforeRouteUpdate composables #8889

Merged
merged 3 commits into from Nov 10, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/nuxt/src/app/composables/index.ts
Expand Up @@ -10,7 +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 { abortNavigation, addRouteMiddleware, defineNuxtRouteMiddleware, setPageLayout, navigateTo, useRoute, useActiveRoute, useRouter } from './router'
export { abortNavigation, addRouteMiddleware, defineNuxtRouteMiddleware, onBeforeRouteLeave, onBeforeRouteUpdate, setPageLayout, navigateTo, useRoute, useActiveRoute, useRouter } from './router'
export type { AddRouteMiddlewareOptions, RouteMiddleware } from './router'
export { preloadComponents, prefetchComponents, preloadRouteComponents } from './preload'
export { isPrerendered, loadPayload, preloadPayload } from './payload'
15 changes: 14 additions & 1 deletion packages/nuxt/src/app/composables/router.ts
@@ -1,4 +1,4 @@
import { getCurrentInstance, inject } from 'vue'
import { getCurrentInstance, inject, onUnmounted } from 'vue'
import type { Router, RouteLocationNormalizedLoaded, NavigationGuard, RouteLocationNormalized, RouteLocationRaw, NavigationFailure, RouteLocationPathRaw } from 'vue-router'
import { sendRedirect } from 'h3'
import { hasProtocol, joinURL, parseURL } from 'ufo'
Expand All @@ -17,6 +17,19 @@ export const useRoute = (): RouteLocationNormalizedLoaded => {
return useNuxtApp()._route
}

export const onBeforeRouteLeave = (guard: NavigationGuard) => {
const unsubscribe = useRouter().beforeEach((to, from, next) => {
if (to === from) { return }
return guard(to, from, next)
})
onUnmounted(unsubscribe)
}

export const onBeforeRouteUpdate = (guard: NavigationGuard) => {
const unsubscribe = useRouter().beforeEach(guard)
onUnmounted(unsubscribe)
}

/** @deprecated Use `useRoute` instead. */
export const useActiveRoute = (): RouteLocationNormalizedLoaded => {
return useNuxtApp()._route
Expand Down
11 changes: 7 additions & 4 deletions packages/nuxt/src/imports/module.ts
Expand Up @@ -31,23 +31,26 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
options = defu(nuxt.options.autoImports, options)
}

// TODO: fix sharing of defaults between invocations of modules
const presets = JSON.parse(JSON.stringify(options.presets)) as ImportPresetWithDeprecation[]

// Allow modules extending sources
await nuxt.callHook('imports:sources', options.presets as ImportPresetWithDeprecation[])
await nuxt.callHook('imports:sources', presets)

options.presets?.forEach((_i) => {
for (const _i of presets) {
const i = _i as ImportPresetWithDeprecation | string
if (typeof i !== 'string' && i.names && !i.imports) {
i.imports = i.names
logger.warn('imports: presets.names is deprecated, use presets.imports instead')
}
})
}

// Filter disabled sources
// options.sources = options.sources.filter(source => source.disabled !== true)

// Create a context to share state between module internals
const ctx = createUnimport({
presets: options.presets,
presets,
imports: options.imports,
virtualImports: ['#imports'],
addons: {
Expand Down
10 changes: 10 additions & 0 deletions packages/nuxt/src/imports/presets.ts
Expand Up @@ -64,6 +64,15 @@ const appPreset = defineUnimportPreset({
]
})

// vue-router
const routerPreset = defineUnimportPreset({
from: '#app',
imports: [
'onBeforeRouteLeave',
'onBeforeRouteUpdate'
]
})

// vue
const vuePreset = defineUnimportPreset({
from: 'vue',
Expand Down Expand Up @@ -140,5 +149,6 @@ const vuePreset = defineUnimportPreset({
export const defaultPresets: InlinePreset[] = [
...commonPresets,
appPreset,
routerPreset,
vuePreset
]
8 changes: 8 additions & 0 deletions packages/nuxt/src/pages/module.ts
Expand Up @@ -54,6 +54,14 @@ export default defineNuxtModule({
references.push({ types: 'vue-router' })
})

// Add vue-router route guard imports
nuxt.hook('imports:sources', (sources) => {
const routerImports = sources.find(s => s.from === '#app' && s.imports.includes('onBeforeRouteLeave'))
pi0 marked this conversation as resolved.
Show resolved Hide resolved
if (routerImports) {
routerImports.from = 'vue-router'
}
})

// Regenerate templates when adding or removing pages
nuxt.hook('builder:watch', async (event, path) => {
const dirs = [
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/test/auto-imports.test.ts
Expand Up @@ -66,7 +66,7 @@ describe('imports:nuxt', () => {
continue
}
it(`should register ${name} globally`, () => {
expect(defaultPresets.find(a => a.from === '#app')!.imports).to.include(name)
expect(defaultPresets.flatMap(a => a.from === '#app' ? a.imports : [])).to.include(name)
})
}
} catch (e) {
Expand Down