fix(nuxt): mark non-augmented NuxtApp properties as unknown (#19643)

This commit is contained in:
Daniel Roe 2023-03-14 10:09:50 +00:00 committed by GitHub
parent e84ec61eeb
commit 0f6276dc6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 59 additions and 14 deletions

View File

@ -25,7 +25,8 @@
"jsdoc/require-param-type": "off", "jsdoc/require-param-type": "off",
"no-redeclare": "off", "no-redeclare": "off",
"import/order": [ "import/order": [
"error", { "error",
{
"pathGroups": [ "pathGroups": [
{ {
"pattern": "@nuxt/test-utils", "pattern": "@nuxt/test-utils",
@ -73,6 +74,7 @@
}, },
"settings": { "settings": {
"jsdoc": { "jsdoc": {
"ignoreInternal": true,
"tagNamePreference": { "tagNamePreference": {
"warning": "warning", "warning": "warning",
"note": "note" "note": "note"

View File

@ -56,7 +56,7 @@ export default defineComponent({
nuxtApp[pKey] = nuxtApp[pKey] || {} nuxtApp[pKey] = nuxtApp[pKey] || {}
if (!nuxtApp[pKey][hashId.value]) { if (!nuxtApp[pKey][hashId.value]) {
nuxtApp[pKey][hashId.value] = _fetchComponent().finally(() => { nuxtApp[pKey][hashId.value] = _fetchComponent().finally(() => {
delete nuxtApp[pKey][hashId.value] delete nuxtApp[pKey]![hashId.value]
}) })
} }
const res: NuxtIslandResponse = await nuxtApp[pKey][hashId.value] const res: NuxtIslandResponse = await nuxtApp[pKey][hashId.value]

View File

@ -7,7 +7,7 @@ interface LoadPayloadOptions {
hash?: string hash?: string
} }
export function loadPayload (url: string, opts: LoadPayloadOptions = {}) { export function loadPayload (url: string, opts: LoadPayloadOptions = {}): Record<string, any> | Promise<Record<string, any>> | null {
if (process.server) { return null } if (process.server) { return null }
const payloadURL = _getPayloadURL(url, opts) const payloadURL = _getPayloadURL(url, opts)
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()

View File

@ -53,10 +53,16 @@ interface AddRouteMiddleware {
export const addRouteMiddleware: AddRouteMiddleware = (name: string | RouteMiddleware, middleware?: RouteMiddleware, options: AddRouteMiddlewareOptions = {}) => { export const addRouteMiddleware: AddRouteMiddleware = (name: string | RouteMiddleware, middleware?: RouteMiddleware, options: AddRouteMiddlewareOptions = {}) => {
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
if (options.global || typeof name === 'function') { const global = options.global || typeof name !== 'string'
nuxtApp._middleware.global.push(typeof name === 'function' ? name : middleware) const mw = typeof name !== 'string' ? name : middleware
if (!mw) {
console.warn('[nuxt] No route middleware passed to `addRouteMiddleware`.', name)
return
}
if (global) {
nuxtApp._middleware.global.push(mw)
} else { } else {
nuxtApp._middleware.named[name] = middleware nuxtApp._middleware.named[name] = mw
} }
} }

View File

@ -1,15 +1,17 @@
/* eslint-disable no-use-before-define */ /* eslint-disable no-use-before-define */
import { getCurrentInstance, reactive } from 'vue' import { getCurrentInstance, reactive } from 'vue'
import type { App, onErrorCaptured, VNode, Ref } from 'vue' import type { App, onErrorCaptured, VNode, Ref } from 'vue'
import type { RouteLocationNormalizedLoaded, Router } from 'vue-router'
import type { Hookable } from 'hookable' import type { Hookable } from 'hookable'
import { createHooks } from 'hookable' import { createHooks } from 'hookable'
import { getContext } from 'unctx' import { getContext } from 'unctx'
import type { SSRContext } from 'vue-bundle-renderer/runtime' import type { SSRContext } from 'vue-bundle-renderer/runtime'
import type { H3Event } from 'h3' import type { H3Event } from 'h3'
import type { RuntimeConfig, AppConfigInput } from 'nuxt/schema' import type { RuntimeConfig, AppConfigInput, AppConfig } from 'nuxt/schema'
// eslint-disable-next-line import/no-restricted-paths // eslint-disable-next-line import/no-restricted-paths
import type { NuxtIslandContext } from '../core/runtime/nitro/renderer' import type { NuxtIslandContext } from '../core/runtime/nitro/renderer'
import type { RouteMiddleware } from '../../app'
const nuxtAppCtx = /* #__PURE__ */ getContext<NuxtApp>('nuxt-app') const nuxtAppCtx = /* #__PURE__ */ getContext<NuxtApp>('nuxt-app')
@ -67,15 +69,40 @@ interface _NuxtApp {
hook: _NuxtApp['hooks']['hook'] hook: _NuxtApp['hooks']['hook']
callHook: _NuxtApp['hooks']['callHook'] callHook: _NuxtApp['hooks']['callHook']
[key: string]: any [key: string]: unknown
/** @internal */
_asyncDataPromises: Record<string, Promise<any> | undefined> _asyncDataPromises: Record<string, Promise<any> | undefined>
/** @internal */
_asyncData: Record<string, { _asyncData: Record<string, {
data: Ref<any> data: Ref<any>
pending: Ref<boolean> pending: Ref<boolean>
error: Ref<any> error: Ref<any>
} | undefined> } | undefined>
/** @internal */
_middleware: {
global: RouteMiddleware[]
named: Record<string, RouteMiddleware>
}
/** @internal */
_observer?: { observe: (element: Element, callback: () => void) => () => void }
/** @internal */
_payloadCache?: Record<string, Promise<Record<string, any>> | Record<string, any>>
/** @internal */
_appConfig: AppConfig
/** @internal */
_route: RouteLocationNormalizedLoaded
/** @internal */
_islandPromises?: Record<string, Promise<any>>
// Nuxt injections
$config: RuntimeConfig
$router: Router
isHydrating?: boolean isHydrating?: boolean
deferHydration: () => () => void | Promise<void> deferHydration: () => () => void | Promise<void>

View File

@ -11,9 +11,9 @@ export default defineNuxtPlugin((nuxtApp) => {
} }
// Load payload into cache // Load payload into cache
nuxtApp.hooks.hook('link:prefetch', (url) => { nuxtApp.hooks.hook('link:prefetch', async (url) => {
if (!parseURL(url).protocol) { if (!parseURL(url).protocol) {
return loadPayload(url) await loadPayload(url)
} }
}) })

View File

@ -30,6 +30,8 @@ interface Route {
redirectedFrom: Route | undefined redirectedFrom: Route | undefined
/** Merged `meta` properties from all of the matched route records. */ /** Merged `meta` properties from all of the matched route records. */
meta: Record<string, any> meta: Record<string, any>
/** compatibility type for vue-router */
matched: never[]
} }
function getRouteFromPath (fullPath: string | Partial<Route>) { function getRouteFromPath (fullPath: string | Partial<Route>) {

View File

@ -67,7 +67,7 @@ const NuxtServerComponent = defineComponent({
nuxtApp[pKey] = nuxtApp[pKey] || {} nuxtApp[pKey] = nuxtApp[pKey] || {}
if (!nuxtApp[pKey][hashId.value]) { if (!nuxtApp[pKey][hashId.value]) {
nuxtApp[pKey][hashId.value] = _fetchComponent().finally(() => { nuxtApp[pKey][hashId.value] = _fetchComponent().finally(() => {
delete nuxtApp[pKey][hashId.value] delete nuxtApp[pKey]![hashId.value]
}) })
} }
const res: NuxtIslandResponse = await nuxtApp[pKey][hashId.value] const res: NuxtIslandResponse = await nuxtApp[pKey][hashId.value]

View File

@ -1,7 +1,6 @@
import { computed, isReadonly, reactive, shallowRef } from 'vue' import { computed, isReadonly, reactive, shallowRef } from 'vue'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import type { import type {
NavigationGuard,
RouteLocation RouteLocation
} from 'vue-router' } from 'vue-router'
import { import {
@ -13,7 +12,7 @@ import {
import { createError } from 'h3' import { createError } from 'h3'
import { withoutBase, isEqual } from 'ufo' import { withoutBase, isEqual } from 'ufo'
import type { PageMeta } from '#app' import type { PageMeta, RouteMiddleware } from '#app'
import { callWithNuxt, defineNuxtPlugin, useRuntimeConfig } from '#app/nuxt' import { callWithNuxt, defineNuxtPlugin, useRuntimeConfig } from '#app/nuxt'
import { showError, clearError, useError } from '#app/composables/error' import { showError, clearError, useError } from '#app/composables/error'
import { useRequestEvent } from '#app/composables/ssr' import { useRequestEvent } from '#app/composables/ssr'
@ -125,7 +124,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
} }
nuxtApp._processingMiddleware = true nuxtApp._processingMiddleware = true
type MiddlewareDef = string | NavigationGuard type MiddlewareDef = string | RouteMiddleware
const middlewareEntries = new Set<MiddlewareDef>([...globalMiddleware, ...nuxtApp._middleware.global]) const middlewareEntries = new Set<MiddlewareDef>([...globalMiddleware, ...nuxtApp._middleware.global])
for (const component of to.matched) { for (const component of to.matched) {
const componentMiddleware = component.meta.middleware as MiddlewareDef | MiddlewareDef[] const componentMiddleware = component.meta.middleware as MiddlewareDef | MiddlewareDef[]

View File

@ -127,6 +127,15 @@ describe('modules', () => {
}) })
}) })
describe('nuxtApp', () => {
it('types injections provided by plugins', () => {
expectTypeOf(useNuxtApp().$asyncPlugin).toEqualTypeOf<() => string>()
})
it('marks unknown injections as unknown', () => {
expectTypeOf(useNuxtApp().doesNotExist).toEqualTypeOf<unknown>()
})
})
describe('runtimeConfig', () => { describe('runtimeConfig', () => {
it('generated runtimeConfig types', () => { it('generated runtimeConfig types', () => {
const runtimeConfig = useRuntimeConfig() const runtimeConfig = useRuntimeConfig()