mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-26 15:42:09 +00:00
feat(bridge): support addRouteMiddleware
, navigateTo
and abortNavigation
(#3193)
This commit is contained in:
parent
d046c9620b
commit
3c563fa48f
@ -30,6 +30,10 @@ export async function setupAutoImports () {
|
|||||||
// Add auto-imports that are added by ad-hoc modules in nuxt 3
|
// Add auto-imports that are added by ad-hoc modules in nuxt 3
|
||||||
autoImports.push({ name: 'useRouter', as: 'useRouter', from: '#app' })
|
autoImports.push({ name: 'useRouter', as: 'useRouter', from: '#app' })
|
||||||
autoImports.push({ name: 'useRoute', as: 'useRoute', from: '#app' })
|
autoImports.push({ name: 'useRoute', as: 'useRoute', from: '#app' })
|
||||||
|
autoImports.push({ name: 'addRouteMiddleware', as: 'addRouteMiddleware', from: '#app' })
|
||||||
|
autoImports.push({ name: 'navigateTo', as: 'navigateTo', from: '#app' })
|
||||||
|
autoImports.push({ name: 'abortNavigation', as: 'abortNavigation', from: '#app' })
|
||||||
|
autoImports.push({ name: 'defineNuxtRouteMiddleware', as: 'defineNuxtRouteMiddleware', from: '#app' })
|
||||||
|
|
||||||
// Add bridge-only auto-imports
|
// Add bridge-only auto-imports
|
||||||
autoImports.push({ name: 'useNuxt2Meta', as: 'useNuxt2Meta', from: '#app' })
|
autoImports.push({ name: 'useNuxt2Meta', as: 'useNuxt2Meta', from: '#app' })
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { createHooks } from 'hookable'
|
import { createHooks } from 'hookable'
|
||||||
import { setNuxtAppInstance } from '#app'
|
import { callWithNuxt, setNuxtAppInstance } from '#app'
|
||||||
|
|
||||||
// Reshape payload to match key `useLazyAsyncData` expects
|
// Reshape payload to match key `useLazyAsyncData` expects
|
||||||
function proxiedState (state) {
|
function proxiedState (state) {
|
||||||
@ -19,7 +19,7 @@ function proxiedState (state) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (ctx, inject) => {
|
export default async (ctx, inject) => {
|
||||||
const nuxtApp = {
|
const nuxtApp = {
|
||||||
vueApp: {
|
vueApp: {
|
||||||
component: Vue.component.bind(Vue),
|
component: Vue.component.bind(Vue),
|
||||||
@ -48,6 +48,27 @@ export default (ctx, inject) => {
|
|||||||
nuxtApp.hook = nuxtApp.hooks.hook
|
nuxtApp.hook = nuxtApp.hooks.hook
|
||||||
nuxtApp.callHook = nuxtApp.hooks.callHook
|
nuxtApp.callHook = nuxtApp.hooks.callHook
|
||||||
|
|
||||||
|
const middleware = await import('#build/middleware').then(r => r.default)
|
||||||
|
nuxtApp._middleware = nuxtApp._middleware || {
|
||||||
|
global: [],
|
||||||
|
named: middleware
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.app.router.beforeEach(async (to, from, next) => {
|
||||||
|
nuxtApp._processingMiddleware = true
|
||||||
|
|
||||||
|
for (const middleware of nuxtApp._middleware.global) {
|
||||||
|
const result = await callWithNuxt(nuxtApp, middleware, [to, from])
|
||||||
|
if (result || result === false) { return next(result) }
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx.app.router.afterEach(() => {
|
||||||
|
delete nuxtApp._processingMiddleware
|
||||||
|
})
|
||||||
|
|
||||||
if (!Array.isArray(ctx.app.created)) {
|
if (!Array.isArray(ctx.app.created)) {
|
||||||
ctx.app.created = [ctx.app.created].filter(Boolean)
|
ctx.app.created = [ctx.app.created].filter(Boolean)
|
||||||
}
|
}
|
||||||
|
@ -58,12 +58,24 @@ export const setNuxtAppInstance = (nuxt: NuxtAppCompat | null) => {
|
|||||||
currentNuxtAppInstance = nuxt
|
currentNuxtAppInstance = nuxt
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defineNuxtPlugin (plugin: (nuxtApp: NuxtAppCompat) => void): (ctx: Context) => void {
|
/**
|
||||||
return (ctx) => {
|
* Ensures that the setup function passed in has access to the Nuxt instance via `useNuxt`.
|
||||||
setNuxtAppInstance(ctx.$_nuxtApp)
|
*
|
||||||
plugin(ctx.$_nuxtApp)
|
* @param nuxt A Nuxt instance
|
||||||
|
* @param setup The function to call
|
||||||
|
*/
|
||||||
|
export function callWithNuxt<T extends (...args: any[]) => any> (nuxt: NuxtAppCompat, setup: T, args?: Parameters<T>) {
|
||||||
|
setNuxtAppInstance(nuxt)
|
||||||
|
const p: ReturnType<T> = args ? setup(...args as Parameters<T>) : setup()
|
||||||
|
if (process.server) {
|
||||||
|
// Unset nuxt instance to prevent context-sharing in server-side
|
||||||
setNuxtAppInstance(null)
|
setNuxtAppInstance(null)
|
||||||
}
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
export function defineNuxtPlugin (plugin: (nuxtApp: NuxtAppCompat) => void): (ctx: Context) => void {
|
||||||
|
return ctx => callWithNuxt(ctx.$_nuxtApp, plugin, [ctx.$_nuxtApp])
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useNuxtApp = (): NuxtAppCompat => {
|
export const useNuxtApp = (): NuxtAppCompat => {
|
||||||
|
@ -2,7 +2,7 @@ import { getCurrentInstance, onBeforeUnmount, isRef, watch, reactive, toRef, isR
|
|||||||
import type { CombinedVueInstance } from 'vue/types/vue'
|
import type { CombinedVueInstance } from 'vue/types/vue'
|
||||||
import type { MetaInfo } from 'vue-meta'
|
import type { MetaInfo } from 'vue-meta'
|
||||||
import type VueRouter from 'vue-router'
|
import type VueRouter from 'vue-router'
|
||||||
import type { Route } from 'vue-router'
|
import type { Location, Route } from 'vue-router'
|
||||||
import type { RuntimeConfig } from '@nuxt/schema'
|
import type { RuntimeConfig } from '@nuxt/schema'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
import { useNuxtApp } from './app'
|
import { useNuxtApp } from './app'
|
||||||
@ -141,3 +141,69 @@ export const useNuxt2Meta = (metaOptions: Reffed<MetaInfo> | (() => Reffed<MetaI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AddRouteMiddlewareOptions {
|
||||||
|
global?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/** internal */
|
||||||
|
function convertToLegacyMiddleware (middleware) {
|
||||||
|
return async (ctx: any) => {
|
||||||
|
const result = await middleware(ctx.route, ctx.from)
|
||||||
|
if (result instanceof Error) {
|
||||||
|
return ctx.error(result)
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
return ctx.redirect(result)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addRouteMiddleware = (name: string, middleware: any, options: AddRouteMiddlewareOptions = {}) => {
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
if (options.global) {
|
||||||
|
nuxtApp._middleware.global.push(middleware)
|
||||||
|
} else {
|
||||||
|
nuxtApp._middleware.named[name] = convertToLegacyMiddleware(middleware)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isProcessingMiddleware = () => {
|
||||||
|
try {
|
||||||
|
if (useNuxtApp()._processingMiddleware) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Within an async middleware
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export const navigateTo = (to: Route) => {
|
||||||
|
if (isProcessingMiddleware()) {
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
const router: VueRouter = process.server ? useRouter() : (window as any).$nuxt.router
|
||||||
|
return router.push(to)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This will abort navigation within a Nuxt route middleware handler. */
|
||||||
|
export const abortNavigation = (err?: Error | string) => {
|
||||||
|
if (process.dev && !isProcessingMiddleware()) {
|
||||||
|
throw new Error('abortNavigation() is only usable inside a route middleware handler.')
|
||||||
|
}
|
||||||
|
if (err) {
|
||||||
|
throw err instanceof Error ? err : new Error(err)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouteMiddlewareReturn = void | Error | string | Location | boolean
|
||||||
|
|
||||||
|
export interface RouteMiddleware {
|
||||||
|
(to: Route, from: Route): RouteMiddlewareReturn | Promise<RouteMiddlewareReturn>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defineNuxtRouteMiddleware = (middleware: RouteMiddleware) => middleware
|
||||||
|
@ -60,7 +60,10 @@ const isProcessingMiddleware = () => {
|
|||||||
if (useNuxtApp()._processingMiddleware) {
|
if (useNuxtApp()._processingMiddleware) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {
|
||||||
|
// Within an async middleware
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user