From e4f3225c53347e7033403b4b759dd127356572e6 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Thu, 4 Aug 2022 23:59:32 +0800 Subject: [PATCH 01/15] chore: enable ts strict for `packages/nuxt` --- packages/nuxt/src/app/compat/capi.ts | 10 +++---- .../src/app/components/nuxt-error-boundary.ts | 2 +- packages/nuxt/src/app/components/nuxt-link.ts | 26 ++++++++++++------- packages/nuxt/src/app/components/utils.ts | 6 ++--- .../nuxt/src/app/composables/asyncData.ts | 20 +++++++------- .../nuxt/src/app/composables/component.ts | 8 +++--- packages/nuxt/src/app/composables/cookie.ts | 11 ++++---- packages/nuxt/src/app/composables/fetch.ts | 2 +- packages/nuxt/src/app/composables/router.ts | 2 +- packages/nuxt/src/app/composables/ssr.ts | 4 +-- packages/nuxt/src/app/composables/state.ts | 2 +- packages/nuxt/src/app/composables/utils.ts | 3 --- packages/nuxt/src/app/entry.ts | 4 +-- packages/nuxt/src/app/nuxt.ts | 22 ++++++++-------- .../nuxt/src/app/plugins/logs.client.dev.ts | 2 +- .../nuxt/src/app/plugins/progress.client.ts | 8 +++--- packages/nuxt/src/app/plugins/router.ts | 7 ++--- packages/nuxt/tsconfig.json | 10 +++++++ 18 files changed, 80 insertions(+), 69 deletions(-) delete mode 100644 packages/nuxt/src/app/composables/utils.ts create mode 100644 packages/nuxt/tsconfig.json diff --git a/packages/nuxt/src/app/compat/capi.ts b/packages/nuxt/src/app/compat/capi.ts index 5bbad31e0de..2ef0b9f7498 100644 --- a/packages/nuxt/src/app/compat/capi.ts +++ b/packages/nuxt/src/app/compat/capi.ts @@ -2,19 +2,19 @@ export * from 'vue' export const install = () => {} -export function set (target, key, val) { +export function set (target: any, key: string | number | symbol, val: any) { if (Array.isArray(target)) { - target.length = Math.max(target.length, key) - target.splice(key, 1, val) + target.length = Math.max(target.length, key as number) + target.splice(key as number, 1, val) return val } target[key] = val return val } -export function del (target, key) { +export function del (target: any, key: string | number | symbol) { if (Array.isArray(target)) { - target.splice(key, 1) + target.splice(key as number, 1) return } delete target[key] diff --git a/packages/nuxt/src/app/components/nuxt-error-boundary.ts b/packages/nuxt/src/app/components/nuxt-error-boundary.ts index 1cf30750874..b1b155a2b7c 100644 --- a/packages/nuxt/src/app/components/nuxt-error-boundary.ts +++ b/packages/nuxt/src/app/components/nuxt-error-boundary.ts @@ -8,7 +8,7 @@ export default defineComponent({ } }, setup (_props, { slots, emit }) { - const error = ref(null) + const error = ref(null) const nuxtApp = useNuxtApp() onErrorCaptured((err) => { diff --git a/packages/nuxt/src/app/components/nuxt-link.ts b/packages/nuxt/src/app/components/nuxt-link.ts index d6d086444c9..dae042c0509 100644 --- a/packages/nuxt/src/app/components/nuxt-link.ts +++ b/packages/nuxt/src/app/components/nuxt-link.ts @@ -1,10 +1,10 @@ -import { defineComponent, h, resolveComponent, PropType, computed, DefineComponent } from 'vue' -import { RouteLocationRaw, Router } from 'vue-router' +import { defineComponent, h, resolveComponent, PropType, computed, DefineComponent, ComputedRef } from 'vue' +import { RouteLocationRaw } from 'vue-router' import { hasProtocol } from 'ufo' import { navigateTo, useRouter } from '#app' -const firstNonUndefined = (...args: T[]): T => args.find(arg => arg !== undefined) +const firstNonUndefined = (...args: (T | undefined)[]) => args.find(arg => arg !== undefined) const DEFAULT_EXTERNAL_REL_ATTRIBUTE = 'noopener noreferrer' @@ -39,7 +39,7 @@ export type NuxtLinkProps = { export function defineNuxtLink (options: NuxtLinkOptions) { const componentName = options.componentName || 'NuxtLink' - const checkPropConflicts = (props: NuxtLinkProps, main: string, sub: string): void => { + const checkPropConflicts = (props: NuxtLinkProps, main: keyof NuxtLinkProps, sub: keyof NuxtLinkProps): void => { if (process.dev && props[main] !== undefined && props[sub] !== undefined) { console.warn(`[${componentName}] \`${main}\` and \`${sub}\` cannot be used together. \`${sub}\` will be ignored.`) } @@ -116,10 +116,10 @@ export function defineNuxtLink (options: NuxtLinkOptions) { } }, setup (props, { slots }) { - const router = useRouter() as Router | undefined + const router = useRouter() // Resolving `to` value from `to` and `href` props - const to = computed(() => { + const to: ComputedRef = computed(() => { checkPropConflicts(props, 'to', 'href') return props.to || props.href || '' // Defaults to empty string (won't render any `href` attribute) @@ -127,7 +127,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) { // Resolving link type const isExternal = computed(() => { - // External prop is explictly set + // External prop is explicitly set if (props.external) { return true } @@ -176,15 +176,21 @@ export function defineNuxtLink (options: NuxtLinkOptions) { // converts `""` to `null` to prevent the attribute from being added as empty (`rel=""`) : firstNonUndefined(props.rel, options.externalRelAttribute, href ? DEFAULT_EXTERNAL_REL_ATTRIBUTE : '') || null - const navigate = () => navigateTo(href, { replace: props.replace }) + const navigate = () => { + if (href) { + navigateTo(href, { replace: props.replace }) + } + } // https://router.vuejs.org/api/#custom if (props.custom) { - if (!slots.default) { return null } + if (!slots.default) { + return null + } return slots.default({ href, navigate, - route: router.resolve(href), + route: href ? router.resolve(href) : undefined, rel, target, isActive: false, diff --git a/packages/nuxt/src/app/components/utils.ts b/packages/nuxt/src/app/components/utils.ts index 42812f8406d..94a8a10695e 100644 --- a/packages/nuxt/src/app/components/utils.ts +++ b/packages/nuxt/src/app/components/utils.ts @@ -1,11 +1,11 @@ -import { h } from 'vue' +import { defineComponent, h } from 'vue' import type { Component } from 'vue' -const Fragment = { +const Fragment = defineComponent({ setup (_props, { slots }) { return () => slots.default?.() } -} +}) /** * Internal utility diff --git a/packages/nuxt/src/app/composables/asyncData.ts b/packages/nuxt/src/app/composables/asyncData.ts index a644d78f977..e834113ac72 100644 --- a/packages/nuxt/src/app/composables/asyncData.ts +++ b/packages/nuxt/src/app/composables/asyncData.ts @@ -1,6 +1,5 @@ import { onBeforeMount, onServerPrefetch, onUnmounted, ref, getCurrentInstance, watch, unref } from 'vue' import type { Ref, WatchSource } from 'vue' -import { wrapInRef } from './utils' import { NuxtApp, useNuxtApp } from '#app' export type _Transform = (input: Input) => Output @@ -25,7 +24,7 @@ export interface AsyncDataOptions< > { server?: boolean lazy?: boolean - default?: () => DataT | Ref + default?: () => DataT | Ref | null transform?: Transform pick?: PickKeys watch?: MultiWatchSources @@ -37,10 +36,10 @@ export interface RefreshOptions { } export interface _AsyncData { - data: Ref + data: Ref pending: Ref refresh: (opts?: RefreshOptions) => Promise - error: Ref + error: Ref } export type AsyncData = _AsyncData & Promise<_AsyncData> @@ -70,7 +69,7 @@ export function useAsyncData< DataE = Error, Transform extends _Transform = _Transform, PickKeys extends KeyOfRes = KeyOfRes -> (...args): AsyncData, PickKeys>, DataE | null | true> { +> (...args: any[]): AsyncData, PickKeys>, DataE | null | true> { const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined if (typeof args[0] !== 'string') { args.unshift(autoKey) } @@ -102,7 +101,8 @@ export function useAsyncData< // Setup hook callbacks once per instance const instance = getCurrentInstance() if (instance && !instance._nuxtOnBeforeMountCbs) { - const cbs = instance._nuxtOnBeforeMountCbs = [] + instance._nuxtOnBeforeMountCbs = [] + const cbs = instance._nuxtOnBeforeMountCbs if (instance && process.client) { onBeforeMount(() => { cbs.forEach((cb) => { cb() }) @@ -115,7 +115,7 @@ export function useAsyncData< const useInitialCache = () => options.initialCache && nuxt.payload.data[key] !== undefined const asyncData = { - data: wrapInRef(nuxt.payload.data[key] ?? options.default()), + data: ref(nuxt.payload.data[key] ?? options.default?.() ?? null), pending: ref(!useInitialCache()), error: ref(nuxt.payload._errors[key] ?? null) } as AsyncData @@ -145,7 +145,7 @@ export function useAsyncData< }) .catch((error: any) => { asyncData.error.value = error - asyncData.data.value = unref(options.default()) + asyncData.data.value = unref(options.default?.() ?? null) }) .finally(() => { asyncData.pending.value = false @@ -224,7 +224,7 @@ export function useLazyAsyncData< DataE = Error, Transform extends _Transform = _Transform, PickKeys extends KeyOfRes = KeyOfRes -> (...args): AsyncData, PickKeys>, DataE | null | true> { +> (...args: any[]): AsyncData, PickKeys>, DataE | null | true> { const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined if (typeof args[0] !== 'string') { args.unshift(autoKey) } const [key, handler, options] = args as [string, (ctx?: NuxtApp) => Promise, AsyncDataOptions] @@ -243,7 +243,7 @@ export function refreshNuxtData (keys?: string | string[]): Promise { function pick (obj: Record, keys: string[]) { const newObj = {} for (const key of keys) { - newObj[key] = obj[key] + (newObj as any)[key] = obj[key] } return newObj } diff --git a/packages/nuxt/src/app/composables/component.ts b/packages/nuxt/src/app/composables/component.ts index 32b1449705a..63348c6538a 100644 --- a/packages/nuxt/src/app/composables/component.ts +++ b/packages/nuxt/src/app/composables/component.ts @@ -9,8 +9,8 @@ export const NuxtComponentIndicator = '__nuxt_component' async function runLegacyAsyncData (res: Record | Promise>, fn: (nuxtApp: NuxtApp) => Promise>) { const nuxt = useNuxtApp() const route = useRoute() - const vm = getCurrentInstance() - const { fetchKey } = vm.proxy.$options + const vm = getCurrentInstance()! + const { fetchKey } = vm.proxy!.$options const key = typeof fetchKey === 'function' ? fetchKey(() => '') : fetchKey || route.fullPath const { data } = await useAsyncData(`options:asyncdata:${key}`, () => fn(nuxt)) if (data.value && typeof data.value === 'object') { @@ -38,8 +38,7 @@ export const defineNuxtComponent: typeof defineComponent = setup (props, ctx) { const res = setup?.(props, ctx) || {} - let promises: unknown[] | undefined = [] - promises = promises || [] + const promises: Promise[] = [] if (options.asyncData) { promises.push(runLegacyAsyncData(res, options.asyncData)) } @@ -49,7 +48,6 @@ export const defineNuxtComponent: typeof defineComponent = .then(() => res) .finally(() => { promises.length = 0 - promises = null }) } } as DefineComponent diff --git a/packages/nuxt/src/app/composables/cookie.ts b/packages/nuxt/src/app/composables/cookie.ts index 4898b86b27c..2b8657c9775 100644 --- a/packages/nuxt/src/app/composables/cookie.ts +++ b/packages/nuxt/src/app/composables/cookie.ts @@ -1,10 +1,9 @@ -import { Ref, watch } from 'vue' +import { ref, Ref, watch } from 'vue' import { parse, serialize, CookieParseOptions, CookieSerializeOptions } from 'cookie-es' import { appendHeader } from 'h3' import type { CompatibilityEvent } from 'h3' import destr from 'destr' import { useRequestEvent } from './ssr' -import { wrapInRef } from './utils' import { useNuxtApp } from '#app' type _CookieOptions = Omit @@ -23,11 +22,11 @@ const CookieDefaults: CookieOptions = { encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val)) } -export function useCookie (name: string, _opts?: CookieOptions): CookieRef { +export function useCookie (name: string, _opts?: CookieOptions): CookieRef { const opts = { ...CookieDefaults, ..._opts } - const cookies = readRawCookies(opts) + const cookies = readRawCookies(opts) || {} - const cookie = wrapInRef(cookies[name] ?? opts.default?.()) + const cookie = ref(cookies[name] as any ?? opts.default?.()) if (process.client) { watch(cookie, () => { writeClientCookie(name, cookie.value, opts as CookieSerializeOptions) }) @@ -45,7 +44,7 @@ export function useCookie (name: string, _opts?: CookieOptions): C return cookie as CookieRef } -function readRawCookies (opts: CookieOptions = {}): Record { +function readRawCookies (opts: CookieOptions = {}): Record | undefined { if (process.server) { return parse(useRequestEvent()?.req.headers.cookie || '', opts) } else if (process.client) { diff --git a/packages/nuxt/src/app/composables/fetch.ts b/packages/nuxt/src/app/composables/fetch.ts index 38a9594ed45..a1e8132cdcd 100644 --- a/packages/nuxt/src/app/composables/fetch.ts +++ b/packages/nuxt/src/app/composables/fetch.ts @@ -37,7 +37,7 @@ export function useFetch< arg1?: string | UseFetchOptions<_ResT, Transform, PickKeys>, arg2?: string ) { - const [opts, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2] + const [opts = {}, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2] const _key = opts.key || autoKey if (!_key || typeof _key !== 'string') { throw new TypeError('[nuxt] [useFetch] key must be a string: ' + _key) diff --git a/packages/nuxt/src/app/composables/router.ts b/packages/nuxt/src/app/composables/router.ts index 106fa66782c..ff35ba07476 100644 --- a/packages/nuxt/src/app/composables/router.ts +++ b/packages/nuxt/src/app/composables/router.ts @@ -74,7 +74,7 @@ export const navigateTo = (to: RouteLocationRaw, options: NavigateToOptions = {} const nuxtApp = useNuxtApp() if (nuxtApp.ssrContext && nuxtApp.ssrContext.event) { const redirectLocation = joinURL(useRuntimeConfig().app.baseURL, router.resolve(to).fullPath || '/') - return nuxtApp.callHook('app:redirected').then(() => sendRedirect(nuxtApp.ssrContext.event, redirectLocation, options.redirectCode || 302)) + return nuxtApp.callHook('app:redirected').then(() => sendRedirect(nuxtApp.ssrContext!.event, redirectLocation, options.redirectCode || 302)) } } // Client-side redirection using vue-router diff --git a/packages/nuxt/src/app/composables/ssr.ts b/packages/nuxt/src/app/composables/ssr.ts index 1cb916ee6af..6172aa9a239 100644 --- a/packages/nuxt/src/app/composables/ssr.ts +++ b/packages/nuxt/src/app/composables/ssr.ts @@ -5,9 +5,9 @@ import { NuxtApp } from '#app/nuxt' export function useRequestHeaders (include: K[]): Record export function useRequestHeaders (): Readonly> -export function useRequestHeaders (include?) { +export function useRequestHeaders (include?: any[]) { if (process.client) { return {} } - const headers: Record = useNuxtApp().ssrContext?.event.req.headers ?? {} + const headers = useNuxtApp().ssrContext?.event.req.headers ?? {} if (!include) { return headers } return Object.fromEntries(include.filter(key => headers[key]).map(key => [key, headers[key]])) } diff --git a/packages/nuxt/src/app/composables/state.ts b/packages/nuxt/src/app/composables/state.ts index 451e6987b97..95f53ca2d27 100644 --- a/packages/nuxt/src/app/composables/state.ts +++ b/packages/nuxt/src/app/composables/state.ts @@ -10,7 +10,7 @@ import { useNuxtApp } from '#app' */ export function useState (key?: string, init?: (() => T | Ref)): Ref export function useState (init?: (() => T | Ref)): Ref -export function useState (...args): Ref { +export function useState (...args: any): Ref { const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined if (typeof args[0] !== 'string') { args.unshift(autoKey) } const [_key, init] = args as [string, (() => T | Ref)] diff --git a/packages/nuxt/src/app/composables/utils.ts b/packages/nuxt/src/app/composables/utils.ts deleted file mode 100644 index 1f454328cb2..00000000000 --- a/packages/nuxt/src/app/composables/utils.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { isRef, ref, Ref } from 'vue' - -export const wrapInRef = (value: T | Ref) => isRef(value) ? value : ref(value) diff --git a/packages/nuxt/src/app/entry.ts b/packages/nuxt/src/app/entry.ts index 36388b78263..01222c8bf20 100644 --- a/packages/nuxt/src/app/entry.ts +++ b/packages/nuxt/src/app/entry.ts @@ -35,7 +35,7 @@ if (process.server) { await nuxt.hooks.callHook('app:created', vueApp) } catch (err) { await nuxt.callHook('app:error', err) - ssrContext.error = ssrContext.error || err + ssrContext!.error ||= err } return vueApp @@ -81,7 +81,7 @@ if (process.client) { } } - entry().catch((error) => { + entry().catch((error: unknown) => { console.error('Error while mounting app:', error) // eslint-disable-line no-console }) } diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts index c243a8a7b38..93332c265dd 100644 --- a/packages/nuxt/src/app/nuxt.ts +++ b/packages/nuxt/src/app/nuxt.ts @@ -48,7 +48,7 @@ interface _NuxtApp { [key: string]: any - _asyncDataPromises?: Record> + _asyncDataPromises: Record | undefined> ssrContext?: SSRContext & { url: string @@ -67,8 +67,8 @@ interface _NuxtApp { } payload: { serverRendered?: boolean - data?: Record - state?: Record + data: Record + state: Record rendered?: Function [key: string]: any } @@ -127,23 +127,23 @@ export function createNuxtApp (options: CreateOptions) { if (process.server) { // Expose to server renderer to create window.__NUXT__ nuxtApp.ssrContext = nuxtApp.ssrContext || {} as any - nuxtApp.ssrContext.payload = nuxtApp.payload + nuxtApp.ssrContext!.payload = nuxtApp.payload } // Expose client runtime-config to the payload if (process.server) { nuxtApp.payload.config = { - public: options.ssrContext.runtimeConfig.public, - app: options.ssrContext.runtimeConfig.app + public: options.ssrContext!.runtimeConfig.public, + app: options.ssrContext!.runtimeConfig.app } } // Expose runtime config const runtimeConfig = process.server - ? options.ssrContext.runtimeConfig + ? options.ssrContext!.runtimeConfig : reactive(nuxtApp.payload.config) - // Backward compatibilty following #4254 + // Backward compatibility following #4254 const compatibilityConfig = new Proxy(runtimeConfig, { get (target, prop) { if (prop === 'public') { @@ -183,9 +183,9 @@ export async function applyPlugins (nuxtApp: NuxtApp, plugins: Plugin[]) { } export function normalizePlugins (_plugins: Plugin[]) { - const unwrappedPlugins = [] - const legacyInjectPlugins = [] - const invalidPlugins = [] + const unwrappedPlugins: Plugin[] = [] + const legacyInjectPlugins: Plugin[] = [] + const invalidPlugins: Plugin[] = [] const plugins = _plugins.map((plugin) => { if (typeof plugin !== 'function') { diff --git a/packages/nuxt/src/app/plugins/logs.client.dev.ts b/packages/nuxt/src/app/plugins/logs.client.dev.ts index 75976931f73..acf7663b618 100644 --- a/packages/nuxt/src/app/plugins/logs.client.dev.ts +++ b/packages/nuxt/src/app/plugins/logs.client.dev.ts @@ -6,7 +6,7 @@ export default defineNuxtPlugin((nuxtApp) => { if (logs.length > 0) { const ssrLogStyle = 'background: #003C3C;border-radius: 0.5em;color: white;font-weight: bold;padding: 2px 0.5em;' console.groupCollapsed && console.groupCollapsed('%cNuxt Server Logs', ssrLogStyle) - logs.forEach(logObj => (console[logObj.type] || console.log)(...logObj.args)) + logs.forEach((logObj:any) => (console[logObj.type as 'log'] || console.log)(...logObj.args)) delete nuxtApp.payload.logs console.groupEnd && console.groupEnd() } diff --git a/packages/nuxt/src/app/plugins/progress.client.ts b/packages/nuxt/src/app/plugins/progress.client.ts index 17c2e7e9b77..673172cb513 100644 --- a/packages/nuxt/src/app/plugins/progress.client.ts +++ b/packages/nuxt/src/app/plugins/progress.client.ts @@ -13,8 +13,8 @@ export default defineNuxtPlugin((nuxtApp) => { el.style.transition = 'width 0.1s, opacity 0.4s' const duration = 3000 const progress = 10000 / Math.floor(duration) - let timeout - let interval + let timeout: ReturnType | undefined + let interval: ReturnType | undefined nuxtApp.hook('page:start', () => { if (timeout) { return } timeout = setTimeout(() => { @@ -30,9 +30,9 @@ export default defineNuxtPlugin((nuxtApp) => { }) nuxtApp.hook('page:finish', () => { timeout && clearTimeout(timeout) - timeout = null + timeout = undefined interval && clearInterval(interval) - interval = null + interval = undefined el.style.width = '100%' el.style.opacity = '0%' setTimeout(() => { diff --git a/packages/nuxt/src/app/plugins/router.ts b/packages/nuxt/src/app/plugins/router.ts index bde980db0c7..2d319a4e8a7 100644 --- a/packages/nuxt/src/app/plugins/router.ts +++ b/packages/nuxt/src/app/plugins/router.ts @@ -90,8 +90,9 @@ interface Router { export default defineNuxtPlugin<{ route: Route, router: Router }>((nuxtApp) => { const initialURL = process.client ? withoutBase(window.location.pathname, useRuntimeConfig().app.baseURL) + window.location.search + window.location.hash - : nuxtApp.ssrContext.url - const routes = [] + : nuxtApp.ssrContext!.url + + const routes: Route[] = [] const hooks: { [key in keyof RouterHooks]: RouterHooks[key][] } = { 'navigate:before': [], @@ -194,7 +195,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>((nuxtApp) => { const route = router.resolve(props.to) return props.custom ? slots.default?.({ href: props.to, navigate, route }) - : h('a', { href: props.to, onClick: (e) => { e.preventDefault(); return navigate() } }, slots) + : h('a', { href: props.to, onClick: (e: MouseEvent) => { e.preventDefault(); return navigate() } }, slots) } } }) diff --git a/packages/nuxt/tsconfig.json b/packages/nuxt/tsconfig.json new file mode 100644 index 00000000000..86aa9b17067 --- /dev/null +++ b/packages/nuxt/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "strict": true, + "noImplicitAny": true + }, + "include": [ + "./**/*.ts" + ] +} From cb73f4d4fd241514e2efe13dd59cf2d29c2f0153 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 5 Aug 2022 00:13:44 +0800 Subject: [PATCH 02/15] chore: types --- .../nuxt/src/core/runtime/nitro/renderer.ts | 32 +++++++++++-------- packages/nuxt/tsconfig.json | 3 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index 7f157c76bf8..e9979711508 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -1,4 +1,4 @@ -import { createRenderer } from 'vue-bundle-renderer' +import { ClientManifest, createRenderer, ResourceMeta } from 'vue-bundle-renderer' import { eventHandler, useQuery } from 'h3' import devalue from '@nuxt/devalue' import { renderToString as _renderToString } from 'vue/server-renderer' @@ -11,6 +11,8 @@ import { buildAssetsURL } from '#paths' export type NuxtSSRContext = NuxtApp['ssrContext'] +type ArgumentType = T extends (...args: infer U) => any ? U : never + export interface NuxtRenderContext { ssrContext: NuxtSSRContext html: { @@ -33,7 +35,7 @@ export interface NuxtRenderResponse { // @ts-ignore const getClientManifest = () => import('#build/dist/server/client.manifest.mjs') .then(r => r.default || r) - .then(r => typeof r === 'function' ? r() : r) + .then(r => typeof r === 'function' ? r() : r) as Promise // @ts-ignore const getServerEntry = () => import('#build/dist/server/server.mjs').then(r => r.default || r) @@ -55,7 +57,7 @@ const getSSRRenderer = lazyCachedFunction(async () => { publicPath: buildAssetsURL() }) - async function renderToString (input, context) { + async function renderToString (input: ArgumentType[0], context: ArgumentType[1]) { const html = await _renderToString(input, context) // In development with vite-node, the manifest is on-demand and will be available after rendering if (process.dev && process.env.NUXT_VITE_NODE_OPTIONS) { @@ -72,21 +74,23 @@ const getSPARenderer = lazyCachedFunction(async () => { const clientManifest = await getClientManifest() const renderToString = (ssrContext: NuxtSSRContext) => { const config = useRuntimeConfig() - ssrContext.payload = { + ssrContext!.payload = { serverRendered: false, config: { public: config.public, app: config.app - } + }, + data: {}, + state: {} } - let entryFiles = Object.values(clientManifest).filter((fileValue: any) => fileValue.isEntry) + let entryFiles = Object.values(clientManifest).filter(fileValue => fileValue.isEntry) if ('all' in clientManifest && 'initial' in clientManifest) { // Upgrade legacy manifest (also see normalizeClientManifest in vue-bundle-renderer) // https://github.com/nuxt-contrib/vue-bundle-renderer/issues/12 - entryFiles = clientManifest.initial.map(file => + entryFiles = (clientManifest.initial as any as string[]).map(file => // Webpack manifest fix with SPA renderer - file.endsWith('css') ? { css: file } : { file } + (file.endsWith('css') ? { css: file } : { file }) as ResourceMeta ) } @@ -127,8 +131,8 @@ export default eventHandler(async (event) => { runtimeConfig: useRuntimeConfig(), noSSR: !!event.req.headers['x-nuxt-no-ssr'], error: ssrError, - nuxt: undefined, /* NuxtApp */ - payload: undefined + nuxt: undefined!, /* NuxtApp */ + payload: undefined! } // Render app @@ -159,7 +163,7 @@ export default eventHandler(async (event) => { _rendered.renderStyles(), ssrContext.styles ]), - bodyAttrs: normalizeChunks([renderedMeta.bodyAttrs]), + bodyAttrs: normalizeChunks([renderedMeta.bodyAttrs!]), bodyPreprend: normalizeChunks([ renderedMeta.bodyScriptsPrepend, ssrContext.teleports?.body @@ -202,7 +206,7 @@ export default eventHandler(async (event) => { event.res.setHeader(header, response.headers[header]) } event.res.statusCode = response.statusCode - event.res.statusMessage = response.statusMessage + event.res.statusMessage = response.statusMessage! } if (!event.res.writableEnded) { event.res.end(response.body) @@ -219,8 +223,8 @@ function lazyCachedFunction (fn: () => Promise): () => Promise { } } -function normalizeChunks (chunks: string[]) { - return chunks.filter(Boolean).map(i => i.trim()) +function normalizeChunks (chunks: (string | undefined)[]) { + return chunks.filter(Boolean).map(i => i!.trim()) } function joinTags (tags: string[]) { diff --git a/packages/nuxt/tsconfig.json b/packages/nuxt/tsconfig.json index 86aa9b17067..35a35f01926 100644 --- a/packages/nuxt/tsconfig.json +++ b/packages/nuxt/tsconfig.json @@ -5,6 +5,7 @@ "noImplicitAny": true }, "include": [ - "./**/*.ts" + "./src/**/*.ts", + "./test/**/*.ts" ] } From 63969b6cba4143b50a06e376f3bb59ca5976365f Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 5 Aug 2022 00:14:45 +0800 Subject: [PATCH 03/15] chore: syntax --- packages/nuxt/src/app/entry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/app/entry.ts b/packages/nuxt/src/app/entry.ts index 01222c8bf20..262d14ee5d1 100644 --- a/packages/nuxt/src/app/entry.ts +++ b/packages/nuxt/src/app/entry.ts @@ -35,7 +35,7 @@ if (process.server) { await nuxt.hooks.callHook('app:created', vueApp) } catch (err) { await nuxt.callHook('app:error', err) - ssrContext!.error ||= err + ssrContext!.error = ssrContext!.error || err } return vueApp From 12f8af548a19120094b0477877639211df355157 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 5 Aug 2022 00:21:22 +0800 Subject: [PATCH 04/15] chore: update --- packages/nuxt/src/app/components/nuxt-link.ts | 8 ++------ packages/nuxt/src/app/composables/router.ts | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/nuxt/src/app/components/nuxt-link.ts b/packages/nuxt/src/app/components/nuxt-link.ts index dae042c0509..75f8dde8aac 100644 --- a/packages/nuxt/src/app/components/nuxt-link.ts +++ b/packages/nuxt/src/app/components/nuxt-link.ts @@ -176,11 +176,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) { // converts `""` to `null` to prevent the attribute from being added as empty (`rel=""`) : firstNonUndefined(props.rel, options.externalRelAttribute, href ? DEFAULT_EXTERNAL_REL_ATTRIBUTE : '') || null - const navigate = () => { - if (href) { - navigateTo(href, { replace: props.replace }) - } - } + const navigate = () => navigateTo(href, { replace: props.replace }) // https://router.vuejs.org/api/#custom if (props.custom) { @@ -190,7 +186,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) { return slots.default({ href, navigate, - route: href ? router.resolve(href) : undefined, + route: router.resolve(href!), rel, target, isActive: false, diff --git a/packages/nuxt/src/app/composables/router.ts b/packages/nuxt/src/app/composables/router.ts index ff35ba07476..ee7661a4cf8 100644 --- a/packages/nuxt/src/app/composables/router.ts +++ b/packages/nuxt/src/app/composables/router.ts @@ -61,7 +61,7 @@ export interface NavigateToOptions { redirectCode?: number } -export const navigateTo = (to: RouteLocationRaw, options: NavigateToOptions = {}): Promise | RouteLocationRaw => { +export const navigateTo = (to: RouteLocationRaw | undefined | null, options: NavigateToOptions = {}): Promise | RouteLocationRaw => { if (!to) { to = '/' } From 9f6bea3d7e535bd6de52c651b2ca191cd6ef827f Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 5 Aug 2022 00:25:38 +0800 Subject: [PATCH 05/15] chore: types --- packages/nuxt/src/core/nuxt.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts index 47a10cd16d4..b04b0227a2a 100644 --- a/packages/nuxt/src/core/nuxt.ts +++ b/packages/nuxt/src/core/nuxt.ts @@ -81,7 +81,7 @@ async function initNuxt (nuxt: Nuxt) { // Transpile layers within node_modules nuxt.options.build.transpile.push( - ...nuxt.options._layers.filter(i => i.cwd && i.cwd.includes('node_modules')).map(i => i.cwd) + ...nuxt.options._layers.filter(i => i.cwd && i.cwd.includes('node_modules')).map(i => i.cwd as string) ) // Init user modules @@ -95,7 +95,7 @@ async function initNuxt (nuxt: Nuxt) { // Add addComponent({ name: 'NuxtWelcome', - filePath: tryResolveModule('@nuxt/ui-templates/templates/welcome.vue') + filePath: tryResolveModule('@nuxt/ui-templates/templates/welcome.vue')! }) addComponent({ @@ -165,7 +165,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise { transform: { include: options._layers .filter(i => i.cwd && i.cwd.includes('node_modules')) - .map(i => new RegExp(`(^|\\/)${escapeRE(i.cwd.split('node_modules/').pop())}(\\/|$)(?!node_modules\\/)`)) + .map(i => new RegExp(`(^|\\/)${escapeRE(i.cwd!.split('node_modules/').pop()!)}(\\/|$)(?!node_modules\\/)`)) } }]) options.modulesDir.push(resolve(pkgDir, 'node_modules')) From 01abaa6684d28a8c7dae208f0bd452fb5ee981f1 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 5 Aug 2022 00:43:15 +0800 Subject: [PATCH 06/15] chore: types --- packages/nuxt/src/core/app.ts | 12 ++++---- packages/nuxt/src/core/builder.ts | 8 +++--- packages/nuxt/src/core/modules.ts | 1 + packages/nuxt/src/core/nitro.ts | 10 +++---- packages/nuxt/src/core/templates.ts | 44 ++++++++++++++--------------- packages/schema/src/types/nuxt.ts | 14 ++++----- 6 files changed, 45 insertions(+), 44 deletions(-) diff --git a/packages/nuxt/src/core/app.ts b/packages/nuxt/src/core/app.ts index 1ae5080960d..6705b6eceb1 100644 --- a/packages/nuxt/src/core/app.ts +++ b/packages/nuxt/src/core/app.ts @@ -1,7 +1,7 @@ import { promises as fsp } from 'node:fs' import { dirname, resolve } from 'pathe' import defu from 'defu' -import type { Nuxt, NuxtApp, NuxtPlugin } from '@nuxt/schema' +import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate } from '@nuxt/schema' import { findPath, resolveFiles, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils, tryResolveModule, resolvePath, resolveAlias } from '@nuxt/kit' import * as defaultTemplates from './templates' @@ -13,7 +13,7 @@ export function createApp (nuxt: Nuxt, options: Partial = {}): NuxtApp extensions: nuxt.options.extensions, plugins: [], templates: [] - } as NuxtApp) + } as unknown as NuxtApp) as NuxtApp } export async function generateApp (nuxt: Nuxt, app: NuxtApp) { @@ -21,7 +21,7 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp) { await resolveApp(nuxt, app) // User templates from options.build.templates - app.templates = Object.values(defaultTemplates).concat(nuxt.options.build.templates) + app.templates = Object.values(defaultTemplates).concat(nuxt.options.build.templates) as NuxtTemplate[] // Extend templates with hook await nuxt.callHook('app:templates', app) @@ -34,10 +34,10 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp) { await Promise.all(app.templates.map(async (template) => { const contents = await compileTemplate(template, templateContext) - const fullPath = template.dst || resolve(nuxt.options.buildDir, template.filename) + const fullPath = template.dst || resolve(nuxt.options.buildDir, template.filename!) nuxt.vfs[fullPath] = contents - const aliasPath = '#build/' + template.filename.replace(/\.\w+$/, '') + const aliasPath = '#build/' + template.filename!.replace(/\.\w+$/, '') nuxt.vfs[aliasPath] = contents // In case a non-normalized absolute path is called for on Windows @@ -58,7 +58,7 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { // Resolve main (app.vue) if (!app.mainComponent) { app.mainComponent = await findPath( - nuxt.options._layers.flatMap(layer => [`${layer.config.srcDir}/App`, `${layer.config.srcDir}/app`]) + nuxt.options._layers.flatMap(layer => [`${layer.config!.srcDir}/App`, `${layer.config!.srcDir}/app`]) ) } if (!app.mainComponent) { diff --git a/packages/nuxt/src/core/builder.ts b/packages/nuxt/src/core/builder.ts index d110c6753f5..09af04bee08 100644 --- a/packages/nuxt/src/core/builder.ts +++ b/packages/nuxt/src/core/builder.ts @@ -15,10 +15,10 @@ export async function build (nuxt: Nuxt) { nuxt.hook('builder:watch', async (event, path) => { if (event !== 'change' && /^(app\.|error\.|plugins\/|middleware\/|layouts\/)/i.test(path)) { if (path.startsWith('app')) { - app.mainComponent = null + app.mainComponent = undefined } if (path.startsWith('error')) { - app.errorComponent = null + app.errorComponent = undefined } await generateApp() } @@ -38,7 +38,7 @@ export async function build (nuxt: Nuxt) { } function watch (nuxt: Nuxt) { - const watcher = chokidar.watch(nuxt.options._layers.map(i => i.config.srcDir), { + const watcher = chokidar.watch(nuxt.options._layers.map(i => i.config?.srcDir as string).filter(Boolean), { ...nuxt.options.watchers.chokidar, cwd: nuxt.options.srcDir, ignoreInitial: true, @@ -61,7 +61,7 @@ async function bundle (nuxt: Nuxt) { : nuxt.options.builder return bundle(nuxt) - } catch (error) { + } catch (error: any) { await nuxt.callHook('build:error', error) if (error.toString().includes('Cannot find module \'@nuxt/webpack-builder\'')) { diff --git a/packages/nuxt/src/core/modules.ts b/packages/nuxt/src/core/modules.ts index 94f242541ef..5041095d4a2 100644 --- a/packages/nuxt/src/core/modules.ts +++ b/packages/nuxt/src/core/modules.ts @@ -20,6 +20,7 @@ export const addModuleTranspiles = (opts: AddModuleTranspilesOptions = {}) => { // Try to sanitize modules to better match imports nuxt.options.build.transpile = nuxt.options.build.transpile.map(m => typeof m === 'string' ? m.split('node_modules/').pop() : m) + .filter((x: T | undefined): x is T => !!x) function isTranspilePresent (mod: string) { return nuxt.options.build.transpile.some(t => !(t instanceof Function) && (t instanceof RegExp ? t.test(mod) : new RegExp(t).test(mod))) diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index 3a7b3b24416..145caa13ae4 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -22,7 +22,7 @@ export async function initNitro (nuxt: Nuxt) { dev: nuxt.options.dev, preset: nuxt.options.dev ? 'nitro-dev' : undefined, buildDir: nuxt.options.buildDir, - scanDirs: nuxt.options._layers.map(layer => join(layer.config.srcDir, 'server')), + scanDirs: nuxt.options._layers.map(layer => join(layer.config!.srcDir!, 'server')), renderer: resolve(distDir, 'core/runtime/nitro/renderer'), errorHandler: resolve(distDir, 'core/runtime/nitro/error'), nodeModulesDirs: nuxt.options.modulesDir, @@ -43,13 +43,13 @@ export async function initNitro (nuxt: Nuxt) { publicAssets: [ { dir: resolve(nuxt.options.buildDir, 'dist/client') }, ...nuxt.options._layers - .map(layer => join(layer.config.srcDir, layer.config.dir?.public || 'public')) + .map(layer => join(layer.config!.srcDir!, layer.config!.dir?.public || 'public')) .filter(dir => existsSync(dir)) .map(dir => ({ dir })) ], prerender: { crawlLinks: nuxt.options._generate ? nuxt.options.generate.crawler : false, - routes: [] + routes: ([] as string[]) .concat(nuxt.options._generate ? ['/', ...nuxt.options.generate.routes] : []) .concat(nuxt.options.ssr === false ? ['/', '/200.html', '/404.html'] : []) }, @@ -101,11 +101,11 @@ export async function initNitro (nuxt: Nuxt) { // Add fallback server for `ssr: false` if (!nuxt.options.ssr) { - nitroConfig.virtual['#build/dist/server/server.mjs'] = 'export default () => {}' + nitroConfig.virtual!['#build/dist/server/server.mjs'] = 'export default () => {}' } // Register nuxt protection patterns - nitroConfig.rollupConfig.plugins.push(ImportProtectionPlugin.rollup({ + nitroConfig.rollupConfig!.plugins!.push(ImportProtectionPlugin.rollup({ rootDir: nuxt.options.rootDir, patterns: [ ...['#app', /^#build(\/|$)/] diff --git a/packages/nuxt/src/core/templates.ts b/packages/nuxt/src/core/templates.ts index 57299a0a6f0..a47ed17fe7b 100644 --- a/packages/nuxt/src/core/templates.ts +++ b/packages/nuxt/src/core/templates.ts @@ -11,7 +11,7 @@ export interface TemplateContext { app: NuxtApp } -export const vueShim = { +export const vueShim: NuxtTemplate = { filename: 'types/vue-shim.d.ts', getContents: () => [ @@ -24,29 +24,29 @@ export const vueShim = { } // TODO: Use an alias -export const appComponentTemplate = { +export const appComponentTemplate: NuxtTemplate = { filename: 'app-component.mjs', - getContents: (ctx: TemplateContext) => genExport(ctx.app.mainComponent, ['default']) + getContents: ctx => genExport(ctx.app.mainComponent!, ['default']) } // TODO: Use an alias -export const rootComponentTemplate = { +export const rootComponentTemplate: NuxtTemplate = { filename: 'root-component.mjs', - getContents: (ctx: TemplateContext) => genExport(ctx.app.rootComponent, ['default']) + getContents: ctx => genExport(ctx.app.rootComponent!, ['default']) } // TODO: Use an alias -export const errorComponentTemplate = { +export const errorComponentTemplate: NuxtTemplate = { filename: 'error-component.mjs', - getContents: (ctx: TemplateContext) => genExport(ctx.app.errorComponent, ['default']) + getContents: ctx => genExport(ctx.app.errorComponent!, ['default']) } -export const cssTemplate = { +export const cssTemplate: NuxtTemplate = { filename: 'css.mjs', - getContents: (ctx: TemplateContext) => ctx.nuxt.options.css.map(i => genImport(i)).join('\n') + getContents: ctx => ctx.nuxt.options.css.map(i => genImport(i)).join('\n') } -export const clientPluginTemplate = { +export const clientPluginTemplate: NuxtTemplate = { filename: 'plugins/client.mjs', - getContents (ctx: TemplateContext) { + getContents (ctx) { const clientPlugins = ctx.app.plugins.filter(p => !p.mode || p.mode !== 'server') const rootDir = ctx.nuxt.options.rootDir const { imports, exports } = templateUtils.importSources(clientPlugins.map(p => p.src), rootDir) @@ -57,9 +57,9 @@ export const clientPluginTemplate = { } } -export const serverPluginTemplate = { +export const serverPluginTemplate: NuxtTemplate = { filename: 'plugins/server.mjs', - getContents (ctx: TemplateContext) { + getContents (ctx) { const serverPlugins = ctx.app.plugins.filter(p => !p.mode || p.mode !== 'client') const rootDir = ctx.nuxt.options.rootDir const { imports, exports } = templateUtils.importSources(serverPlugins.map(p => p.src), rootDir) @@ -74,9 +74,9 @@ export const serverPluginTemplate = { } } -export const pluginsDeclaration = { +export const pluginsDeclaration: NuxtTemplate = { filename: 'types/plugins.d.ts', - getContents: (ctx: TemplateContext) => { + getContents: (ctx) => { const EXTENSION_RE = new RegExp(`(?<=\\w)(${ctx.nuxt.options.extensions.map(e => escapeRE(e)).join('|')})$`, 'g') const tsImports = ctx.app.plugins.map(p => (isAbsolute(p.src) ? relative(join(ctx.nuxt.options.buildDir, 'types'), p.src) : p.src).replace(EXTENSION_RE, '')) @@ -103,9 +103,9 @@ export { } } const adHocModules = ['router', 'pages', 'auto-imports', 'meta', 'components'] -export const schemaTemplate = { +export const schemaTemplate: NuxtTemplate = { filename: 'types/schema.d.ts', - getContents: ({ nuxt }: TemplateContext) => { + getContents: ({ nuxt }) => { const moduleInfo = nuxt.options._installedModules.map(m => ({ ...m.meta || {}, importName: m.entryPath || m.meta?.name @@ -141,9 +141,9 @@ export const schemaTemplate = { } // Add layouts template -export const layoutTemplate: NuxtTemplate = { +export const layoutTemplate: NuxtTemplate = { filename: 'layouts.mjs', - getContents ({ app }: TemplateContext) { + getContents ({ app }) { const layoutsObject = genObjectFromRawEntries(Object.values(app.layouts).map(({ name, file }) => { return [name, `defineAsyncComponent(${genDynamicImport(file)})`] })) @@ -155,9 +155,9 @@ export const layoutTemplate: NuxtTemplate = { } // Add middleware template -export const middlewareTemplate: NuxtTemplate = { +export const middlewareTemplate: NuxtTemplate = { filename: 'middleware.mjs', - getContents ({ app }: TemplateContext) { + getContents ({ app }) { const globalMiddleware = app.middleware.filter(mw => mw.global) const namedMiddleware = app.middleware.filter(mw => !mw.global) const namedMiddlewareObject = genObjectFromRawEntries(namedMiddleware.map(mw => [mw.name, genDynamicImport(mw.path)])) @@ -176,7 +176,7 @@ export const useRuntimeConfig = () => window?.__NUXT__?.config || {} ` } -export const publicPathTemplate: NuxtTemplate = { +export const publicPathTemplate: NuxtTemplate = { filename: 'paths.mjs', getContents ({ nuxt }) { return [ diff --git a/packages/schema/src/types/nuxt.ts b/packages/schema/src/types/nuxt.ts index b5c21a067ca..99d9c877cd2 100644 --- a/packages/schema/src/types/nuxt.ts +++ b/packages/schema/src/types/nuxt.ts @@ -24,7 +24,7 @@ export interface Nuxt { vfs: Record } -export interface NuxtTemplate { +export interface NuxtTemplate> { /** @deprecated filename */ fileName?: string /** @deprecated whether template is custom or a nuxt core template */ @@ -34,11 +34,11 @@ export interface NuxtTemplate { /** The target filename once the template is copied into the Nuxt buildDir */ filename?: string /** An options object that will be accessible within the template via `<% options %>` */ - options?: Record + options?: Options /** The resolved path to the source file to be template */ src?: string - /** Provided compile option intead of src */ - getContents?: (data: Record) => string | Promise + /** Provided compile option instead of src */ + getContents?: (options: Options) => string | Promise /** Write to filesystem */ write?: boolean } @@ -51,9 +51,9 @@ export interface NuxtPlugin { } export interface NuxtApp { - mainComponent?: string - rootComponent?: string - errorComponent?: string + mainComponent?: string | null + rootComponent?: string | null + errorComponent?: string | null dir: string extensions: string[] plugins: NuxtPlugin[] From b92f4a7a379255650fc1c28696607d89becf6634 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 10 Aug 2022 17:23:21 +0800 Subject: [PATCH 07/15] chore: update --- packages/nuxt/src/app/components/nuxt-link.ts | 4 ++-- packages/nuxt/src/app/entry.ts | 6 +++--- packages/nuxt/src/app/plugins/router.ts | 3 +-- packages/nuxt/src/core/runtime/nitro/error.ts | 2 +- .../nuxt/src/core/runtime/nitro/renderer.ts | 19 +++++++++---------- packages/nuxt/test/nuxt-link.test.ts | 8 ++++---- test/fixtures/basic/types.ts | 2 +- tsconfig.json | 7 +++++++ 8 files changed, 28 insertions(+), 23 deletions(-) diff --git a/packages/nuxt/src/app/components/nuxt-link.ts b/packages/nuxt/src/app/components/nuxt-link.ts index 75f8dde8aac..b6b8c2ed577 100644 --- a/packages/nuxt/src/app/components/nuxt-link.ts +++ b/packages/nuxt/src/app/components/nuxt-link.ts @@ -24,8 +24,8 @@ export type NuxtLinkProps = { custom?: boolean // Attributes - target?: string - rel?: string + target?: string | null + rel?: string | null noRel?: boolean // Styling diff --git a/packages/nuxt/src/app/entry.ts b/packages/nuxt/src/app/entry.ts index 69478ffb37f..f612d4ffb78 100644 --- a/packages/nuxt/src/app/entry.ts +++ b/packages/nuxt/src/app/entry.ts @@ -35,7 +35,7 @@ if (process.server) { await nuxt.hooks.callHook('app:created', vueApp) } catch (err) { await nuxt.callHook('app:error', err) - nuxt.payload.error = nuxt.payload.error || err + nuxt.payload.error = (nuxt.payload.error || err) as any } return vueApp @@ -66,7 +66,7 @@ if (process.client) { await applyPlugins(nuxt, plugins) } catch (err) { await nuxt.callHook('app:error', err) - nuxt.payload.error = nuxt.payload.error || err + nuxt.payload.error = (nuxt.payload.error || err) as any } try { @@ -77,7 +77,7 @@ if (process.client) { await nextTick() } catch (err) { await nuxt.callHook('app:error', err) - nuxt.payload.error = nuxt.payload.error || err + nuxt.payload.error = (nuxt.payload.error || err) as any } } diff --git a/packages/nuxt/src/app/plugins/router.ts b/packages/nuxt/src/app/plugins/router.ts index 2d319a4e8a7..59cf70fc6a2 100644 --- a/packages/nuxt/src/app/plugins/router.ts +++ b/packages/nuxt/src/app/plugins/router.ts @@ -1,9 +1,8 @@ import { reactive, h } from 'vue' import { parseURL, parseQuery, withoutBase, isEqual, joinURL } from 'ufo' import { createError } from 'h3' -import { defineNuxtPlugin } from '..' +import { defineNuxtPlugin, clearError, navigateTo, showError, useRuntimeConfig } from '..' import { callWithNuxt } from '../nuxt' -import { clearError, navigateTo, showError, useRuntimeConfig } from '#app' // @ts-ignore import { globalMiddleware } from '#build/middleware' diff --git a/packages/nuxt/src/core/runtime/nitro/error.ts b/packages/nuxt/src/core/runtime/nitro/error.ts index d0579af7246..2ed524681a5 100644 --- a/packages/nuxt/src/core/runtime/nitro/error.ts +++ b/packages/nuxt/src/core/runtime/nitro/error.ts @@ -1,8 +1,8 @@ import { withQuery } from 'ufo' import type { NitroErrorHandler } from 'nitropack' // @ts-ignore TODO +import type { NuxtApp } from '@nuxt/schema' import { normalizeError, isJsonRequest } from '#internal/nitro/utils' -import { NuxtApp } from '#app' export default async function errorhandler (_error, event) { // Parse and normalize error diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index fc04c92795b..2467024ef9f 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -1,13 +1,12 @@ -import { ClientManifest, createRenderer, ResourceMeta } from 'vue-bundle-renderer/runtime' -import type { RenderHandler, RenderResponse } from 'nitropack' +import { createRenderer } from 'vue-bundle-renderer/runtime' +import type { RenderResponse } from 'nitropack' import type { Manifest } from 'vite' -import { CompatibilityEvent, getQuery } from 'h3' +import { getQuery } from 'h3' import devalue from '@nuxt/devalue' import { renderToString as _renderToString } from 'vue/server-renderer' -import type { NuxtApp } from '#app' - -// @ts-ignore import { useRuntimeConfig, useNitroApp, defineRenderHandler as _defineRenderHandler } from '#internal/nitro' +import type { NuxtApp } from '@nuxt/schema' + // @ts-ignore import { buildAssetsURL } from '#paths' @@ -94,14 +93,14 @@ const getSPARenderer = lazyCachedFunction(async () => { data: {}, state: {} } - ssrContext.renderMeta = ssrContext.renderMeta ?? (() => ({})) + ssrContext!.renderMeta = ssrContext!.renderMeta ?? (() => ({})) return Promise.resolve(result) } return { renderToString } }) -export default defineRenderHandler(async (event) => { +export default _defineRenderHandler(async (event) => { // Whether we're rendering an error page const ssrError = event.req.url?.startsWith('/__nuxt_error') ? getQuery(event) as Exclude : null const url = ssrError?.url as string || event.req.url! @@ -115,8 +114,8 @@ export default defineRenderHandler(async (event) => { runtimeConfig: useRuntimeConfig(), noSSR: !!event.req.headers['x-nuxt-no-ssr'], error: !!ssrError, - nuxt: undefined, /* NuxtApp */ - payload: ssrError ? { error: ssrError } : undefined + nuxt: undefined!, /* NuxtApp */ + payload: ssrError ? { error: ssrError } as NuxtSSRContext['payload'] : undefined! } // Render app diff --git a/packages/nuxt/test/nuxt-link.test.ts b/packages/nuxt/test/nuxt-link.test.ts index 5138dea8985..0be3bf43406 100644 --- a/packages/nuxt/test/nuxt-link.test.ts +++ b/packages/nuxt/test/nuxt-link.test.ts @@ -8,7 +8,7 @@ vi.mock('vue', async () => { return { ...vue, resolveComponent: (name: string) => name, - h: (...args) => args + h: (...args: any[]) => args } }) @@ -17,7 +17,7 @@ vi.mock('#app', () => ({ useRouter: () => ({ resolve: ({ to }: { to: string }) => ({ href: to }) }) })) -// Helpers for test lisibility +// Helpers for test visibility const EXTERNAL = 'a' const INTERNAL = 'RouterLink' @@ -44,7 +44,7 @@ describe('nuxt-link:to', () => { }) it('renders link with `to` prop and warns about `href` prop conflict', () => { - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(vi.fn()) + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(vi.fn() as any) expect(nuxtLink({ to: '/to', href: '/href' }).props.to).toBe('/to') // TODO: Uncomment when `dev` mode for tests is available @@ -136,7 +136,7 @@ describe('nuxt-link:propsOrAttributes', () => { }) it('honors `noRel` prop and warns about `rel` prop conflict', () => { - const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(vi.fn()) + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(vi.fn() as any) expect(nuxtLink({ to: 'https://nuxtjs.org', noRel: true, rel: 'foo' }).props.rel).toBe(null) // TODO: Uncomment when `dev` mode for tests is available diff --git a/test/fixtures/basic/types.ts b/test/fixtures/basic/types.ts index 0a12b4d9fe6..7e896f81c06 100644 --- a/test/fixtures/basic/types.ts +++ b/test/fixtures/basic/types.ts @@ -4,8 +4,8 @@ import type { Ref } from 'vue' import { NavigationFailure, RouteLocationNormalizedLoaded, RouteLocationRaw, useRouter as vueUseRouter } from 'vue-router' import { defineNuxtConfig } from '~~/../../../packages/nuxt/src' -import { useRouter } from '#imports' import { isVue3 } from '#app' +import { useRouter } from '#imports' interface TestResponse { message: string } diff --git a/tsconfig.json b/tsconfig.json index 0022fea8d9c..ffabca27f6c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ "moduleResolution": "Node", "strict": false, "allowJs": true, + "noEmit": true, "noUnusedLocals": true, "resolveJsonModule": true, "types": [ @@ -23,6 +24,12 @@ "#head": [ "./packages/nuxt/src/head/runtime/index" ], + "#internal/nitro": [ + "./node_modules/nitropack/dist/runtime" + ], + "#internal/nitro/utils": [ + "./node_modules/nitropack/dist/runtime/utils" + ] } }, "exclude": [ From 628321eddbaeb7ea00d392d0c61dbf4403057801 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 10 Aug 2022 19:33:54 +0800 Subject: [PATCH 08/15] chore: update --- packages/nuxt/src/app/nuxt.ts | 3 +-- packages/nuxt/src/core/app.ts | 26 ++++++++++++------- packages/nuxt/src/core/runtime/nitro/error.ts | 4 +-- .../nuxt/src/core/runtime/nitro/renderer.ts | 17 ++++++++---- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts index e8541657698..491e728e03a 100644 --- a/packages/nuxt/src/app/nuxt.ts +++ b/packages/nuxt/src/app/nuxt.ts @@ -135,10 +135,9 @@ export function createNuxtApp (options: CreateOptions) { } // Expose to server renderer to create window.__NUXT__ nuxtApp.ssrContext = nuxtApp.ssrContext || {} as any - if (nuxtApp.ssrContext.payload) { + if (nuxtApp.ssrContext?.payload) { Object.assign(nuxtApp.payload, nuxtApp.ssrContext.payload) } - nuxtApp.ssrContext.payload = nuxtApp.payload // Expose client runtime-config to the payload nuxtApp.payload.config = { diff --git a/packages/nuxt/src/core/app.ts b/packages/nuxt/src/core/app.ts index 1f6ce4765aa..51d703dfa96 100644 --- a/packages/nuxt/src/core/app.ts +++ b/packages/nuxt/src/core/app.ts @@ -1,7 +1,7 @@ import { promises as fsp } from 'node:fs' import { dirname, resolve } from 'pathe' import defu from 'defu' -import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate } from '@nuxt/schema' +import type { Nuxt, NuxtApp, NuxtConfig, NuxtPlugin, NuxtTemplate } from '@nuxt/schema' import { findPath, resolveFiles, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils, tryResolveModule, resolvePath, resolveAlias } from '@nuxt/kit' import * as defaultTemplates from './templates' @@ -16,6 +16,10 @@ export function createApp (nuxt: Nuxt, options: Partial = {}): NuxtApp } as unknown as NuxtApp) as NuxtApp } +function getLayerConfigs (nuxt: Nuxt) { + return nuxt.options._layers.map(layer => layer.config).filter(Boolean) as NuxtConfig[] +} + export async function generateApp (nuxt: Nuxt, app: NuxtApp) { // Resolve app await resolveApp(nuxt, app) @@ -77,7 +81,8 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { // Resolve layouts/ from all config layers app.layouts = {} - for (const config of nuxt.options._layers.map(layer => layer.config)) { + for (const config of getLayerConfigs(nuxt)) { + if (!config.srcDir) { continue } const layoutFiles = await resolveFiles(config.srcDir, `${config.dir?.layouts || 'layouts'}/*{${nuxt.options.extensions.join(',')}}`) for (const file of layoutFiles) { const name = getNameFromPath(file) @@ -87,7 +92,8 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { // Resolve middleware/ from all config layers app.middleware = [] - for (const config of nuxt.options._layers.map(layer => layer.config)) { + for (const config of getLayerConfigs(nuxt)) { + if (!config.srcDir) { continue } const middlewareFiles = await resolveFiles(config.srcDir, `${config.dir?.middleware || 'middleware'}/*{${nuxt.options.extensions.join(',')}}`) app.middleware.push(...middlewareFiles.map((file) => { const name = getNameFromPath(file) @@ -99,16 +105,16 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { app.plugins = [ ...nuxt.options.plugins.map(normalizePlugin) ] - for (const config of nuxt.options._layers.map(layer => layer.config)) { - if (config) { - app.plugins.push(...[ - ...(config.plugins || []), - ...await resolveFiles(config.srcDir, [ + for (const config of getLayerConfigs(nuxt)) { + app.plugins.push(...[ + ...(config.plugins || []), + ...config.srcDir + ? await resolveFiles(config.srcDir, [ 'plugins/*.{ts,js,mjs,cjs,mts,cts}', 'plugins/*/index.*{ts,js,mjs,cjs,mts,cts}' ]) - ].map(plugin => normalizePlugin(plugin as NuxtPlugin))) - } + : [] + ].map(plugin => normalizePlugin(plugin as NuxtPlugin))) } // Normalize and de-duplicate plugins and middleware diff --git a/packages/nuxt/src/core/runtime/nitro/error.ts b/packages/nuxt/src/core/runtime/nitro/error.ts index 2ed524681a5..b9a6ba1dc68 100644 --- a/packages/nuxt/src/core/runtime/nitro/error.ts +++ b/packages/nuxt/src/core/runtime/nitro/error.ts @@ -1,7 +1,5 @@ import { withQuery } from 'ufo' import type { NitroErrorHandler } from 'nitropack' -// @ts-ignore TODO -import type { NuxtApp } from '@nuxt/schema' import { normalizeError, isJsonRequest } from '#internal/nitro/utils' export default async function errorhandler (_error, event) { @@ -9,7 +7,7 @@ export default async function errorhandler (_error, event) { const { stack, statusCode, statusMessage, message } = normalizeError(_error) // Create an error object - const errorObject: Exclude = { + const errorObject = { url: event.req.url, statusCode, statusMessage, diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index 2467024ef9f..36f05ee0a1f 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -4,13 +4,16 @@ import type { Manifest } from 'vite' import { getQuery } from 'h3' import devalue from '@nuxt/devalue' import { renderToString as _renderToString } from 'vue/server-renderer' +import type { NuxtApp } from '#app' import { useRuntimeConfig, useNitroApp, defineRenderHandler as _defineRenderHandler } from '#internal/nitro' -import type { NuxtApp } from '@nuxt/schema' // @ts-ignore import { buildAssetsURL } from '#paths' -export type NuxtSSRContext = NuxtApp['ssrContext'] +type ArgumentType = T extends (...args: infer U) => any ? U : never +type Required = T extends undefined ? never : T + +export type NuxtSSRContext = Required export interface NuxtRenderContext { ssrContext: NuxtSSRContext @@ -31,6 +34,8 @@ export interface NuxtRenderResponse { headers: Record } +interface ClientManifest {} + // @ts-ignore const getClientManifest: () => Promise = () => import('#build/dist/server/client.manifest.mjs') .then(r => r.default || r) @@ -111,7 +116,7 @@ export default _defineRenderHandler(async (event) => { event, req: event.req, res: event.res, - runtimeConfig: useRuntimeConfig(), + runtimeConfig: useRuntimeConfig() as NuxtSSRContext['runtimeConfig'], noSSR: !!event.req.headers['x-nuxt-no-ssr'], error: !!ssrError, nuxt: undefined!, /* NuxtApp */ @@ -121,12 +126,14 @@ export default _defineRenderHandler(async (event) => { // Render app const renderer = (process.env.NUXT_NO_SSR || ssrContext.noSSR) ? await getSPARenderer() : await getSSRRenderer() const _rendered = await renderer.renderToString(ssrContext).catch((err) => { - if (!ssrError) { throw err } + if (!ssrError) { + throw err + } }) // Handle errors if (!_rendered) { - return + return undefined! } if (ssrContext.payload?.error && !ssrError) { throw ssrContext.payload.error From 4eae522d91ca0ba1663fbcb908252170b563360f Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Wed, 10 Aug 2022 19:38:30 +0800 Subject: [PATCH 09/15] chore: update --- packages/nuxt/src/app/nuxt.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts index 491e728e03a..228782bcd4b 100644 --- a/packages/nuxt/src/app/nuxt.ts +++ b/packages/nuxt/src/app/nuxt.ts @@ -135,9 +135,10 @@ export function createNuxtApp (options: CreateOptions) { } // Expose to server renderer to create window.__NUXT__ nuxtApp.ssrContext = nuxtApp.ssrContext || {} as any - if (nuxtApp.ssrContext?.payload) { - Object.assign(nuxtApp.payload, nuxtApp.ssrContext.payload) + if (nuxtApp.ssrContext!.payload) { + Object.assign(nuxtApp.payload, nuxtApp.ssrContext!.payload) } + nuxtApp.ssrContext!.payload = nuxtApp.payload // Expose client runtime-config to the payload nuxtApp.payload.config = { From b23db485da3f8caf071196065c82be892ab59809 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Thu, 11 Aug 2022 00:03:42 +0800 Subject: [PATCH 10/15] chore: update --- packages/nuxt/src/auto-imports/module.ts | 10 +++++++--- packages/nuxt/src/core/app.ts | 14 +++++--------- packages/nuxt/src/core/nitro.ts | 4 ++-- packages/schema/src/types/config.ts | 6 +++++- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/packages/nuxt/src/auto-imports/module.ts b/packages/nuxt/src/auto-imports/module.ts index b6577363823..289a143c5ed 100644 --- a/packages/nuxt/src/auto-imports/module.ts +++ b/packages/nuxt/src/auto-imports/module.ts @@ -24,7 +24,7 @@ export default defineNuxtModule>({ // Allow modules extending sources await nuxt.callHook('autoImports:sources', options.presets as ImportPresetWithDeprecation[]) - options.presets.forEach((i: ImportPresetWithDeprecation) => { + options.presets?.forEach((i: ImportPresetWithDeprecation | string) => { if (typeof i !== 'string' && i.names && !i.imports) { i.imports = i.names logger.warn('auto-imports: presets.names is deprecated, use presets.imports instead') @@ -45,10 +45,14 @@ export default defineNuxtModule>({ }) // composables/ dirs from all layers - let composablesDirs = [] + let composablesDirs: string[] = [] for (const layer of nuxt.options._layers) { + if (!layer.config.srcDir) { continue } composablesDirs.push(resolve(layer.config.srcDir, 'composables')) for (const dir of (layer.config.autoImports?.dirs ?? [])) { + if (!dir) { + continue + } composablesDirs.push(resolve(layer.config.srcDir, dir)) } } @@ -123,7 +127,7 @@ function addDeclarationTemplates (ctx: Unimport) { // Remove file extension for benefit of TypeScript const stripExtension = (path: string) => path.replace(/\.[a-z]+$/, '') - const resolved = {} + const resolved: Record = {} const r = ({ from }: Import) => { if (resolved[from]) { return resolved[from] diff --git a/packages/nuxt/src/core/app.ts b/packages/nuxt/src/core/app.ts index 51d703dfa96..f07e64ae7a3 100644 --- a/packages/nuxt/src/core/app.ts +++ b/packages/nuxt/src/core/app.ts @@ -1,7 +1,7 @@ import { promises as fsp } from 'node:fs' import { dirname, resolve } from 'pathe' import defu from 'defu' -import type { Nuxt, NuxtApp, NuxtConfig, NuxtPlugin, NuxtTemplate } from '@nuxt/schema' +import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate } from '@nuxt/schema' import { findPath, resolveFiles, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils, tryResolveModule, resolvePath, resolveAlias } from '@nuxt/kit' import * as defaultTemplates from './templates' @@ -16,10 +16,6 @@ export function createApp (nuxt: Nuxt, options: Partial = {}): NuxtApp } as unknown as NuxtApp) as NuxtApp } -function getLayerConfigs (nuxt: Nuxt) { - return nuxt.options._layers.map(layer => layer.config).filter(Boolean) as NuxtConfig[] -} - export async function generateApp (nuxt: Nuxt, app: NuxtApp) { // Resolve app await resolveApp(nuxt, app) @@ -62,7 +58,7 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { // Resolve main (app.vue) if (!app.mainComponent) { app.mainComponent = await findPath( - nuxt.options._layers.flatMap(layer => [`${layer.config!.srcDir}/App`, `${layer.config!.srcDir}/app`]) + nuxt.options._layers.flatMap(layer => [`${layer.config.srcDir}/App`, `${layer.config.srcDir}/app`]) ) } if (!app.mainComponent) { @@ -81,7 +77,7 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { // Resolve layouts/ from all config layers app.layouts = {} - for (const config of getLayerConfigs(nuxt)) { + for (const config of nuxt.options._layers.map(layer => layer.config)) { if (!config.srcDir) { continue } const layoutFiles = await resolveFiles(config.srcDir, `${config.dir?.layouts || 'layouts'}/*{${nuxt.options.extensions.join(',')}}`) for (const file of layoutFiles) { @@ -92,7 +88,7 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { // Resolve middleware/ from all config layers app.middleware = [] - for (const config of getLayerConfigs(nuxt)) { + for (const config of nuxt.options._layers.map(layer => layer.config)) { if (!config.srcDir) { continue } const middlewareFiles = await resolveFiles(config.srcDir, `${config.dir?.middleware || 'middleware'}/*{${nuxt.options.extensions.join(',')}}`) app.middleware.push(...middlewareFiles.map((file) => { @@ -105,7 +101,7 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { app.plugins = [ ...nuxt.options.plugins.map(normalizePlugin) ] - for (const config of getLayerConfigs(nuxt)) { + for (const config of nuxt.options._layers.map(layer => layer.config)) { app.plugins.push(...[ ...(config.plugins || []), ...config.srcDir diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index 145caa13ae4..003ad3f4125 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -22,7 +22,7 @@ export async function initNitro (nuxt: Nuxt) { dev: nuxt.options.dev, preset: nuxt.options.dev ? 'nitro-dev' : undefined, buildDir: nuxt.options.buildDir, - scanDirs: nuxt.options._layers.map(layer => join(layer.config!.srcDir!, 'server')), + scanDirs: nuxt.options._layers.map(layer => layer.config.srcDir).filter(Boolean).map(dir => join(dir!, 'server')), renderer: resolve(distDir, 'core/runtime/nitro/renderer'), errorHandler: resolve(distDir, 'core/runtime/nitro/error'), nodeModulesDirs: nuxt.options.modulesDir, @@ -43,7 +43,7 @@ export async function initNitro (nuxt: Nuxt) { publicAssets: [ { dir: resolve(nuxt.options.buildDir, 'dist/client') }, ...nuxt.options._layers - .map(layer => join(layer.config!.srcDir!, layer.config!.dir?.public || 'public')) + .map(layer => join(layer.config.srcDir!, layer.config.dir?.public || 'public')) .filter(dir => existsSync(dir)) .map(dir => ({ dir })) ], diff --git a/packages/schema/src/types/config.ts b/packages/schema/src/types/config.ts index 3e365c131d7..9bda3ff7e05 100644 --- a/packages/schema/src/types/config.ts +++ b/packages/schema/src/types/config.ts @@ -12,9 +12,13 @@ export interface NuxtConfig extends DeepPartial> { [key: string]: any } +export interface LayerOptions extends ResolvedConfig { + config: NuxtConfig +} + /** Normalized Nuxt options available as `nuxt.options.*` */ export interface NuxtOptions extends ConfigSchema { - _layers: ResolvedConfig[] + _layers: LayerOptions[] } type RuntimeConfigNamespace = Record From b97f6f22b85998ef77528b7bd2e213ba44a8da51 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 12 Aug 2022 19:00:39 +0200 Subject: [PATCH 11/15] update layer related types --- packages/kit/src/loader/config.ts | 3 ++- packages/nuxt/src/auto-imports/module.ts | 1 - packages/nuxt/src/core/app.ts | 2 -- packages/nuxt/src/core/builder.ts | 2 +- packages/nuxt/src/core/nitro.ts | 2 +- packages/nuxt/src/core/nuxt.ts | 2 +- packages/schema/src/types/config.ts | 13 ++++++++++--- 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/kit/src/loader/config.ts b/packages/kit/src/loader/config.ts index 84a85f5cbb1..112c404a5a8 100644 --- a/packages/kit/src/loader/config.ts +++ b/packages/kit/src/loader/config.ts @@ -7,7 +7,7 @@ import { NuxtConfigSchema } from '@nuxt/schema' export interface LoadNuxtConfigOptions extends LoadConfigOptions {} export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise { - const { config: nuxtConfig, configFile, layers, cwd } = await loadConfig({ + const { config: nuxtConfig, configFile, layers, cwd } = await loadConfig({ name: 'nuxt', configFile: 'nuxt.config', rcFile: '.nuxtrc', @@ -23,6 +23,7 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise>({ // composables/ dirs from all layers let composablesDirs: string[] = [] for (const layer of nuxt.options._layers) { - if (!layer.config.srcDir) { continue } composablesDirs.push(resolve(layer.config.srcDir, 'composables')) for (const dir of (layer.config.autoImports?.dirs ?? [])) { if (!dir) { diff --git a/packages/nuxt/src/core/app.ts b/packages/nuxt/src/core/app.ts index f07e64ae7a3..8af1db8ddd8 100644 --- a/packages/nuxt/src/core/app.ts +++ b/packages/nuxt/src/core/app.ts @@ -78,7 +78,6 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { // Resolve layouts/ from all config layers app.layouts = {} for (const config of nuxt.options._layers.map(layer => layer.config)) { - if (!config.srcDir) { continue } const layoutFiles = await resolveFiles(config.srcDir, `${config.dir?.layouts || 'layouts'}/*{${nuxt.options.extensions.join(',')}}`) for (const file of layoutFiles) { const name = getNameFromPath(file) @@ -89,7 +88,6 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) { // Resolve middleware/ from all config layers app.middleware = [] for (const config of nuxt.options._layers.map(layer => layer.config)) { - if (!config.srcDir) { continue } const middlewareFiles = await resolveFiles(config.srcDir, `${config.dir?.middleware || 'middleware'}/*{${nuxt.options.extensions.join(',')}}`) app.middleware.push(...middlewareFiles.map((file) => { const name = getNameFromPath(file) diff --git a/packages/nuxt/src/core/builder.ts b/packages/nuxt/src/core/builder.ts index 09af04bee08..2e0028f8a6c 100644 --- a/packages/nuxt/src/core/builder.ts +++ b/packages/nuxt/src/core/builder.ts @@ -38,7 +38,7 @@ export async function build (nuxt: Nuxt) { } function watch (nuxt: Nuxt) { - const watcher = chokidar.watch(nuxt.options._layers.map(i => i.config?.srcDir as string).filter(Boolean), { + const watcher = chokidar.watch(nuxt.options._layers.map(i => i.config.srcDir as string).filter(Boolean), { ...nuxt.options.watchers.chokidar, cwd: nuxt.options.srcDir, ignoreInitial: true, diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index 7d5598af9eb..c3993ec3d44 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -43,7 +43,7 @@ export async function initNitro (nuxt: Nuxt) { publicAssets: [ { dir: resolve(nuxt.options.buildDir, 'dist/client') }, ...nuxt.options._layers - .map(layer => join(layer.config.srcDir!, layer.config.dir?.public || 'public')) + .map(layer => join(layer.config.srcDir, layer.config.dir?.public || 'public')) .filter(dir => existsSync(dir)) .map(dir => ({ dir })) ], diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts index b04b0227a2a..730eb763efd 100644 --- a/packages/nuxt/src/core/nuxt.ts +++ b/packages/nuxt/src/core/nuxt.ts @@ -81,7 +81,7 @@ async function initNuxt (nuxt: Nuxt) { // Transpile layers within node_modules nuxt.options.build.transpile.push( - ...nuxt.options._layers.filter(i => i.cwd && i.cwd.includes('node_modules')).map(i => i.cwd as string) + ...nuxt.options._layers.filter(i => i.cwd.includes('node_modules')).map(i => i.cwd as string) ) // Init user modules diff --git a/packages/schema/src/types/config.ts b/packages/schema/src/types/config.ts index 9bda3ff7e05..6b69e5adf81 100644 --- a/packages/schema/src/types/config.ts +++ b/packages/schema/src/types/config.ts @@ -12,13 +12,20 @@ export interface NuxtConfig extends DeepPartial> { [key: string]: any } -export interface LayerOptions extends ResolvedConfig { - config: NuxtConfig +// TODO: Expose ConfigLayer from c12 +interface ConfigLayer { + config: T; + cwd: string; + configFile: string } +export type NuxtConfigLayer = ConfigLayer /** Normalized Nuxt options available as `nuxt.options.*` */ export interface NuxtOptions extends ConfigSchema { - _layers: LayerOptions[] + _layers: NuxtConfigLayer[] } type RuntimeConfigNamespace = Record From 7e06712b1eccd021c48b9e9a92e2c2ce1ee10317 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 12 Aug 2022 19:13:49 +0200 Subject: [PATCH 12/15] simplify renderer types --- packages/nuxt/src/app/nuxt.ts | 34 ++++++++++--------- .../nuxt/src/core/runtime/nitro/renderer.ts | 10 ++---- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts index 8777c87f6dc..b24bda3c8d5 100644 --- a/packages/nuxt/src/app/nuxt.ts +++ b/packages/nuxt/src/app/nuxt.ts @@ -38,6 +38,23 @@ export interface RuntimeNuxtHooks { 'vue:error': (...args: Parameters[0]>) => HookResult } +export interface NuxtSSRContext extends SSRContext { + url: string + event: CompatibilityEvent + /** @deprecated Use `event` instead. */ + req?: CompatibilityEvent['req'] + /** @deprecated Use `event` instead. */ + res?: CompatibilityEvent['res'] + runtimeConfig: RuntimeConfig + noSSR: boolean + /** whether we are rendering an SSR error */ + error?: boolean + nuxt: _NuxtApp + payload: _NuxtApp['payload'] + teleports?: Record + renderMeta?: () => Promise | NuxtMeta +} + interface _NuxtApp { vueApp: App globalName: string @@ -50,22 +67,7 @@ interface _NuxtApp { _asyncDataPromises: Record | undefined> - ssrContext?: SSRContext & { - url: string - event: CompatibilityEvent - /** @deprecated Use `event` instead. */ - req?: CompatibilityEvent['req'] - /** @deprecated Use `event` instead. */ - res?: CompatibilityEvent['res'] - runtimeConfig: RuntimeConfig - noSSR: boolean - /** whether we are rendering an SSR error */ - error?: boolean - nuxt: _NuxtApp - payload: _NuxtApp['payload'] - teleports?: Record - renderMeta?: () => Promise | NuxtMeta - } + ssrContext?: NuxtSSRContext payload: { serverRendered?: boolean data: Record diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index 4b63f1771b4..a1addbe10ad 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -4,17 +4,12 @@ import type { Manifest } from 'vite' import { getQuery } from 'h3' import devalue from '@nuxt/devalue' import { renderToString as _renderToString } from 'vue/server-renderer' -import type { NuxtApp } from '#app' +import type { NuxtApp, NuxtSSRContext } from '#app' import { useRuntimeConfig, useNitroApp, defineRenderHandler as _defineRenderHandler } from '#internal/nitro' // @ts-ignore import { buildAssetsURL } from '#paths' -type ArgumentType = T extends (...args: infer U) => any ? U : never -type Required = T extends undefined ? never : T - -export type NuxtSSRContext = Required - export interface NuxtRenderHTMLContext { htmlAttrs: string[] head: string[] @@ -59,7 +54,8 @@ const getSSRRenderer = lazyCachedFunction(async () => { // Create renderer const renderer = createRenderer(createSSRApp, options) - async function renderToString (input: ArgumentType[0], context: ArgumentType[1]) { + type RenderToStringParams = Parameters + async function renderToString (input: RenderToStringParams[0], context: RenderToStringParams[1]) { const html = await _renderToString(input, context) // In development with vite-node, the manifest is on-demand and will be available after rendering if (process.dev && process.env.NUXT_VITE_NODE_OPTIONS) { From 2b65f8e0faba07ac94bfc45d4646ab59c543f042 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 12 Aug 2022 19:15:25 +0200 Subject: [PATCH 13/15] remove unnecessary rename --- packages/nuxt/src/core/runtime/nitro/renderer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index a1addbe10ad..9c42349db93 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -5,7 +5,7 @@ import { getQuery } from 'h3' import devalue from '@nuxt/devalue' import { renderToString as _renderToString } from 'vue/server-renderer' import type { NuxtApp, NuxtSSRContext } from '#app' -import { useRuntimeConfig, useNitroApp, defineRenderHandler as _defineRenderHandler } from '#internal/nitro' +import { useRuntimeConfig, useNitroApp, defineRenderHandler } from '#internal/nitro' // @ts-ignore import { buildAssetsURL } from '#paths' @@ -98,7 +98,7 @@ const getSPARenderer = lazyCachedFunction(async () => { return { renderToString } }) -export default _defineRenderHandler(async (event) => { +export default defineRenderHandler(async (event) => { // Whether we're rendering an error page const ssrError = event.req.url?.startsWith('/__nuxt_error') ? getQuery(event) as Exclude : null const url = ssrError?.url as string || event.req.url! From 369ae4e52e3c579ab58aa83001238241fc6e576f Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 12 Aug 2022 19:36:15 +0200 Subject: [PATCH 14/15] add some missing types --- .../nuxt/src/head/runtime/lib/vue-meta.plugin.ts | 16 ++++++++-------- .../src/head/runtime/lib/vueuse-head.plugin.ts | 2 +- packages/nuxt/src/head/runtime/plugin.ts | 2 +- packages/nuxt/src/pages/module.ts | 2 +- packages/nuxt/src/pages/runtime/page.ts | 7 ++++--- packages/nuxt/src/pages/runtime/router.ts | 14 +++++++------- packages/nuxt/src/pages/runtime/utils.ts | 4 ++-- packages/nuxt/src/pages/utils.ts | 6 +++--- 8 files changed, 27 insertions(+), 26 deletions(-) diff --git a/packages/nuxt/src/head/runtime/lib/vue-meta.plugin.ts b/packages/nuxt/src/head/runtime/lib/vue-meta.plugin.ts index 89695dc9fcf..9569534d954 100644 --- a/packages/nuxt/src/head/runtime/lib/vue-meta.plugin.ts +++ b/packages/nuxt/src/head/runtime/lib/vue-meta.plugin.ts @@ -20,20 +20,20 @@ export default defineNuxtPlugin((nuxtApp) => { } if (process.server) { - nuxtApp.ssrContext.renderMeta = async () => { + nuxtApp.ssrContext!.renderMeta = async () => { // @ts-ignore const { renderMetaToString } = await import('vue-meta/ssr') - nuxtApp.ssrContext.teleports = nuxtApp.ssrContext.teleports || {} + nuxtApp.ssrContext!.teleports = nuxtApp.ssrContext!.teleports || {} await renderMetaToString(nuxtApp.app, nuxtApp.ssrContext) return { - htmlAttrs: nuxtApp.ssrContext.teleports.htmlAttrs || '', - headAttrs: nuxtApp.ssrContext.teleports.headAttrs || '', - bodyAttrs: nuxtApp.ssrContext.teleports.bodyAttrs || '', - headTags: nuxtApp.ssrContext.teleports.head || '', - bodyScriptsPrepend: nuxtApp.ssrContext.teleports['body-prepend'] || '', - bodyScripts: nuxtApp.ssrContext.teleports.body || '' + htmlAttrs: nuxtApp.ssrContext!.teleports.htmlAttrs || '', + headAttrs: nuxtApp.ssrContext!.teleports.headAttrs || '', + bodyAttrs: nuxtApp.ssrContext!.teleports.bodyAttrs || '', + headTags: nuxtApp.ssrContext!.teleports.head || '', + bodyScriptsPrepend: nuxtApp.ssrContext!.teleports['body-prepend'] || '', + bodyScripts: nuxtApp.ssrContext!.teleports.body || '' } } } diff --git a/packages/nuxt/src/head/runtime/lib/vueuse-head.plugin.ts b/packages/nuxt/src/head/runtime/lib/vueuse-head.plugin.ts index 0bd2c5d6fe6..87558cc44c0 100644 --- a/packages/nuxt/src/head/runtime/lib/vueuse-head.plugin.ts +++ b/packages/nuxt/src/head/runtime/lib/vueuse-head.plugin.ts @@ -45,7 +45,7 @@ export default defineNuxtPlugin((nuxtApp) => { } if (process.server) { - nuxtApp.ssrContext.renderMeta = () => { + nuxtApp.ssrContext!.renderMeta = () => { const meta = renderHeadToString(head) return { ...meta, diff --git a/packages/nuxt/src/head/runtime/plugin.ts b/packages/nuxt/src/head/runtime/plugin.ts index 476bba28803..f9713dad13d 100644 --- a/packages/nuxt/src/head/runtime/plugin.ts +++ b/packages/nuxt/src/head/runtime/plugin.ts @@ -34,6 +34,6 @@ export default defineNuxtPlugin((nuxtApp) => { for (const name in Components) { // eslint-disable-next-line import/namespace - nuxtApp.vueApp.component(name, Components[name]) + nuxtApp.vueApp.component(name, (Components as any)[name]) } }) diff --git a/packages/nuxt/src/pages/module.ts b/packages/nuxt/src/pages/module.ts index 4dd56899c9d..e331c3402ea 100644 --- a/packages/nuxt/src/pages/module.ts +++ b/packages/nuxt/src/pages/module.ts @@ -47,7 +47,7 @@ export default defineNuxtModule({ nuxt.hook('app:resolve', (app) => { // Add default layout for pages - if (app.mainComponent.includes('@nuxt/ui-templates')) { + if (app.mainComponent!.includes('@nuxt/ui-templates')) { app.mainComponent = resolve(runtimeDir, 'app.vue') } }) diff --git a/packages/nuxt/src/pages/runtime/page.ts b/packages/nuxt/src/pages/runtime/page.ts index d1e22f797d2..49e223df6f5 100644 --- a/packages/nuxt/src/pages/runtime/page.ts +++ b/packages/nuxt/src/pages/runtime/page.ts @@ -1,5 +1,5 @@ import { computed, DefineComponent, defineComponent, h, inject, provide, reactive, Suspense, Transition } from 'vue' -import { RouteLocationNormalized, RouteLocationNormalizedLoaded, RouterView } from 'vue-router' +import { RouteLocation, RouteLocationNormalized, RouteLocationNormalizedLoaded, RouterView } from 'vue-router' import { generateRouteKey, RouterViewSlotProps, wrapInKeepAlive } from './utils' import { useNuxtApp } from '#app' @@ -58,6 +58,7 @@ export default defineComponent({ const defaultPageTransition = { name: 'page', mode: 'out-in' } const Component = defineComponent({ + // TODO: Type props // eslint-disable-next-line vue/require-prop-types props: ['routeProps', 'pageKey'], setup (props) { @@ -66,9 +67,9 @@ const Component = defineComponent({ const previousRoute = props.routeProps.route // Provide a reactive route within the page - const route = {} + const route = {} as RouteLocation for (const key in props.routeProps.route) { - route[key] = computed(() => previousKey === props.pageKey ? props.routeProps.route[key] : previousRoute[key]) + (route as any)[key] = computed(() => previousKey === props.pageKey ? props.routeProps.route[key] : previousRoute[key]) } provide('_route', reactive(route)) diff --git a/packages/nuxt/src/pages/runtime/router.ts b/packages/nuxt/src/pages/runtime/router.ts index 190ad20cc79..0b50bd67a9d 100644 --- a/packages/nuxt/src/pages/runtime/router.ts +++ b/packages/nuxt/src/pages/runtime/router.ts @@ -59,7 +59,7 @@ export default defineNuxtPlugin(async (nuxtApp) => { ? createWebHistory(baseURL) : createMemoryHistory(baseURL) - const initialURL = process.server ? nuxtApp.ssrContext.url : createCurrentLocation(baseURL, window.location) + const initialURL = process.server ? nuxtApp.ssrContext!.url : createCurrentLocation(baseURL, window.location) const router = createRouter({ ...routerOptions, history: routerHistory, @@ -89,9 +89,9 @@ export default defineNuxtPlugin(async (nuxtApp) => { }) // https://github.com/vuejs/router/blob/main/packages/router/src/router.ts#L1225-L1233 - const route = {} + const route = {} as RouteLocation for (const key in _route.value) { - route[key] = computed(() => _route.value[key]) + (route as any)[key] = computed(() => _route.value[key as keyof RouteLocation]) } nuxtApp._route = reactive(route) @@ -109,7 +109,7 @@ export default defineNuxtPlugin(async (nuxtApp) => { } await router.isReady() - } catch (error) { + } catch (error: any) { // We'll catch 404s here callWithNuxt(nuxtApp, showError, [error]) } @@ -133,7 +133,7 @@ export default defineNuxtPlugin(async (nuxtApp) => { } for (const entry of middlewareEntries) { - const middleware = typeof entry === 'string' ? nuxtApp._middleware.named[entry] || await namedMiddleware[entry]?.().then(r => r.default || r) : entry + const middleware = typeof entry === 'string' ? nuxtApp._middleware.named[entry] || await namedMiddleware[entry]?.().then((r: any) => r.default || r) : entry if (!middleware) { if (process.dev) { @@ -169,7 +169,7 @@ export default defineNuxtPlugin(async (nuxtApp) => { statusMessage: `Page not found: ${to.fullPath}` })]) } else if (process.server && to.matched[0].name === '404' && nuxtApp.ssrContext) { - nuxtApp.ssrContext.res.statusCode = 404 + nuxtApp.ssrContext.event.res.statusCode = 404 } else if (process.server) { const currentURL = to.fullPath || '/' if (!isEqual(currentURL, initialURL)) { @@ -185,7 +185,7 @@ export default defineNuxtPlugin(async (nuxtApp) => { name: undefined, // #4920, #$4982 force: true }) - } catch (error) { + } catch (error: any) { // We'll catch middleware errors or deliberate exceptions here callWithNuxt(nuxtApp, showError, [error]) } diff --git a/packages/nuxt/src/pages/runtime/utils.ts b/packages/nuxt/src/pages/runtime/utils.ts index 3d36e132199..e0700cf4bd9 100644 --- a/packages/nuxt/src/pages/runtime/utils.ts +++ b/packages/nuxt/src/pages/runtime/utils.ts @@ -12,8 +12,8 @@ const interpolatePath = (route: RouteLocationNormalizedLoaded, match: RouteLocat } export const generateRouteKey = (override: string | ((route: RouteLocationNormalizedLoaded) => string), routeProps: RouterViewSlotProps) => { - const matchedRoute = routeProps.route.matched.find(m => m.components.default === routeProps.Component.type) - const source = override ?? matchedRoute?.meta.key ?? interpolatePath(routeProps.route, matchedRoute) + const matchedRoute = routeProps.route.matched.find(m => m.components?.default === routeProps.Component.type) + const source = override ?? matchedRoute?.meta.key ?? (matchedRoute && interpolatePath(routeProps.route, matchedRoute)) return typeof source === 'function' ? source(routeProps.route) : source } diff --git a/packages/nuxt/src/pages/utils.ts b/packages/nuxt/src/pages/utils.ts index 29ae037322b..0e23b1391ad 100644 --- a/packages/nuxt/src/pages/utils.ts +++ b/packages/nuxt/src/pages/utils.ts @@ -76,7 +76,7 @@ export function generateRoutesFromFiles (files: string[], pagesDir: string): Nux // ex: parent.vue + parent/child.vue const child = parent.find(parentRoute => parentRoute.name === route.name && !parentRoute.path.endsWith('(.*)*')) - if (child) { + if (child && child.children) { parent = child.children route.path = '' } else if (segmentName === '404' && isSingleSegment) { @@ -213,11 +213,11 @@ function prepareRoutes (routes: NuxtPage[], parent?: NuxtPage) { route.path = route.path.slice(1) } - if (route.children.length) { + if (route.children?.length) { route.children = prepareRoutes(route.children, route) } - if (route.children.find(childRoute => childRoute.path === '')) { + if (route.children?.find(childRoute => childRoute.path === '')) { delete route.name } } From 2a045109538a245e3488568a1efc785ec9970e6a Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 12 Aug 2022 19:37:05 +0200 Subject: [PATCH 15/15] fix lint --- packages/schema/src/types/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/schema/src/types/config.ts b/packages/schema/src/types/config.ts index 6b69e5adf81..3207e7f87ae 100644 --- a/packages/schema/src/types/config.ts +++ b/packages/schema/src/types/config.ts @@ -1,5 +1,4 @@ import { ConfigSchema } from '../../schema/config' -import type { ResolvedConfig } from 'c12' import type { UserConfig as ViteUserConfig } from 'vite' import type { Options as VuePluginOptions } from '@vitejs/plugin-vue'