mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
refactor(nuxt): enable strict type checking (#6368)
Co-authored-by: Pooya Parsa <pooya@pi0.io>
This commit is contained in:
parent
cb98c8b921
commit
f350a70775
@ -7,7 +7,7 @@ import { NuxtConfigSchema } from '@nuxt/schema'
|
|||||||
export interface LoadNuxtConfigOptions extends LoadConfigOptions<NuxtConfig> {}
|
export interface LoadNuxtConfigOptions extends LoadConfigOptions<NuxtConfig> {}
|
||||||
|
|
||||||
export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<NuxtOptions> {
|
export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<NuxtOptions> {
|
||||||
const { config: nuxtConfig, configFile, layers, cwd } = await loadConfig({
|
const { config: nuxtConfig, configFile, layers, cwd } = await loadConfig<NuxtConfig>({
|
||||||
name: 'nuxt',
|
name: 'nuxt',
|
||||||
configFile: 'nuxt.config',
|
configFile: 'nuxt.config',
|
||||||
rcFile: '.nuxtrc',
|
rcFile: '.nuxtrc',
|
||||||
@ -23,6 +23,7 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
|
|||||||
|
|
||||||
// Resolve `rootDir` & `srcDir` of layers
|
// Resolve `rootDir` & `srcDir` of layers
|
||||||
for (const layer of layers) {
|
for (const layer of layers) {
|
||||||
|
layer.config = layer.config || {}
|
||||||
layer.config.rootDir = layer.config.rootDir ?? layer.cwd
|
layer.config.rootDir = layer.config.rootDir ?? layer.cwd
|
||||||
layer.config.srcDir = resolve(layer.config.rootDir, layer.config.srcDir)
|
layer.config.srcDir = resolve(layer.config.rootDir, layer.config.srcDir)
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,19 @@ export * from 'vue'
|
|||||||
|
|
||||||
export const install = () => {}
|
export const install = () => {}
|
||||||
|
|
||||||
export function set (target, key, val) {
|
export function set (target: any, key: string | number | symbol, val: any) {
|
||||||
if (Array.isArray(target)) {
|
if (Array.isArray(target)) {
|
||||||
target.length = Math.max(target.length, key)
|
target.length = Math.max(target.length, key as number)
|
||||||
target.splice(key, 1, val)
|
target.splice(key as number, 1, val)
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
target[key] = val
|
target[key] = val
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
export function del (target, key) {
|
export function del (target: any, key: string | number | symbol) {
|
||||||
if (Array.isArray(target)) {
|
if (Array.isArray(target)) {
|
||||||
target.splice(key, 1)
|
target.splice(key as number, 1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
delete target[key]
|
delete target[key]
|
||||||
|
@ -8,7 +8,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup (_props, { slots, emit }) {
|
setup (_props, { slots, emit }) {
|
||||||
const error = ref(null)
|
const error = ref<Error | null>(null)
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
|
|
||||||
onErrorCaptured((err) => {
|
onErrorCaptured((err) => {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { defineComponent, h, resolveComponent, PropType, computed, DefineComponent } from 'vue'
|
import { defineComponent, h, resolveComponent, PropType, computed, DefineComponent, ComputedRef } from 'vue'
|
||||||
import { RouteLocationRaw, Router } from 'vue-router'
|
import { RouteLocationRaw } from 'vue-router'
|
||||||
import { hasProtocol } from 'ufo'
|
import { hasProtocol } from 'ufo'
|
||||||
|
|
||||||
import { navigateTo, useRouter } from '#app'
|
import { navigateTo, useRouter } from '#app'
|
||||||
|
|
||||||
const firstNonUndefined = <T>(...args: T[]): T => args.find(arg => arg !== undefined)
|
const firstNonUndefined = <T>(...args: (T | undefined)[]) => args.find(arg => arg !== undefined)
|
||||||
|
|
||||||
const DEFAULT_EXTERNAL_REL_ATTRIBUTE = 'noopener noreferrer'
|
const DEFAULT_EXTERNAL_REL_ATTRIBUTE = 'noopener noreferrer'
|
||||||
|
|
||||||
@ -24,8 +24,8 @@ export type NuxtLinkProps = {
|
|||||||
custom?: boolean
|
custom?: boolean
|
||||||
|
|
||||||
// Attributes
|
// Attributes
|
||||||
target?: string
|
target?: string | null
|
||||||
rel?: string
|
rel?: string | null
|
||||||
noRel?: boolean
|
noRel?: boolean
|
||||||
|
|
||||||
// Styling
|
// Styling
|
||||||
@ -39,7 +39,7 @@ export type NuxtLinkProps = {
|
|||||||
export function defineNuxtLink (options: NuxtLinkOptions) {
|
export function defineNuxtLink (options: NuxtLinkOptions) {
|
||||||
const componentName = options.componentName || 'NuxtLink'
|
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) {
|
if (process.dev && props[main] !== undefined && props[sub] !== undefined) {
|
||||||
console.warn(`[${componentName}] \`${main}\` and \`${sub}\` cannot be used together. \`${sub}\` will be ignored.`)
|
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 }) {
|
setup (props, { slots }) {
|
||||||
const router = useRouter() as Router | undefined
|
const router = useRouter()
|
||||||
|
|
||||||
// Resolving `to` value from `to` and `href` props
|
// Resolving `to` value from `to` and `href` props
|
||||||
const to = computed<string | RouteLocationRaw>(() => {
|
const to: ComputedRef<string | RouteLocationRaw> = computed(() => {
|
||||||
checkPropConflicts(props, 'to', 'href')
|
checkPropConflicts(props, 'to', 'href')
|
||||||
|
|
||||||
return props.to || props.href || '' // Defaults to empty string (won't render any `href` attribute)
|
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
|
// Resolving link type
|
||||||
const isExternal = computed<boolean>(() => {
|
const isExternal = computed<boolean>(() => {
|
||||||
// External prop is explictly set
|
// External prop is explicitly set
|
||||||
if (props.external) {
|
if (props.external) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -180,11 +180,13 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
|
|||||||
|
|
||||||
// https://router.vuejs.org/api/#custom
|
// https://router.vuejs.org/api/#custom
|
||||||
if (props.custom) {
|
if (props.custom) {
|
||||||
if (!slots.default) { return null }
|
if (!slots.default) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
return slots.default({
|
return slots.default({
|
||||||
href,
|
href,
|
||||||
navigate,
|
navigate,
|
||||||
route: router.resolve(href),
|
route: router.resolve(href!),
|
||||||
rel,
|
rel,
|
||||||
target,
|
target,
|
||||||
isActive: false,
|
isActive: false,
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { h } from 'vue'
|
import { defineComponent, h } from 'vue'
|
||||||
import type { Component } from 'vue'
|
import type { Component } from 'vue'
|
||||||
|
|
||||||
const Fragment = {
|
const Fragment = defineComponent({
|
||||||
setup (_props, { slots }) {
|
setup (_props, { slots }) {
|
||||||
return () => slots.default?.()
|
return () => slots.default?.()
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal utility
|
* Internal utility
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { onBeforeMount, onServerPrefetch, onUnmounted, ref, getCurrentInstance, watch, unref } from 'vue'
|
import { onBeforeMount, onServerPrefetch, onUnmounted, ref, getCurrentInstance, watch, unref } from 'vue'
|
||||||
import type { Ref, WatchSource } from 'vue'
|
import type { Ref, WatchSource } from 'vue'
|
||||||
import { wrapInRef } from './utils'
|
|
||||||
import { NuxtApp, useNuxtApp } from '#app'
|
import { NuxtApp, useNuxtApp } from '#app'
|
||||||
|
|
||||||
export type _Transform<Input = any, Output = any> = (input: Input) => Output
|
export type _Transform<Input = any, Output = any> = (input: Input) => Output
|
||||||
@ -25,7 +24,7 @@ export interface AsyncDataOptions<
|
|||||||
> {
|
> {
|
||||||
server?: boolean
|
server?: boolean
|
||||||
lazy?: boolean
|
lazy?: boolean
|
||||||
default?: () => DataT | Ref<DataT>
|
default?: () => DataT | Ref<DataT> | null
|
||||||
transform?: Transform
|
transform?: Transform
|
||||||
pick?: PickKeys
|
pick?: PickKeys
|
||||||
watch?: MultiWatchSources
|
watch?: MultiWatchSources
|
||||||
@ -37,10 +36,10 @@ export interface RefreshOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface _AsyncData<DataT, ErrorT> {
|
export interface _AsyncData<DataT, ErrorT> {
|
||||||
data: Ref<DataT>
|
data: Ref<DataT | null>
|
||||||
pending: Ref<boolean>
|
pending: Ref<boolean>
|
||||||
refresh: (opts?: RefreshOptions) => Promise<void>
|
refresh: (opts?: RefreshOptions) => Promise<void>
|
||||||
error: Ref<ErrorT>
|
error: Ref<ErrorT | null>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AsyncData<Data, Error> = _AsyncData<Data, Error> & Promise<_AsyncData<Data, Error>>
|
export type AsyncData<Data, Error> = _AsyncData<Data, Error> & Promise<_AsyncData<Data, Error>>
|
||||||
@ -70,7 +69,7 @@ export function useAsyncData<
|
|||||||
DataE = Error,
|
DataE = Error,
|
||||||
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
|
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
|
||||||
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
||||||
> (...args): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
|
> (...args: any[]): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
|
||||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||||
|
|
||||||
@ -102,7 +101,8 @@ export function useAsyncData<
|
|||||||
// Setup hook callbacks once per instance
|
// Setup hook callbacks once per instance
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
if (instance && !instance._nuxtOnBeforeMountCbs) {
|
if (instance && !instance._nuxtOnBeforeMountCbs) {
|
||||||
const cbs = instance._nuxtOnBeforeMountCbs = []
|
instance._nuxtOnBeforeMountCbs = []
|
||||||
|
const cbs = instance._nuxtOnBeforeMountCbs
|
||||||
if (instance && process.client) {
|
if (instance && process.client) {
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
cbs.forEach((cb) => { cb() })
|
cbs.forEach((cb) => { cb() })
|
||||||
@ -115,7 +115,7 @@ export function useAsyncData<
|
|||||||
const useInitialCache = () => options.initialCache && nuxt.payload.data[key] !== undefined
|
const useInitialCache = () => options.initialCache && nuxt.payload.data[key] !== undefined
|
||||||
|
|
||||||
const asyncData = {
|
const asyncData = {
|
||||||
data: wrapInRef(nuxt.payload.data[key] ?? options.default()),
|
data: ref(nuxt.payload.data[key] ?? options.default?.() ?? null),
|
||||||
pending: ref(!useInitialCache()),
|
pending: ref(!useInitialCache()),
|
||||||
error: ref(nuxt.payload._errors[key] ?? null)
|
error: ref(nuxt.payload._errors[key] ?? null)
|
||||||
} as AsyncData<DataT, DataE>
|
} as AsyncData<DataT, DataE>
|
||||||
@ -151,7 +151,7 @@ export function useAsyncData<
|
|||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error: any) => {
|
||||||
asyncData.error.value = error
|
asyncData.error.value = error
|
||||||
asyncData.data.value = unref(options.default())
|
asyncData.data.value = unref(options.default?.() ?? null)
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
asyncData.pending.value = false
|
asyncData.pending.value = false
|
||||||
@ -230,7 +230,7 @@ export function useLazyAsyncData<
|
|||||||
DataE = Error,
|
DataE = Error,
|
||||||
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
|
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
|
||||||
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
||||||
> (...args): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
|
> (...args: any[]): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE | null | true> {
|
||||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||||
const [key, handler, options] = args as [string, (ctx?: NuxtApp) => Promise<DataT>, AsyncDataOptions<DataT, Transform, PickKeys>]
|
const [key, handler, options] = args as [string, (ctx?: NuxtApp) => Promise<DataT>, AsyncDataOptions<DataT, Transform, PickKeys>]
|
||||||
@ -249,7 +249,7 @@ export function refreshNuxtData (keys?: string | string[]): Promise<void> {
|
|||||||
function pick (obj: Record<string, any>, keys: string[]) {
|
function pick (obj: Record<string, any>, keys: string[]) {
|
||||||
const newObj = {}
|
const newObj = {}
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
newObj[key] = obj[key]
|
(newObj as any)[key] = obj[key]
|
||||||
}
|
}
|
||||||
return newObj
|
return newObj
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ export const NuxtComponentIndicator = '__nuxt_component'
|
|||||||
async function runLegacyAsyncData (res: Record<string, any> | Promise<Record<string, any>>, fn: (nuxtApp: NuxtApp) => Promise<Record<string, any>>) {
|
async function runLegacyAsyncData (res: Record<string, any> | Promise<Record<string, any>>, fn: (nuxtApp: NuxtApp) => Promise<Record<string, any>>) {
|
||||||
const nuxt = useNuxtApp()
|
const nuxt = useNuxtApp()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const vm = getCurrentInstance()
|
const vm = getCurrentInstance()!
|
||||||
const { fetchKey } = vm.proxy.$options
|
const { fetchKey } = vm.proxy!.$options
|
||||||
const key = typeof fetchKey === 'function' ? fetchKey(() => '') : fetchKey || route.fullPath
|
const key = typeof fetchKey === 'function' ? fetchKey(() => '') : fetchKey || route.fullPath
|
||||||
const { data } = await useAsyncData(`options:asyncdata:${key}`, () => fn(nuxt))
|
const { data } = await useAsyncData(`options:asyncdata:${key}`, () => fn(nuxt))
|
||||||
if (data.value && typeof data.value === 'object') {
|
if (data.value && typeof data.value === 'object') {
|
||||||
@ -38,8 +38,7 @@ export const defineNuxtComponent: typeof defineComponent =
|
|||||||
setup (props, ctx) {
|
setup (props, ctx) {
|
||||||
const res = setup?.(props, ctx) || {}
|
const res = setup?.(props, ctx) || {}
|
||||||
|
|
||||||
let promises: unknown[] | undefined = []
|
const promises: Promise<any>[] = []
|
||||||
promises = promises || []
|
|
||||||
if (options.asyncData) {
|
if (options.asyncData) {
|
||||||
promises.push(runLegacyAsyncData(res, options.asyncData))
|
promises.push(runLegacyAsyncData(res, options.asyncData))
|
||||||
}
|
}
|
||||||
@ -49,7 +48,6 @@ export const defineNuxtComponent: typeof defineComponent =
|
|||||||
.then(() => res)
|
.then(() => res)
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
promises.length = 0
|
promises.length = 0
|
||||||
promises = null
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} as DefineComponent
|
} as DefineComponent
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { Ref, watch } from 'vue'
|
import { ref, Ref, watch } from 'vue'
|
||||||
import { parse, serialize, CookieParseOptions, CookieSerializeOptions } from 'cookie-es'
|
import { parse, serialize, CookieParseOptions, CookieSerializeOptions } from 'cookie-es'
|
||||||
import { appendHeader } from 'h3'
|
import { appendHeader } from 'h3'
|
||||||
import type { CompatibilityEvent } from 'h3'
|
import type { CompatibilityEvent } from 'h3'
|
||||||
import destr from 'destr'
|
import destr from 'destr'
|
||||||
import { isEqual } from 'ohash'
|
import { isEqual } from 'ohash'
|
||||||
import { useRequestEvent } from './ssr'
|
import { useRequestEvent } from './ssr'
|
||||||
import { wrapInRef } from './utils'
|
|
||||||
import { useNuxtApp } from '#app'
|
import { useNuxtApp } from '#app'
|
||||||
|
|
||||||
type _CookieOptions = Omit<CookieSerializeOptions & CookieParseOptions, 'decode' | 'encode'>
|
type _CookieOptions = Omit<CookieSerializeOptions & CookieParseOptions, 'decode' | 'encode'>
|
||||||
@ -24,11 +23,11 @@ const CookieDefaults: CookieOptions<any> = {
|
|||||||
encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val))
|
encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCookie <T=string> (name: string, _opts?: CookieOptions<T>): CookieRef<T> {
|
export function useCookie <T = string> (name: string, _opts?: CookieOptions<T>): CookieRef<T> {
|
||||||
const opts = { ...CookieDefaults, ..._opts }
|
const opts = { ...CookieDefaults, ..._opts }
|
||||||
const cookies = readRawCookies(opts)
|
const cookies = readRawCookies(opts) || {}
|
||||||
|
|
||||||
const cookie = wrapInRef<T>(cookies[name] ?? opts.default?.())
|
const cookie = ref<T | undefined>(cookies[name] as any ?? opts.default?.())
|
||||||
|
|
||||||
if (process.client) {
|
if (process.client) {
|
||||||
watch(cookie, () => { writeClientCookie(name, cookie.value, opts as CookieSerializeOptions) })
|
watch(cookie, () => { writeClientCookie(name, cookie.value, opts as CookieSerializeOptions) })
|
||||||
@ -46,7 +45,7 @@ export function useCookie <T=string> (name: string, _opts?: CookieOptions<T>): C
|
|||||||
return cookie as CookieRef<T>
|
return cookie as CookieRef<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
function readRawCookies (opts: CookieOptions = {}): Record<string, string> {
|
function readRawCookies (opts: CookieOptions = {}): Record<string, string> | undefined {
|
||||||
if (process.server) {
|
if (process.server) {
|
||||||
return parse(useRequestEvent()?.req.headers.cookie || '', opts)
|
return parse(useRequestEvent()?.req.headers.cookie || '', opts)
|
||||||
} else if (process.client) {
|
} else if (process.client) {
|
||||||
|
@ -37,7 +37,7 @@ export function useFetch<
|
|||||||
arg1?: string | UseFetchOptions<_ResT, Transform, PickKeys>,
|
arg1?: string | UseFetchOptions<_ResT, Transform, PickKeys>,
|
||||||
arg2?: string
|
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
|
const _key = opts.key || autoKey
|
||||||
if (!_key || typeof _key !== 'string') {
|
if (!_key || typeof _key !== 'string') {
|
||||||
throw new TypeError('[nuxt] [useFetch] key must be a string: ' + _key)
|
throw new TypeError('[nuxt] [useFetch] key must be a string: ' + _key)
|
||||||
|
@ -61,7 +61,7 @@ export interface NavigateToOptions {
|
|||||||
redirectCode?: number
|
redirectCode?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const navigateTo = (to: RouteLocationRaw, options: NavigateToOptions = {}): Promise<void | NavigationFailure> | RouteLocationRaw => {
|
export const navigateTo = (to: RouteLocationRaw | undefined | null, options: NavigateToOptions = {}): Promise<void | NavigationFailure> | RouteLocationRaw => {
|
||||||
if (!to) {
|
if (!to) {
|
||||||
to = '/'
|
to = '/'
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ export const navigateTo = (to: RouteLocationRaw, options: NavigateToOptions = {}
|
|||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
if (nuxtApp.ssrContext && nuxtApp.ssrContext.event) {
|
if (nuxtApp.ssrContext && nuxtApp.ssrContext.event) {
|
||||||
const redirectLocation = joinURL(useRuntimeConfig().app.baseURL, router.resolve(to).fullPath || '/')
|
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
|
// Client-side redirection using vue-router
|
||||||
|
@ -5,9 +5,9 @@ import { NuxtApp } from '#app/nuxt'
|
|||||||
|
|
||||||
export function useRequestHeaders<K extends string = string> (include: K[]): Record<K, string | undefined>
|
export function useRequestHeaders<K extends string = string> (include: K[]): Record<K, string | undefined>
|
||||||
export function useRequestHeaders (): Readonly<Record<string, string | undefined>>
|
export function useRequestHeaders (): Readonly<Record<string, string | undefined>>
|
||||||
export function useRequestHeaders (include?) {
|
export function useRequestHeaders (include?: any[]) {
|
||||||
if (process.client) { return {} }
|
if (process.client) { return {} }
|
||||||
const headers: Record<string, string | string[]> = useNuxtApp().ssrContext?.event.req.headers ?? {}
|
const headers = useNuxtApp().ssrContext?.event.req.headers ?? {}
|
||||||
if (!include) { return headers }
|
if (!include) { return headers }
|
||||||
return Object.fromEntries(include.filter(key => headers[key]).map(key => [key, headers[key]]))
|
return Object.fromEntries(include.filter(key => headers[key]).map(key => [key, headers[key]]))
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import { useNuxtApp } from '#app'
|
|||||||
*/
|
*/
|
||||||
export function useState <T> (key?: string, init?: (() => T | Ref<T>)): Ref<T>
|
export function useState <T> (key?: string, init?: (() => T | Ref<T>)): Ref<T>
|
||||||
export function useState <T> (init?: (() => T | Ref<T>)): Ref<T>
|
export function useState <T> (init?: (() => T | Ref<T>)): Ref<T>
|
||||||
export function useState <T> (...args): Ref<T> {
|
export function useState <T> (...args: any): Ref<T> {
|
||||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||||
const [_key, init] = args as [string, (() => T | Ref<T>)]
|
const [_key, init] = args as [string, (() => T | Ref<T>)]
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
import { isRef, ref, Ref } from 'vue'
|
|
||||||
|
|
||||||
export const wrapInRef = <T> (value: T | Ref<T>) => isRef(value) ? value : ref(value)
|
|
@ -35,7 +35,7 @@ if (process.server) {
|
|||||||
await nuxt.hooks.callHook('app:created', vueApp)
|
await nuxt.hooks.callHook('app:created', vueApp)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
await nuxt.callHook('app:error', 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
|
return vueApp
|
||||||
@ -66,7 +66,7 @@ if (process.client) {
|
|||||||
await applyPlugins(nuxt, plugins)
|
await applyPlugins(nuxt, plugins)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
await nuxt.callHook('app:error', err)
|
await nuxt.callHook('app:error', err)
|
||||||
nuxt.payload.error = nuxt.payload.error || err
|
nuxt.payload.error = (nuxt.payload.error || err) as any
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -77,11 +77,11 @@ if (process.client) {
|
|||||||
await nextTick()
|
await nextTick()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
await nuxt.callHook('app:error', err)
|
await nuxt.callHook('app:error', err)
|
||||||
nuxt.payload.error = nuxt.payload.error || err
|
nuxt.payload.error = (nuxt.payload.error || err) as any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry().catch((error) => {
|
entry().catch((error: unknown) => {
|
||||||
console.error('Error while mounting app:', error) // eslint-disable-line no-console
|
console.error('Error while mounting app:', error) // eslint-disable-line no-console
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,23 @@ export interface RuntimeNuxtHooks {
|
|||||||
'vue:error': (...args: Parameters<Parameters<typeof onErrorCaptured>[0]>) => HookResult
|
'vue:error': (...args: Parameters<Parameters<typeof onErrorCaptured>[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<string, string>
|
||||||
|
renderMeta?: () => Promise<NuxtMeta> | NuxtMeta
|
||||||
|
}
|
||||||
|
|
||||||
interface _NuxtApp {
|
interface _NuxtApp {
|
||||||
vueApp: App<Element>
|
vueApp: App<Element>
|
||||||
globalName: string
|
globalName: string
|
||||||
@ -48,28 +65,13 @@ interface _NuxtApp {
|
|||||||
|
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
|
|
||||||
_asyncDataPromises?: Record<string, Promise<any>>
|
_asyncDataPromises: Record<string, Promise<any> | undefined>
|
||||||
|
|
||||||
ssrContext?: SSRContext & {
|
ssrContext?: NuxtSSRContext
|
||||||
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<string, string>
|
|
||||||
renderMeta?: () => Promise<NuxtMeta> | NuxtMeta
|
|
||||||
}
|
|
||||||
payload: {
|
payload: {
|
||||||
serverRendered?: boolean
|
serverRendered?: boolean
|
||||||
data?: Record<string, any>
|
data: Record<string, any>
|
||||||
state?: Record<string, any>
|
state: Record<string, any>
|
||||||
rendered?: Function
|
rendered?: Function
|
||||||
error?: Error | {
|
error?: Error | {
|
||||||
url: string
|
url: string
|
||||||
@ -135,24 +137,24 @@ export function createNuxtApp (options: CreateOptions) {
|
|||||||
}
|
}
|
||||||
// Expose to server renderer to create window.__NUXT__
|
// Expose to server renderer to create window.__NUXT__
|
||||||
nuxtApp.ssrContext = nuxtApp.ssrContext || {} as any
|
nuxtApp.ssrContext = nuxtApp.ssrContext || {} as any
|
||||||
if (nuxtApp.ssrContext.payload) {
|
if (nuxtApp.ssrContext!.payload) {
|
||||||
Object.assign(nuxtApp.payload, nuxtApp.ssrContext.payload)
|
Object.assign(nuxtApp.payload, nuxtApp.ssrContext!.payload)
|
||||||
}
|
}
|
||||||
nuxtApp.ssrContext.payload = nuxtApp.payload
|
nuxtApp.ssrContext!.payload = nuxtApp.payload
|
||||||
|
|
||||||
// Expose client runtime-config to the payload
|
// Expose client runtime-config to the payload
|
||||||
nuxtApp.payload.config = {
|
nuxtApp.payload.config = {
|
||||||
public: options.ssrContext.runtimeConfig.public,
|
public: options.ssrContext!.runtimeConfig.public,
|
||||||
app: options.ssrContext.runtimeConfig.app
|
app: options.ssrContext!.runtimeConfig.app
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose runtime config
|
// Expose runtime config
|
||||||
const runtimeConfig = process.server
|
const runtimeConfig = process.server
|
||||||
? options.ssrContext.runtimeConfig
|
? options.ssrContext!.runtimeConfig
|
||||||
: reactive(nuxtApp.payload.config)
|
: reactive(nuxtApp.payload.config)
|
||||||
|
|
||||||
// Backward compatibilty following #4254
|
// Backward compatibility following #4254
|
||||||
const compatibilityConfig = new Proxy(runtimeConfig, {
|
const compatibilityConfig = new Proxy(runtimeConfig, {
|
||||||
get (target, prop) {
|
get (target, prop) {
|
||||||
if (prop === 'public') {
|
if (prop === 'public') {
|
||||||
@ -192,9 +194,9 @@ export async function applyPlugins (nuxtApp: NuxtApp, plugins: Plugin[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function normalizePlugins (_plugins: Plugin[]) {
|
export function normalizePlugins (_plugins: Plugin[]) {
|
||||||
const unwrappedPlugins = []
|
const unwrappedPlugins: Plugin[] = []
|
||||||
const legacyInjectPlugins = []
|
const legacyInjectPlugins: Plugin[] = []
|
||||||
const invalidPlugins = []
|
const invalidPlugins: Plugin[] = []
|
||||||
|
|
||||||
const plugins = _plugins.map((plugin) => {
|
const plugins = _plugins.map((plugin) => {
|
||||||
if (typeof plugin !== 'function') {
|
if (typeof plugin !== 'function') {
|
||||||
|
@ -6,7 +6,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
if (logs.length > 0) {
|
if (logs.length > 0) {
|
||||||
const ssrLogStyle = 'background: #003C3C;border-radius: 0.5em;color: white;font-weight: bold;padding: 2px 0.5em;'
|
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)
|
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
|
delete nuxtApp.payload.logs
|
||||||
console.groupEnd && console.groupEnd()
|
console.groupEnd && console.groupEnd()
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
el.style.transition = 'width 0.1s, opacity 0.4s'
|
el.style.transition = 'width 0.1s, opacity 0.4s'
|
||||||
const duration = 3000
|
const duration = 3000
|
||||||
const progress = 10000 / Math.floor(duration)
|
const progress = 10000 / Math.floor(duration)
|
||||||
let timeout
|
let timeout: ReturnType<typeof setTimeout> | undefined
|
||||||
let interval
|
let interval: ReturnType<typeof setInterval> | undefined
|
||||||
nuxtApp.hook('page:start', () => {
|
nuxtApp.hook('page:start', () => {
|
||||||
if (timeout) { return }
|
if (timeout) { return }
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
@ -30,9 +30,9 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
})
|
})
|
||||||
nuxtApp.hook('page:finish', () => {
|
nuxtApp.hook('page:finish', () => {
|
||||||
timeout && clearTimeout(timeout)
|
timeout && clearTimeout(timeout)
|
||||||
timeout = null
|
timeout = undefined
|
||||||
interval && clearInterval(interval)
|
interval && clearInterval(interval)
|
||||||
interval = null
|
interval = undefined
|
||||||
el.style.width = '100%'
|
el.style.width = '100%'
|
||||||
el.style.opacity = '0%'
|
el.style.opacity = '0%'
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { reactive, h } from 'vue'
|
import { reactive, h } from 'vue'
|
||||||
import { parseURL, parseQuery, withoutBase, isEqual, joinURL } from 'ufo'
|
import { parseURL, parseQuery, withoutBase, isEqual, joinURL } from 'ufo'
|
||||||
import { createError } from 'h3'
|
import { createError } from 'h3'
|
||||||
import { defineNuxtPlugin } from '..'
|
import { defineNuxtPlugin, clearError, navigateTo, showError, useRuntimeConfig } from '..'
|
||||||
import { callWithNuxt } from '../nuxt'
|
import { callWithNuxt } from '../nuxt'
|
||||||
import { clearError, navigateTo, showError, useRuntimeConfig } from '#app'
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { globalMiddleware } from '#build/middleware'
|
import { globalMiddleware } from '#build/middleware'
|
||||||
|
|
||||||
@ -90,8 +89,9 @@ interface Router {
|
|||||||
export default defineNuxtPlugin<{ route: Route, router: Router }>((nuxtApp) => {
|
export default defineNuxtPlugin<{ route: Route, router: Router }>((nuxtApp) => {
|
||||||
const initialURL = process.client
|
const initialURL = process.client
|
||||||
? withoutBase(window.location.pathname, useRuntimeConfig().app.baseURL) + window.location.search + window.location.hash
|
? withoutBase(window.location.pathname, useRuntimeConfig().app.baseURL) + window.location.search + window.location.hash
|
||||||
: nuxtApp.ssrContext.url
|
: nuxtApp.ssrContext!.url
|
||||||
const routes = []
|
|
||||||
|
const routes: Route[] = []
|
||||||
|
|
||||||
const hooks: { [key in keyof RouterHooks]: RouterHooks[key][] } = {
|
const hooks: { [key in keyof RouterHooks]: RouterHooks[key][] } = {
|
||||||
'navigate:before': [],
|
'navigate:before': [],
|
||||||
@ -194,7 +194,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>((nuxtApp) => {
|
|||||||
const route = router.resolve(props.to)
|
const route = router.resolve(props.to)
|
||||||
return props.custom
|
return props.custom
|
||||||
? slots.default?.({ href: props.to, navigate, route })
|
? 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -24,7 +24,7 @@ export default defineNuxtModule<Partial<AutoImportsOptions>>({
|
|||||||
// Allow modules extending sources
|
// Allow modules extending sources
|
||||||
await nuxt.callHook('autoImports:sources', options.presets as ImportPresetWithDeprecation[])
|
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) {
|
if (typeof i !== 'string' && i.names && !i.imports) {
|
||||||
i.imports = i.names
|
i.imports = i.names
|
||||||
logger.warn('auto-imports: presets.names is deprecated, use presets.imports instead')
|
logger.warn('auto-imports: presets.names is deprecated, use presets.imports instead')
|
||||||
@ -45,10 +45,13 @@ export default defineNuxtModule<Partial<AutoImportsOptions>>({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// composables/ dirs from all layers
|
// composables/ dirs from all layers
|
||||||
let composablesDirs = []
|
let composablesDirs: string[] = []
|
||||||
for (const layer of nuxt.options._layers) {
|
for (const layer of nuxt.options._layers) {
|
||||||
composablesDirs.push(resolve(layer.config.srcDir, 'composables'))
|
composablesDirs.push(resolve(layer.config.srcDir, 'composables'))
|
||||||
for (const dir of (layer.config.autoImports?.dirs ?? [])) {
|
for (const dir of (layer.config.autoImports?.dirs ?? [])) {
|
||||||
|
if (!dir) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
composablesDirs.push(resolve(layer.config.srcDir, dir))
|
composablesDirs.push(resolve(layer.config.srcDir, dir))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +126,7 @@ function addDeclarationTemplates (ctx: Unimport) {
|
|||||||
// Remove file extension for benefit of TypeScript
|
// Remove file extension for benefit of TypeScript
|
||||||
const stripExtension = (path: string) => path.replace(/\.[a-z]+$/, '')
|
const stripExtension = (path: string) => path.replace(/\.[a-z]+$/, '')
|
||||||
|
|
||||||
const resolved = {}
|
const resolved: Record<string, string> = {}
|
||||||
const r = ({ from }: Import) => {
|
const r = ({ from }: Import) => {
|
||||||
if (resolved[from]) {
|
if (resolved[from]) {
|
||||||
return resolved[from]
|
return resolved[from]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { promises as fsp } from 'node:fs'
|
import { promises as fsp } from 'node:fs'
|
||||||
import { dirname, resolve } from 'pathe'
|
import { dirname, resolve } from 'pathe'
|
||||||
import defu from 'defu'
|
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 { findPath, resolveFiles, normalizePlugin, normalizeTemplate, compileTemplate, templateUtils, tryResolveModule, resolvePath, resolveAlias } from '@nuxt/kit'
|
||||||
|
|
||||||
import * as defaultTemplates from './templates'
|
import * as defaultTemplates from './templates'
|
||||||
@ -13,7 +13,7 @@ export function createApp (nuxt: Nuxt, options: Partial<NuxtApp> = {}): NuxtApp
|
|||||||
extensions: nuxt.options.extensions,
|
extensions: nuxt.options.extensions,
|
||||||
plugins: [],
|
plugins: [],
|
||||||
templates: []
|
templates: []
|
||||||
} as NuxtApp)
|
} as unknown as NuxtApp) as NuxtApp
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateApp (nuxt: Nuxt, app: 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)
|
await resolveApp(nuxt, app)
|
||||||
|
|
||||||
// User templates from options.build.templates
|
// 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
|
// Extend templates with hook
|
||||||
await nuxt.callHook('app:templates', app)
|
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) => {
|
await Promise.all(app.templates.map(async (template) => {
|
||||||
const contents = await compileTemplate(template, templateContext)
|
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
|
nuxt.vfs[fullPath] = contents
|
||||||
|
|
||||||
const aliasPath = '#build/' + template.filename.replace(/\.\w+$/, '')
|
const aliasPath = '#build/' + template.filename!.replace(/\.\w+$/, '')
|
||||||
nuxt.vfs[aliasPath] = contents
|
nuxt.vfs[aliasPath] = contents
|
||||||
|
|
||||||
// In case a non-normalized absolute path is called for on Windows
|
// In case a non-normalized absolute path is called for on Windows
|
||||||
@ -102,10 +102,12 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
|
|||||||
for (const config of nuxt.options._layers.map(layer => layer.config)) {
|
for (const config of nuxt.options._layers.map(layer => layer.config)) {
|
||||||
app.plugins.push(...[
|
app.plugins.push(...[
|
||||||
...(config.plugins || []),
|
...(config.plugins || []),
|
||||||
...await resolveFiles(config.srcDir, [
|
...config.srcDir
|
||||||
'plugins/*.{ts,js,mjs,cjs,mts,cts}',
|
? await resolveFiles(config.srcDir, [
|
||||||
'plugins/*/index.*{ts,js,mjs,cjs,mts,cts}'
|
'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)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,10 +15,10 @@ export async function build (nuxt: Nuxt) {
|
|||||||
nuxt.hook('builder:watch', async (event, path) => {
|
nuxt.hook('builder:watch', async (event, path) => {
|
||||||
if (event !== 'change' && /^(app\.|error\.|plugins\/|middleware\/|layouts\/)/i.test(path)) {
|
if (event !== 'change' && /^(app\.|error\.|plugins\/|middleware\/|layouts\/)/i.test(path)) {
|
||||||
if (path.startsWith('app')) {
|
if (path.startsWith('app')) {
|
||||||
app.mainComponent = null
|
app.mainComponent = undefined
|
||||||
}
|
}
|
||||||
if (path.startsWith('error')) {
|
if (path.startsWith('error')) {
|
||||||
app.errorComponent = null
|
app.errorComponent = undefined
|
||||||
}
|
}
|
||||||
await generateApp()
|
await generateApp()
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ export async function build (nuxt: Nuxt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function watch (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,
|
...nuxt.options.watchers.chokidar,
|
||||||
cwd: nuxt.options.srcDir,
|
cwd: nuxt.options.srcDir,
|
||||||
ignoreInitial: true,
|
ignoreInitial: true,
|
||||||
@ -61,7 +61,7 @@ async function bundle (nuxt: Nuxt) {
|
|||||||
: nuxt.options.builder
|
: nuxt.options.builder
|
||||||
|
|
||||||
return bundle(nuxt)
|
return bundle(nuxt)
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
await nuxt.callHook('build:error', error)
|
await nuxt.callHook('build:error', error)
|
||||||
|
|
||||||
if (error.toString().includes('Cannot find module \'@nuxt/webpack-builder\'')) {
|
if (error.toString().includes('Cannot find module \'@nuxt/webpack-builder\'')) {
|
||||||
|
@ -20,6 +20,7 @@ export const addModuleTranspiles = (opts: AddModuleTranspilesOptions = {}) => {
|
|||||||
// Try to sanitize modules to better match imports
|
// Try to sanitize modules to better match imports
|
||||||
nuxt.options.build.transpile =
|
nuxt.options.build.transpile =
|
||||||
nuxt.options.build.transpile.map(m => typeof m === 'string' ? m.split('node_modules/').pop() : m)
|
nuxt.options.build.transpile.map(m => typeof m === 'string' ? m.split('node_modules/').pop() : m)
|
||||||
|
.filter(<T>(x: T | undefined): x is T => !!x)
|
||||||
|
|
||||||
function isTranspilePresent (mod: string) {
|
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)))
|
return nuxt.options.build.transpile.some(t => !(t instanceof Function) && (t instanceof RegExp ? t.test(mod) : new RegExp(t).test(mod)))
|
||||||
|
@ -22,7 +22,7 @@ export async function initNitro (nuxt: Nuxt) {
|
|||||||
dev: nuxt.options.dev,
|
dev: nuxt.options.dev,
|
||||||
preset: nuxt.options.dev ? 'nitro-dev' : undefined,
|
preset: nuxt.options.dev ? 'nitro-dev' : undefined,
|
||||||
buildDir: nuxt.options.buildDir,
|
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'),
|
renderer: resolve(distDir, 'core/runtime/nitro/renderer'),
|
||||||
errorHandler: resolve(distDir, 'core/runtime/nitro/error'),
|
errorHandler: resolve(distDir, 'core/runtime/nitro/error'),
|
||||||
nodeModulesDirs: nuxt.options.modulesDir,
|
nodeModulesDirs: nuxt.options.modulesDir,
|
||||||
@ -49,7 +49,7 @@ export async function initNitro (nuxt: Nuxt) {
|
|||||||
],
|
],
|
||||||
prerender: {
|
prerender: {
|
||||||
crawlLinks: nuxt.options._generate ? nuxt.options.generate.crawler : false,
|
crawlLinks: nuxt.options._generate ? nuxt.options.generate.crawler : false,
|
||||||
routes: []
|
routes: ([] as string[])
|
||||||
.concat(nuxt.options._generate ? ['/', ...nuxt.options.generate.routes] : [])
|
.concat(nuxt.options._generate ? ['/', ...nuxt.options.generate.routes] : [])
|
||||||
.concat(nuxt.options.ssr === false ? ['/', '/200.html', '/404.html'] : [])
|
.concat(nuxt.options.ssr === false ? ['/', '/200.html', '/404.html'] : [])
|
||||||
},
|
},
|
||||||
@ -102,11 +102,11 @@ export async function initNitro (nuxt: Nuxt) {
|
|||||||
|
|
||||||
// Add fallback server for `ssr: false`
|
// Add fallback server for `ssr: false`
|
||||||
if (!nuxt.options.ssr) {
|
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
|
// Register nuxt protection patterns
|
||||||
nitroConfig.rollupConfig.plugins.push(ImportProtectionPlugin.rollup({
|
nitroConfig.rollupConfig!.plugins!.push(ImportProtectionPlugin.rollup({
|
||||||
rootDir: nuxt.options.rootDir,
|
rootDir: nuxt.options.rootDir,
|
||||||
patterns: [
|
patterns: [
|
||||||
...['#app', /^#build(\/|$)/]
|
...['#app', /^#build(\/|$)/]
|
||||||
|
@ -81,7 +81,7 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
|
|
||||||
// Transpile layers within node_modules
|
// Transpile layers within node_modules
|
||||||
nuxt.options.build.transpile.push(
|
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.includes('node_modules')).map(i => i.cwd as string)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init user modules
|
// Init user modules
|
||||||
@ -95,7 +95,7 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
// Add <NuxtWelcome>
|
// Add <NuxtWelcome>
|
||||||
addComponent({
|
addComponent({
|
||||||
name: 'NuxtWelcome',
|
name: 'NuxtWelcome',
|
||||||
filePath: tryResolveModule('@nuxt/ui-templates/templates/welcome.vue')
|
filePath: tryResolveModule('@nuxt/ui-templates/templates/welcome.vue')!
|
||||||
})
|
})
|
||||||
|
|
||||||
addComponent({
|
addComponent({
|
||||||
@ -165,7 +165,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
|
|||||||
transform: {
|
transform: {
|
||||||
include: options._layers
|
include: options._layers
|
||||||
.filter(i => i.cwd && i.cwd.includes('node_modules'))
|
.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'))
|
options.modulesDir.push(resolve(pkgDir, 'node_modules'))
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
import { withQuery } from 'ufo'
|
import { withQuery } from 'ufo'
|
||||||
import type { NitroErrorHandler } from 'nitropack'
|
import type { NitroErrorHandler } from 'nitropack'
|
||||||
import type { H3Error } from 'h3'
|
import type { H3Error } from 'h3'
|
||||||
// @ts-ignore TODO
|
|
||||||
import { normalizeError, isJsonRequest } from '#internal/nitro/utils'
|
import { normalizeError, isJsonRequest } from '#internal/nitro/utils'
|
||||||
import { NuxtApp } from '#app'
|
|
||||||
|
|
||||||
export default <NitroErrorHandler> async function errorhandler (error: H3Error, event) {
|
export default <NitroErrorHandler> async function errorhandler (error: H3Error, event) {
|
||||||
// Parse and normalize error
|
// Parse and normalize error
|
||||||
const { stack, statusCode, statusMessage, message } = normalizeError(error)
|
const { stack, statusCode, statusMessage, message } = normalizeError(error)
|
||||||
|
|
||||||
// Create an error object
|
// Create an error object
|
||||||
const errorObject: Exclude<NuxtApp['payload']['error'], Error> = {
|
const errorObject = {
|
||||||
url: event.req.url,
|
url: event.req.url,
|
||||||
statusCode,
|
statusCode,
|
||||||
statusMessage,
|
statusMessage,
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
import { createRenderer } from 'vue-bundle-renderer/runtime'
|
import { createRenderer } from 'vue-bundle-renderer/runtime'
|
||||||
import type { RenderHandler, RenderResponse } from 'nitropack'
|
import type { RenderResponse } from 'nitropack'
|
||||||
import type { Manifest } from 'vite'
|
import type { Manifest } from 'vite'
|
||||||
import { CompatibilityEvent, getQuery } from 'h3'
|
import { getQuery } from 'h3'
|
||||||
import devalue from '@nuxt/devalue'
|
import devalue from '@nuxt/devalue'
|
||||||
import { renderToString as _renderToString } from 'vue/server-renderer'
|
import { renderToString as _renderToString } from 'vue/server-renderer'
|
||||||
import type { NuxtApp } from '#app'
|
import type { NuxtApp, NuxtSSRContext } from '#app'
|
||||||
|
import { useRuntimeConfig, useNitroApp, defineRenderHandler } from '#internal/nitro'
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
import { useRuntimeConfig, useNitroApp, defineRenderHandler as _defineRenderHandler } from '#internal/nitro'
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { buildAssetsURL } from '#paths'
|
import { buildAssetsURL } from '#paths'
|
||||||
|
|
||||||
export type NuxtSSRContext = NuxtApp['ssrContext']
|
|
||||||
|
|
||||||
const defineRenderHandler = _defineRenderHandler as (h: RenderHandler) => CompatibilityEvent
|
|
||||||
|
|
||||||
export interface NuxtRenderHTMLContext {
|
export interface NuxtRenderHTMLContext {
|
||||||
htmlAttrs: string[]
|
htmlAttrs: string[]
|
||||||
head: string[]
|
head: string[]
|
||||||
@ -31,10 +26,12 @@ export interface NuxtRenderResponse {
|
|||||||
headers: Record<string, string>
|
headers: Record<string, string>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ClientManifest {}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const getClientManifest: () => Promise<Manifest> = () => import('#build/dist/server/client.manifest.mjs')
|
const getClientManifest: () => Promise<Manifest> = () => import('#build/dist/server/client.manifest.mjs')
|
||||||
.then(r => r.default || r)
|
.then(r => r.default || r)
|
||||||
.then(r => typeof r === 'function' ? r() : r)
|
.then(r => typeof r === 'function' ? r() : r) as Promise<ClientManifest>
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const getServerEntry = () => import('#build/dist/server/server.mjs').then(r => r.default || r)
|
const getServerEntry = () => import('#build/dist/server/server.mjs').then(r => r.default || r)
|
||||||
@ -57,7 +54,8 @@ const getSSRRenderer = lazyCachedFunction(async () => {
|
|||||||
// Create renderer
|
// Create renderer
|
||||||
const renderer = createRenderer(createSSRApp, options)
|
const renderer = createRenderer(createSSRApp, options)
|
||||||
|
|
||||||
async function renderToString (input, context) {
|
type RenderToStringParams = Parameters<typeof _renderToString>
|
||||||
|
async function renderToString (input: RenderToStringParams[0], context: RenderToStringParams[1]) {
|
||||||
const html = await _renderToString(input, context)
|
const html = await _renderToString(input, context)
|
||||||
// In development with vite-node, the manifest is on-demand and will be available after rendering
|
// 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) {
|
if (process.dev && process.env.NUXT_VITE_NODE_OPTIONS) {
|
||||||
@ -84,14 +82,16 @@ const getSPARenderer = lazyCachedFunction(async () => {
|
|||||||
|
|
||||||
const renderToString = (ssrContext: NuxtSSRContext) => {
|
const renderToString = (ssrContext: NuxtSSRContext) => {
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
ssrContext.payload = {
|
ssrContext!.payload = {
|
||||||
serverRendered: false,
|
serverRendered: false,
|
||||||
config: {
|
config: {
|
||||||
public: config.public,
|
public: config.public,
|
||||||
app: config.app
|
app: config.app
|
||||||
}
|
},
|
||||||
|
data: {},
|
||||||
|
state: {}
|
||||||
}
|
}
|
||||||
ssrContext.renderMeta = ssrContext.renderMeta ?? (() => ({}))
|
ssrContext!.renderMeta = ssrContext!.renderMeta ?? (() => ({}))
|
||||||
return Promise.resolve(result)
|
return Promise.resolve(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,23 +109,25 @@ export default defineRenderHandler(async (event) => {
|
|||||||
event,
|
event,
|
||||||
req: event.req,
|
req: event.req,
|
||||||
res: event.res,
|
res: event.res,
|
||||||
runtimeConfig: useRuntimeConfig(),
|
runtimeConfig: useRuntimeConfig() as NuxtSSRContext['runtimeConfig'],
|
||||||
noSSR: !!event.req.headers['x-nuxt-no-ssr'],
|
noSSR: !!event.req.headers['x-nuxt-no-ssr'],
|
||||||
error: !!ssrError,
|
error: !!ssrError,
|
||||||
nuxt: undefined, /* NuxtApp */
|
nuxt: undefined!, /* NuxtApp */
|
||||||
payload: ssrError ? { error: ssrError } : undefined
|
payload: ssrError ? { error: ssrError } as NuxtSSRContext['payload'] : undefined!
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render app
|
// Render app
|
||||||
const renderer = (process.env.NUXT_NO_SSR || ssrContext.noSSR) ? await getSPARenderer() : await getSSRRenderer()
|
const renderer = (process.env.NUXT_NO_SSR || ssrContext.noSSR) ? await getSPARenderer() : await getSSRRenderer()
|
||||||
const _rendered = await renderer.renderToString(ssrContext).catch((err) => {
|
const _rendered = await renderer.renderToString(ssrContext).catch((err) => {
|
||||||
if (!ssrError) { throw err }
|
if (!ssrError) {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
})
|
})
|
||||||
await ssrContext.nuxt?.hooks.callHook('app:rendered', { ssrContext })
|
await ssrContext.nuxt?.hooks.callHook('app:rendered', { ssrContext })
|
||||||
|
|
||||||
// Handle errors
|
// Handle errors
|
||||||
if (!_rendered) {
|
if (!_rendered) {
|
||||||
return
|
return undefined!
|
||||||
}
|
}
|
||||||
if (ssrContext.payload?.error && !ssrError) {
|
if (ssrContext.payload?.error && !ssrError) {
|
||||||
throw ssrContext.payload.error
|
throw ssrContext.payload.error
|
||||||
@ -143,7 +145,7 @@ export default defineRenderHandler(async (event) => {
|
|||||||
_rendered.renderStyles(),
|
_rendered.renderStyles(),
|
||||||
ssrContext.styles
|
ssrContext.styles
|
||||||
]),
|
]),
|
||||||
bodyAttrs: normalizeChunks([renderedMeta.bodyAttrs]),
|
bodyAttrs: normalizeChunks([renderedMeta.bodyAttrs!]),
|
||||||
bodyPreprend: normalizeChunks([
|
bodyPreprend: normalizeChunks([
|
||||||
renderedMeta.bodyScriptsPrepend,
|
renderedMeta.bodyScriptsPrepend,
|
||||||
ssrContext.teleports?.body
|
ssrContext.teleports?.body
|
||||||
@ -188,8 +190,8 @@ function lazyCachedFunction <T> (fn: () => Promise<T>): () => Promise<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeChunks (chunks: string[]) {
|
function normalizeChunks (chunks: (string | undefined)[]) {
|
||||||
return chunks.filter(Boolean).map(i => i.trim())
|
return chunks.filter(Boolean).map(i => i!.trim())
|
||||||
}
|
}
|
||||||
|
|
||||||
function joinTags (tags: string[]) {
|
function joinTags (tags: string[]) {
|
||||||
|
@ -11,7 +11,7 @@ export interface TemplateContext {
|
|||||||
app: NuxtApp
|
app: NuxtApp
|
||||||
}
|
}
|
||||||
|
|
||||||
export const vueShim = {
|
export const vueShim: NuxtTemplate = {
|
||||||
filename: 'types/vue-shim.d.ts',
|
filename: 'types/vue-shim.d.ts',
|
||||||
getContents: () =>
|
getContents: () =>
|
||||||
[
|
[
|
||||||
@ -24,29 +24,29 @@ export const vueShim = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use an alias
|
// TODO: Use an alias
|
||||||
export const appComponentTemplate = {
|
export const appComponentTemplate: NuxtTemplate<TemplateContext> = {
|
||||||
filename: 'app-component.mjs',
|
filename: 'app-component.mjs',
|
||||||
getContents: (ctx: TemplateContext) => genExport(ctx.app.mainComponent, ['default'])
|
getContents: ctx => genExport(ctx.app.mainComponent!, ['default'])
|
||||||
}
|
}
|
||||||
// TODO: Use an alias
|
// TODO: Use an alias
|
||||||
export const rootComponentTemplate = {
|
export const rootComponentTemplate: NuxtTemplate<TemplateContext> = {
|
||||||
filename: 'root-component.mjs',
|
filename: 'root-component.mjs',
|
||||||
getContents: (ctx: TemplateContext) => genExport(ctx.app.rootComponent, ['default'])
|
getContents: ctx => genExport(ctx.app.rootComponent!, ['default'])
|
||||||
}
|
}
|
||||||
// TODO: Use an alias
|
// TODO: Use an alias
|
||||||
export const errorComponentTemplate = {
|
export const errorComponentTemplate: NuxtTemplate<TemplateContext> = {
|
||||||
filename: 'error-component.mjs',
|
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<TemplateContext> = {
|
||||||
filename: 'css.mjs',
|
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<TemplateContext> = {
|
||||||
filename: 'plugins/client.mjs',
|
filename: 'plugins/client.mjs',
|
||||||
getContents (ctx: TemplateContext) {
|
getContents (ctx) {
|
||||||
const clientPlugins = ctx.app.plugins.filter(p => !p.mode || p.mode !== 'server')
|
const clientPlugins = ctx.app.plugins.filter(p => !p.mode || p.mode !== 'server')
|
||||||
const exports: string[] = []
|
const exports: string[] = []
|
||||||
const imports: string[] = []
|
const imports: string[] = []
|
||||||
@ -63,9 +63,9 @@ export const clientPluginTemplate = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const serverPluginTemplate = {
|
export const serverPluginTemplate: NuxtTemplate<TemplateContext> = {
|
||||||
filename: 'plugins/server.mjs',
|
filename: 'plugins/server.mjs',
|
||||||
getContents (ctx: TemplateContext) {
|
getContents (ctx) {
|
||||||
const serverPlugins = ctx.app.plugins.filter(p => !p.mode || p.mode !== 'client')
|
const serverPlugins = ctx.app.plugins.filter(p => !p.mode || p.mode !== 'client')
|
||||||
const exports: string[] = ['preload']
|
const exports: string[] = ['preload']
|
||||||
const imports: string[] = ["import preload from '#app/plugins/preload.server'"]
|
const imports: string[] = ["import preload from '#app/plugins/preload.server'"]
|
||||||
@ -82,9 +82,9 @@ export const serverPluginTemplate = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const pluginsDeclaration = {
|
export const pluginsDeclaration: NuxtTemplate<TemplateContext> = {
|
||||||
filename: 'types/plugins.d.ts',
|
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 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, ''))
|
const tsImports = ctx.app.plugins.map(p => (isAbsolute(p.src) ? relative(join(ctx.nuxt.options.buildDir, 'types'), p.src) : p.src).replace(EXTENSION_RE, ''))
|
||||||
|
|
||||||
@ -111,9 +111,9 @@ export { }
|
|||||||
}
|
}
|
||||||
|
|
||||||
const adHocModules = ['router', 'pages', 'auto-imports', 'meta', 'components']
|
const adHocModules = ['router', 'pages', 'auto-imports', 'meta', 'components']
|
||||||
export const schemaTemplate = {
|
export const schemaTemplate: NuxtTemplate<TemplateContext> = {
|
||||||
filename: 'types/schema.d.ts',
|
filename: 'types/schema.d.ts',
|
||||||
getContents: ({ nuxt }: TemplateContext) => {
|
getContents: ({ nuxt }) => {
|
||||||
const moduleInfo = nuxt.options._installedModules.map(m => ({
|
const moduleInfo = nuxt.options._installedModules.map(m => ({
|
||||||
...m.meta || {},
|
...m.meta || {},
|
||||||
importName: m.entryPath || m.meta?.name
|
importName: m.entryPath || m.meta?.name
|
||||||
@ -149,9 +149,9 @@ export const schemaTemplate = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add layouts template
|
// Add layouts template
|
||||||
export const layoutTemplate: NuxtTemplate = {
|
export const layoutTemplate: NuxtTemplate<TemplateContext> = {
|
||||||
filename: 'layouts.mjs',
|
filename: 'layouts.mjs',
|
||||||
getContents ({ app }: TemplateContext) {
|
getContents ({ app }) {
|
||||||
const layoutsObject = genObjectFromRawEntries(Object.values(app.layouts).map(({ name, file }) => {
|
const layoutsObject = genObjectFromRawEntries(Object.values(app.layouts).map(({ name, file }) => {
|
||||||
return [name, `defineAsyncComponent(${genDynamicImport(file)})`]
|
return [name, `defineAsyncComponent(${genDynamicImport(file)})`]
|
||||||
}))
|
}))
|
||||||
@ -163,9 +163,9 @@ export const layoutTemplate: NuxtTemplate = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add middleware template
|
// Add middleware template
|
||||||
export const middlewareTemplate: NuxtTemplate = {
|
export const middlewareTemplate: NuxtTemplate<TemplateContext> = {
|
||||||
filename: 'middleware.mjs',
|
filename: 'middleware.mjs',
|
||||||
getContents ({ app }: TemplateContext) {
|
getContents ({ app }) {
|
||||||
const globalMiddleware = app.middleware.filter(mw => mw.global)
|
const globalMiddleware = app.middleware.filter(mw => mw.global)
|
||||||
const namedMiddleware = 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)]))
|
const namedMiddlewareObject = genObjectFromRawEntries(namedMiddleware.map(mw => [mw.name, genDynamicImport(mw.path)]))
|
||||||
@ -184,7 +184,7 @@ export const useRuntimeConfig = () => window?.__NUXT__?.config || {}
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const publicPathTemplate: NuxtTemplate = {
|
export const publicPathTemplate: NuxtTemplate<TemplateContext> = {
|
||||||
filename: 'paths.mjs',
|
filename: 'paths.mjs',
|
||||||
getContents ({ nuxt }) {
|
getContents ({ nuxt }) {
|
||||||
return [
|
return [
|
||||||
|
@ -20,20 +20,20 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process.server) {
|
if (process.server) {
|
||||||
nuxtApp.ssrContext.renderMeta = async () => {
|
nuxtApp.ssrContext!.renderMeta = async () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const { renderMetaToString } = await import('vue-meta/ssr')
|
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)
|
await renderMetaToString(nuxtApp.app, nuxtApp.ssrContext)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
htmlAttrs: nuxtApp.ssrContext.teleports.htmlAttrs || '',
|
htmlAttrs: nuxtApp.ssrContext!.teleports.htmlAttrs || '',
|
||||||
headAttrs: nuxtApp.ssrContext.teleports.headAttrs || '',
|
headAttrs: nuxtApp.ssrContext!.teleports.headAttrs || '',
|
||||||
bodyAttrs: nuxtApp.ssrContext.teleports.bodyAttrs || '',
|
bodyAttrs: nuxtApp.ssrContext!.teleports.bodyAttrs || '',
|
||||||
headTags: nuxtApp.ssrContext.teleports.head || '',
|
headTags: nuxtApp.ssrContext!.teleports.head || '',
|
||||||
bodyScriptsPrepend: nuxtApp.ssrContext.teleports['body-prepend'] || '',
|
bodyScriptsPrepend: nuxtApp.ssrContext!.teleports['body-prepend'] || '',
|
||||||
bodyScripts: nuxtApp.ssrContext.teleports.body || ''
|
bodyScripts: nuxtApp.ssrContext!.teleports.body || ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (process.server) {
|
if (process.server) {
|
||||||
nuxtApp.ssrContext.renderMeta = () => {
|
nuxtApp.ssrContext!.renderMeta = () => {
|
||||||
const meta = renderHeadToString(head)
|
const meta = renderHeadToString(head)
|
||||||
return {
|
return {
|
||||||
...meta,
|
...meta,
|
||||||
|
@ -34,6 +34,6 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
|
|
||||||
for (const name in Components) {
|
for (const name in Components) {
|
||||||
// eslint-disable-next-line import/namespace
|
// eslint-disable-next-line import/namespace
|
||||||
nuxtApp.vueApp.component(name, Components[name])
|
nuxtApp.vueApp.component(name, (Components as any)[name])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -47,7 +47,7 @@ export default defineNuxtModule({
|
|||||||
|
|
||||||
nuxt.hook('app:resolve', (app) => {
|
nuxt.hook('app:resolve', (app) => {
|
||||||
// Add default layout for pages
|
// 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')
|
app.mainComponent = resolve(runtimeDir, 'app.vue')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { computed, DefineComponent, defineComponent, h, inject, provide, reactive, Suspense, Transition } from 'vue'
|
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 { generateRouteKey, RouterViewSlotProps, wrapInKeepAlive } from './utils'
|
||||||
import { useNuxtApp } from '#app'
|
import { useNuxtApp } from '#app'
|
||||||
@ -58,6 +58,7 @@ export default defineComponent({
|
|||||||
const defaultPageTransition = { name: 'page', mode: 'out-in' }
|
const defaultPageTransition = { name: 'page', mode: 'out-in' }
|
||||||
|
|
||||||
const Component = defineComponent({
|
const Component = defineComponent({
|
||||||
|
// TODO: Type props
|
||||||
// eslint-disable-next-line vue/require-prop-types
|
// eslint-disable-next-line vue/require-prop-types
|
||||||
props: ['routeProps', 'pageKey'],
|
props: ['routeProps', 'pageKey'],
|
||||||
setup (props) {
|
setup (props) {
|
||||||
@ -66,9 +67,9 @@ const Component = defineComponent({
|
|||||||
const previousRoute = props.routeProps.route
|
const previousRoute = props.routeProps.route
|
||||||
|
|
||||||
// Provide a reactive route within the page
|
// Provide a reactive route within the page
|
||||||
const route = {}
|
const route = {} as RouteLocation
|
||||||
for (const key in props.routeProps.route) {
|
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))
|
provide('_route', reactive(route))
|
||||||
|
@ -59,7 +59,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
|||||||
? createWebHistory(baseURL)
|
? createWebHistory(baseURL)
|
||||||
: createMemoryHistory(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({
|
const router = createRouter({
|
||||||
...routerOptions,
|
...routerOptions,
|
||||||
history: routerHistory,
|
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
|
// 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) {
|
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)
|
nuxtApp._route = reactive(route)
|
||||||
@ -109,7 +109,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await router.isReady()
|
await router.isReady()
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
// We'll catch 404s here
|
// We'll catch 404s here
|
||||||
callWithNuxt(nuxtApp, showError, [error])
|
callWithNuxt(nuxtApp, showError, [error])
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const entry of middlewareEntries) {
|
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 (!middleware) {
|
||||||
if (process.dev) {
|
if (process.dev) {
|
||||||
@ -169,7 +169,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
|||||||
statusMessage: `Page not found: ${to.fullPath}`
|
statusMessage: `Page not found: ${to.fullPath}`
|
||||||
})])
|
})])
|
||||||
} else if (process.server && to.matched[0].name === '404' && nuxtApp.ssrContext) {
|
} 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) {
|
} else if (process.server) {
|
||||||
const currentURL = to.fullPath || '/'
|
const currentURL = to.fullPath || '/'
|
||||||
if (!isEqual(currentURL, initialURL)) {
|
if (!isEqual(currentURL, initialURL)) {
|
||||||
@ -185,7 +185,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
|||||||
name: undefined, // #4920, #$4982
|
name: undefined, // #4920, #$4982
|
||||||
force: true
|
force: true
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
// We'll catch middleware errors or deliberate exceptions here
|
// We'll catch middleware errors or deliberate exceptions here
|
||||||
callWithNuxt(nuxtApp, showError, [error])
|
callWithNuxt(nuxtApp, showError, [error])
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ const interpolatePath = (route: RouteLocationNormalizedLoaded, match: RouteLocat
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const generateRouteKey = (override: string | ((route: RouteLocationNormalizedLoaded) => string), routeProps: RouterViewSlotProps) => {
|
export const generateRouteKey = (override: string | ((route: RouteLocationNormalizedLoaded) => string), routeProps: RouterViewSlotProps) => {
|
||||||
const matchedRoute = routeProps.route.matched.find(m => m.components.default === routeProps.Component.type)
|
const matchedRoute = routeProps.route.matched.find(m => m.components?.default === routeProps.Component.type)
|
||||||
const source = override ?? matchedRoute?.meta.key ?? interpolatePath(routeProps.route, matchedRoute)
|
const source = override ?? matchedRoute?.meta.key ?? (matchedRoute && interpolatePath(routeProps.route, matchedRoute))
|
||||||
return typeof source === 'function' ? source(routeProps.route) : source
|
return typeof source === 'function' ? source(routeProps.route) : source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ export function generateRoutesFromFiles (files: string[], pagesDir: string): Nux
|
|||||||
// ex: parent.vue + parent/child.vue
|
// ex: parent.vue + parent/child.vue
|
||||||
const child = parent.find(parentRoute => parentRoute.name === route.name && !parentRoute.path.endsWith('(.*)*'))
|
const child = parent.find(parentRoute => parentRoute.name === route.name && !parentRoute.path.endsWith('(.*)*'))
|
||||||
|
|
||||||
if (child) {
|
if (child && child.children) {
|
||||||
parent = child.children
|
parent = child.children
|
||||||
route.path = ''
|
route.path = ''
|
||||||
} else if (segmentName === '404' && isSingleSegment) {
|
} else if (segmentName === '404' && isSingleSegment) {
|
||||||
@ -213,11 +213,11 @@ function prepareRoutes (routes: NuxtPage[], parent?: NuxtPage) {
|
|||||||
route.path = route.path.slice(1)
|
route.path = route.path.slice(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.children.length) {
|
if (route.children?.length) {
|
||||||
route.children = prepareRoutes(route.children, route)
|
route.children = prepareRoutes(route.children, route)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.children.find(childRoute => childRoute.path === '')) {
|
if (route.children?.find(childRoute => childRoute.path === '')) {
|
||||||
delete route.name
|
delete route.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ vi.mock('vue', async () => {
|
|||||||
return {
|
return {
|
||||||
...vue,
|
...vue,
|
||||||
resolveComponent: (name: string) => name,
|
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 }) })
|
useRouter: () => ({ resolve: ({ to }: { to: string }) => ({ href: to }) })
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Helpers for test lisibility
|
// Helpers for test visibility
|
||||||
const EXTERNAL = 'a'
|
const EXTERNAL = 'a'
|
||||||
const INTERNAL = 'RouterLink'
|
const INTERNAL = 'RouterLink'
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ describe('nuxt-link:to', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('renders link with `to` prop and warns about `href` prop conflict', () => {
|
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')
|
expect(nuxtLink({ to: '/to', href: '/href' }).props.to).toBe('/to')
|
||||||
// TODO: Uncomment when `dev` mode for tests is available
|
// 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', () => {
|
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)
|
expect(nuxtLink({ to: 'https://nuxtjs.org', noRel: true, rel: 'foo' }).props.rel).toBe(null)
|
||||||
// TODO: Uncomment when `dev` mode for tests is available
|
// TODO: Uncomment when `dev` mode for tests is available
|
||||||
|
11
packages/nuxt/tsconfig.json
Normal file
11
packages/nuxt/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitAny": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/**/*.ts",
|
||||||
|
"./test/**/*.ts"
|
||||||
|
]
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
import { ConfigSchema } from '../../schema/config'
|
import { ConfigSchema } from '../../schema/config'
|
||||||
import type { ResolvedConfig } from 'c12'
|
|
||||||
import type { UserConfig as ViteUserConfig } from 'vite'
|
import type { UserConfig as ViteUserConfig } from 'vite'
|
||||||
import type { Options as VuePluginOptions } from '@vitejs/plugin-vue'
|
import type { Options as VuePluginOptions } from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
@ -12,9 +11,20 @@ export interface NuxtConfig extends DeepPartial<Omit<ConfigSchema, 'vite'>> {
|
|||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Expose ConfigLayer<T> from c12
|
||||||
|
interface ConfigLayer<T> {
|
||||||
|
config: T;
|
||||||
|
cwd: string;
|
||||||
|
configFile: string
|
||||||
|
}
|
||||||
|
export type NuxtConfigLayer = ConfigLayer<NuxtConfig & {
|
||||||
|
srcDir: ConfigSchema['srcDir'],
|
||||||
|
rootDir: ConfigSchema['rootDir']
|
||||||
|
}>
|
||||||
|
|
||||||
/** Normalized Nuxt options available as `nuxt.options.*` */
|
/** Normalized Nuxt options available as `nuxt.options.*` */
|
||||||
export interface NuxtOptions extends ConfigSchema {
|
export interface NuxtOptions extends ConfigSchema {
|
||||||
_layers: ResolvedConfig<NuxtConfig>[]
|
_layers: NuxtConfigLayer[]
|
||||||
}
|
}
|
||||||
|
|
||||||
type RuntimeConfigNamespace = Record<string, any>
|
type RuntimeConfigNamespace = Record<string, any>
|
||||||
|
@ -24,7 +24,7 @@ export interface Nuxt {
|
|||||||
vfs: Record<string, string>
|
vfs: Record<string, string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NuxtTemplate {
|
export interface NuxtTemplate<Options = Record<string, any>> {
|
||||||
/** @deprecated filename */
|
/** @deprecated filename */
|
||||||
fileName?: string
|
fileName?: string
|
||||||
/** @deprecated whether template is custom or a nuxt core template */
|
/** @deprecated whether template is custom or a nuxt core template */
|
||||||
@ -51,9 +51,9 @@ export interface NuxtPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface NuxtApp {
|
export interface NuxtApp {
|
||||||
mainComponent?: string
|
mainComponent?: string | null
|
||||||
rootComponent?: string
|
rootComponent?: string | null
|
||||||
errorComponent?: string
|
errorComponent?: string | null
|
||||||
dir: string
|
dir: string
|
||||||
extensions: string[]
|
extensions: string[]
|
||||||
plugins: NuxtPlugin[]
|
plugins: NuxtPlugin[]
|
||||||
|
2
test/fixtures/basic/types.ts
vendored
2
test/fixtures/basic/types.ts
vendored
@ -4,8 +4,8 @@ import type { Ref } from 'vue'
|
|||||||
|
|
||||||
import { NavigationFailure, RouteLocationNormalizedLoaded, RouteLocationRaw, useRouter as vueUseRouter } from 'vue-router'
|
import { NavigationFailure, RouteLocationNormalizedLoaded, RouteLocationRaw, useRouter as vueUseRouter } from 'vue-router'
|
||||||
import { defineNuxtConfig } from '~~/../../../packages/nuxt/src'
|
import { defineNuxtConfig } from '~~/../../../packages/nuxt/src'
|
||||||
import { useRouter } from '#imports'
|
|
||||||
import { isVue3 } from '#app'
|
import { isVue3 } from '#app'
|
||||||
|
import { useRouter } from '#imports'
|
||||||
|
|
||||||
interface TestResponse { message: string }
|
interface TestResponse { message: string }
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
"moduleResolution": "Node",
|
"moduleResolution": "Node",
|
||||||
"strict": false,
|
"strict": false,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
"noEmit": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"types": [
|
"types": [
|
||||||
@ -23,6 +24,12 @@
|
|||||||
"#head": [
|
"#head": [
|
||||||
"./packages/nuxt/src/head/runtime/index"
|
"./packages/nuxt/src/head/runtime/index"
|
||||||
],
|
],
|
||||||
|
"#internal/nitro": [
|
||||||
|
"./node_modules/nitropack/dist/runtime"
|
||||||
|
],
|
||||||
|
"#internal/nitro/utils": [
|
||||||
|
"./node_modules/nitropack/dist/runtime/utils"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
Loading…
Reference in New Issue
Block a user