chore: add back stylistic rules and lint project

This commit is contained in:
Daniel Roe 2024-03-09 06:48:15 +00:00
parent 3782ac0a2c
commit 7252b56d52
78 changed files with 435 additions and 303 deletions

View File

@ -12,11 +12,67 @@
},
"plugins": ["jsdoc", "import", "unicorn", "no-only-tests"],
"extends": [
"standard",
"plugin:jsdoc/recommended",
"@nuxt/eslint-config",
"plugin:import/typescript"
],
"rules": {
// Imports should come first
"import/first": "error",
// Other import rules
"import/no-mutable-exports": "error",
// Allow unresolved imports
"import/no-unresolved": "off",
// Allow paren-less arrow functions only when there's no braces
"arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }],
// Allow async-await
"generator-star-spacing": "off",
// Prefer const over let
"prefer-const": ["error", { "destructuring": "any", "ignoreReadBeforeAssign": false }],
// No single if in an "else" block
"no-lonely-if": "error",
// Force curly braces for control flow,
// including if blocks with a single statement
"curly": ["error", "all"
],
// No async function without await
"require-await": "error",
// Force dot notation when possible
"dot-notation": "error",
"no-var": "error",
// Force object shorthand where possible
"object-shorthand": "error",
// No useless destructuring/importing/exporting renames
"no-useless-rename": "error",
/**********************/
/* Unicorn Rules */
/**********************/
// Pass error message when throwing errors
"unicorn/error-message": "error",
// Uppercase regex escapes
"unicorn/escape-case": "error",
// Array.isArray instead of instanceof
"unicorn/no-array-instanceof": "error",
// Prevent deprecated `new Buffer()`
"unicorn/no-new-buffer": "error",
// Keep regex literals safe!
"unicorn/no-unsafe-regex": "off",
// Lowercase number formatting for octal, hex, binary (0x12 instead of 0X12)
"unicorn/number-literal-case": "error",
// ** instead of Math.pow()
"unicorn/prefer-exponentiation-operator": "error",
// includes over indexOf when checking for existence
"unicorn/prefer-includes": "error",
// String methods startsWith/endsWith instead of more complicated stuff
"unicorn/prefer-starts-ends-with": "error",
// textContent instead of innerText
"unicorn/prefer-text-content": "error",
// Enforce throwing type error when throwing error while checking typeof
"unicorn/prefer-type-error": "error",
// Use new when throwing error
"unicorn/throw-new-error": "error",
"sort-imports": [
"error",
{

View File

@ -9,8 +9,8 @@ export default defineNuxtConfig({
function () {
addPluginTemplate({
filename: 'plugins/my-plugin.mjs',
getContents: () => `export default defineNuxtPlugin({ name: 'my-plugin' })`
getContents: () => 'export default defineNuxtPlugin({ name: \'my-plugin\' })'
})
}
],
]
})

View File

@ -60,6 +60,7 @@
"consola": "3.2.3",
"devalue": "4.3.2",
"eslint": "8.57.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "48.2.1",
"eslint-plugin-no-only-tests": "3.1.0",

View File

@ -9,7 +9,7 @@ import { toArray } from '../utils'
/** @deprecated */
// TODO: Remove support for compiling ejs templates in v4
export async function compileTemplate <T>(template: NuxtTemplate<T>, ctx: any) {
export async function compileTemplate <T> (template: NuxtTemplate<T>, ctx: any) {
const data = { ...ctx, options: template.options }
if (template.src) {
try {

View File

@ -3,13 +3,13 @@ import { describe, expect, it, vi } from 'vitest'
import { consola } from 'consola'
import { logger, useLogger } from './logger'
vi.mock("consola", () => {
const logger = {} as any;
vi.mock('consola', () => {
const logger = {} as any
logger.create = vi.fn(() => ({...logger}));
logger.withTag = vi.fn(() => ({...logger}));
return { consola: logger };
logger.create = vi.fn(() => ({ ...logger }))
logger.withTag = vi.fn(() => ({ ...logger }))
return { consola: logger }
})
describe('logger', () => {
@ -20,29 +20,28 @@ describe('logger', () => {
describe('useLogger', () => {
it('should expose consola when not passing a tag', () => {
expect(useLogger()).toBe(consola);
});
expect(useLogger()).toBe(consola)
})
it('should create a new instance when passing a tag', () => {
const logger = vi.mocked(consola);
const instance = useLogger("tag");
const logger = vi.mocked(consola)
expect(instance).toEqual(logger);
expect(instance).not.toBe(logger);
expect(logger.create).toBeCalledWith({});
expect(logger.withTag).toBeCalledWith("tag");
});
const instance = useLogger('tag')
expect(instance).toEqual(logger)
expect(instance).not.toBe(logger)
expect(logger.create).toBeCalledWith({})
expect(logger.withTag).toBeCalledWith('tag')
})
it('should create a new instance when passing a tag and options', () => {
const logger = vi.mocked(consola);
const instance = useLogger("tag", { level: 0 });
const logger = vi.mocked(consola)
expect(instance).toEqual(logger);
expect(instance).not.toBe(logger);
expect(logger.create).toBeCalledWith({ level: 0 });
expect(logger.withTag).toBeCalledWith("tag");
});
const instance = useLogger('tag', { level: 0 })
expect(instance).toEqual(logger)
expect(instance).not.toBe(logger)
expect(logger.create).toBeCalledWith({ level: 0 })
expect(logger.withTag).toBeCalledWith('tag')
})
})

View File

@ -1,5 +1,5 @@
import { consola } from 'consola'
import type { ConsolaOptions } from 'consola';
import type { ConsolaOptions } from 'consola'
export const logger = consola

View File

@ -22,9 +22,9 @@ const mockNuxt = {
modules: [],
_layers: [{ config: { srcDir: '/my-app' } }],
_installedModules: [],
_modules: [],
_modules: []
},
callHook: () => {},
callHook: () => {}
} satisfies DeepPartial<Nuxt> as unknown as Nuxt
const mockNuxtWithOptions = (options: NuxtConfig) => defu({ options }, mockNuxt) as Nuxt

View File

@ -9,7 +9,7 @@ const fixtures = {
'basic test fixture': 'test/fixtures/basic',
'basic test fixture (types)': 'test/fixtures/basic-types',
'minimal test fixture': 'test/fixtures/minimal',
'minimal test fixture (types)': 'test/fixtures/minimal-types',
'minimal test fixture (types)': 'test/fixtures/minimal-types'
}
describe('loadNuxtConfig', () => {

View File

@ -2,13 +2,15 @@ import { createError } from '../composables/error'
const intervalError = '[nuxt] `setInterval` should not be used on the server. Consider wrapping it with an `onNuxtReady`, `onBeforeMount` or `onMounted` lifecycle hook, or ensure you only call it in the browser by checking `import.meta.client`.'
export const setInterval = import.meta.client ? window.setInterval : () => {
if (import.meta.dev) {
throw createError({
statusCode: 500,
message: intervalError
})
}
export const setInterval = import.meta.client
? window.setInterval
: () => {
if (import.meta.dev) {
throw createError({
statusCode: 500,
message: intervalError
})
}
console.error(intervalError)
}
console.error(intervalError)
}

View File

@ -33,7 +33,7 @@ export default defineComponent({
const cache = new WeakMap()
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
export function createClientOnly<T extends ComponentOptions> (component: T) {
if (cache.has(component)) {
return cache.get(component)

View File

@ -213,7 +213,7 @@ export default defineComponent({
}
expose({
refresh: () => fetchComponent(true),
refresh: () => fetchComponent(true)
})
if (import.meta.hot) {
@ -264,7 +264,7 @@ export default defineComponent({
const { html, slots } = info
let replaced = html.replaceAll('data-island-uid', `data-island-uid="${uid.value}"`)
for (const slot in slots) {
replaced = replaced.replaceAll(`data-island-slot="${slot}">`, (full) => full + slots[slot])
replaced = replaced.replaceAll(`data-island-slot="${slot}">`, full => full + slots[slot])
}
teleports.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}` }, {
default: () => [createStaticVNode(replaced, 1)]

View File

@ -22,29 +22,6 @@ const firstNonUndefined = <T> (...args: (T | undefined)[]) => args.find(arg => a
const NuxtLinkDevKeySymbol: InjectionKey<boolean> = Symbol('nuxt-link-dev-key')
/**
* Create a NuxtLink component with given options as defaults.
* @see https://nuxt.com/docs/api/components/nuxt-link
*/
export interface NuxtLinkOptions extends
Pick<RouterLinkProps, 'activeClass' | 'exactActiveClass'>,
Pick<NuxtLinkProps, 'prefetchedClass'> {
/**
* The name of the component.
* @default "NuxtLink"
*/
componentName?: string
/**
* A default `rel` attribute value applied on external links. Defaults to `"noopener noreferrer"`. Set it to `""` to disable.
*/
externalRelAttribute?: string | null
/**
* An option to either add or remove trailing slashes in the `href`.
* If unset or not matching the valid values `append` or `remove`, it will be ignored.
*/
trailingSlash?: 'append' | 'remove'
}
/**
* <NuxtLink> is a drop-in replacement for both Vue Router's <RouterLink> component and HTML's <a> tag.
* @see https://nuxt.com/docs/api/components/nuxt-link
@ -88,7 +65,30 @@ export interface NuxtLinkProps extends Omit<RouterLinkProps, 'to'> {
noPrefetch?: boolean
}
/*@__NO_SIDE_EFFECTS__*/
/**
* Create a NuxtLink component with given options as defaults.
* @see https://nuxt.com/docs/api/components/nuxt-link
*/
export interface NuxtLinkOptions extends
Pick<RouterLinkProps, 'activeClass' | 'exactActiveClass'>,
Pick<NuxtLinkProps, 'prefetchedClass'> {
/**
* The name of the component.
* @default "NuxtLink"
*/
componentName?: string
/**
* A default `rel` attribute value applied on external links. Defaults to `"noopener noreferrer"`. Set it to `""` to disable.
*/
externalRelAttribute?: string | null
/**
* An option to either add or remove trailing slashes in the `href`.
* If unset or not matching the valid values `append` or `remove`, it will be ignored.
*/
trailingSlash?: 'append' | 'remove'
}
/* @__NO_SIDE_EFFECTS__ */
export function defineNuxtLink (options: NuxtLinkOptions) {
const componentName = options.componentName || 'NuxtLink'

View File

@ -23,13 +23,13 @@ export default defineComponent({
estimatedProgress: {
type: Function as unknown as () => (duration: number, elapsed: number) => number,
required: false
},
}
},
setup (props, { slots, expose }) {
const { progress, isLoading, start, finish, clear } = useLoadingIndicator({
duration: props.duration,
throttle: props.throttle,
estimatedProgress: props.estimatedProgress,
estimatedProgress: props.estimatedProgress
})
expose({

View File

@ -40,7 +40,7 @@ export default defineComponent({
vnodes.push(h('div', {
style: 'display: contents;',
'data-island-uid': '',
'data-island-slot': props.name,
'data-island-slot': props.name
}, {
// Teleport in slot to not be hydrated client-side with the staticVNode
default: () => [createVNode(Teleport, { to: `island-slot=${componentName};${props.name}` }, slots.default?.())]
@ -49,7 +49,7 @@ export default defineComponent({
vnodes.push(h('div', {
style: 'display: contents;',
'data-island-uid': '',
'data-island-slot': props.name,
'data-island-slot': props.name
}))
}

View File

@ -214,14 +214,16 @@ export function useAsyncData<
const nuxtApp = useNuxtApp()
// When prerendering, share payload data automatically between requests
const handler = import.meta.client || !import.meta.prerender || !nuxtApp.ssrContext?._sharedPrerenderCache ? _handler : () => {
const value = nuxtApp.ssrContext!._sharedPrerenderCache!.get(key)
if (value) { return value as Promise<ResT> }
const handler = import.meta.client || !import.meta.prerender || !nuxtApp.ssrContext?._sharedPrerenderCache
? _handler
: () => {
const value = nuxtApp.ssrContext!._sharedPrerenderCache!.get(key)
if (value) { return value as Promise<ResT> }
const promise = nuxtApp.runWithContext(_handler)
const promise = nuxtApp.runWithContext(_handler)
nuxtApp.ssrContext!._sharedPrerenderCache!.set(key, promise)
return promise
}
}
// Used to get default values
const getDefault = () => null

View File

@ -28,7 +28,7 @@ async function runLegacyAsyncData (res: Record<string, any> | Promise<Record<str
}
/** @since 3.0.0 */
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
export const defineNuxtComponent: typeof defineComponent =
function defineNuxtComponent (...args: any[]): any {
const [options, key] = args

View File

@ -92,7 +92,7 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
if (store) {
store.onchange = (event) => {
const cookie = event.changed.find((c: any) => c.name === name)
if (cookie) handleChange({ value: cookie.value })
if (cookie) { handleChange({ value: cookie.value }) }
}
} else if (channel) {
channel.onmessage = ({ data }) => handleChange(data)
@ -124,7 +124,7 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
}
/** @since 3.10.0 */
export function refreshCookie (name: string) {
if (store || typeof BroadcastChannel === 'undefined') return
if (store || typeof BroadcastChannel === 'undefined') { return }
new BroadcastChannel(`nuxt:cookies:${name}`)?.postMessage({ refresh: true })
}

View File

@ -52,10 +52,8 @@ export const clearError = async (options: { redirect?: string } = {}) => {
/** @since 3.0.0 */
export const isNuxtError = <DataT = unknown>(
error?: string | object
): error is NuxtError<DataT> => (
!!error && typeof error === 'object' && NUXT_ERROR_SIGNATURE in error
)
error?: string | object
): error is NuxtError<DataT> => !!error && typeof error === 'object' && NUXT_ERROR_SIGNATURE in error
/** @since 3.0.0 */
export const createError = <DataT = unknown>(

View File

@ -243,10 +243,10 @@ export function useLazyFetch<
autoKey)
}
function generateOptionSegments <_ResT, DataT, DefaultT>(opts: UseFetchOptions<_ResT, DataT, any, DefaultT, any, any>) {
function generateOptionSegments <_ResT, DataT, DefaultT> (opts: UseFetchOptions<_ResT, DataT, any, DefaultT, any, any>) {
const segments: Array<string | undefined | Record<string, string>> = [
toValue(opts.method as MaybeRef<string | undefined> | undefined)?.toUpperCase() || 'GET',
toValue(opts.baseURL),
toValue(opts.baseURL)
]
for (const _obj of [opts.params || opts.query]) {
const obj = toValue(_obj)

View File

@ -29,7 +29,7 @@ export function usePreviewMode<S extends EnteredState> (options: PreviewModeOpti
if (preview.value._initialized) {
return {
enabled: toRef(preview.value, 'enabled'),
state: preview.value.state as S extends void ? Preview['state'] : (NonNullable<S> & Preview['state']),
state: preview.value.state as S extends void ? Preview['state'] : (NonNullable<S> & Preview['state'])
}
}
@ -56,7 +56,7 @@ export function usePreviewMode<S extends EnteredState> (options: PreviewModeOpti
if (import.meta.client && !unregisterRefreshHook) {
refreshNuxtData()
unregisterRefreshHook = useRouter().afterEach((() => refreshNuxtData()))
unregisterRefreshHook = useRouter().afterEach(() => refreshNuxtData())
}
} else if (unregisterRefreshHook) {
unregisterRefreshHook()
@ -67,7 +67,7 @@ export function usePreviewMode<S extends EnteredState> (options: PreviewModeOpti
return {
enabled: toRef(preview.value, 'enabled'),
state: preview.value.state as S extends void ? Preview['state'] : (NonNullable<S> & Preview['state']),
state: preview.value.state as S extends void ? Preview['state'] : (NonNullable<S> & Preview['state'])
}
}

View File

@ -48,7 +48,7 @@ export interface RouteMiddleware {
}
/** @since 3.0.0 */
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
export function defineNuxtRouteMiddleware (middleware: RouteMiddleware) {
return middleware
}
@ -214,8 +214,8 @@ export const navigateTo = (to: RouteLocationRaw | undefined | null, options?: Na
return options?.replace ? router.replace(to) : router.push(to)
}
/**
* This will abort navigation within a Nuxt route middleware handler.
/**
* This will abort navigation within a Nuxt route middleware handler.
* @since 3.0.0
*/
export const abortNavigation = (err?: string | Partial<NuxtError>) => {

View File

@ -61,7 +61,7 @@ if (import.meta.client) {
const nuxt = createNuxtApp({ vueApp })
async function handleVueError(error: any) {
async function handleVueError (error: any) {
await nuxt.callHook('app:error', error)
nuxt.payload.error = nuxt.payload.error || createError(error as any)
}
@ -85,8 +85,7 @@ if (import.meta.client) {
}
// If the errorHandler is not overridden by the user, we unset it
if (vueApp.config.errorHandler === handleVueError)
vueApp.config.errorHandler = undefined
if (vueApp.config.errorHandler === handleVueError) { vueApp.config.errorHandler = undefined }
return vueApp
}

View File

@ -21,7 +21,7 @@ import type { ViewTransition } from './plugins/view-transitions.client'
import type { NuxtAppLiterals } from '#app'
const nuxtAppCtx = /*@__PURE__*/ getContext<NuxtApp>('nuxt-app', {
const nuxtAppCtx = /* @__PURE__ */ getContext<NuxtApp>('nuxt-app', {
asyncContext: !!__NUXT_ASYNC_CONTEXT__ && import.meta.server
})
@ -406,7 +406,7 @@ export async function applyPlugins (nuxtApp: NuxtApp, plugins: Array<Plugin & Ob
if (errors.length) { throw errors[0] }
}
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
export function defineNuxtPlugin<T extends Record<string, unknown>> (plugin: Plugin<T> | ObjectPlugin<T>): Plugin<T> & ObjectPlugin<T> {
if (typeof plugin === 'function') { return plugin }
@ -415,7 +415,7 @@ export function defineNuxtPlugin<T extends Record<string, unknown>> (plugin: Plu
return Object.assign(plugin.setup || (() => {}), plugin, { [NuxtPluginIndicator]: true, _name } as const)
}
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
export const definePayloadPlugin = defineNuxtPlugin
export function isNuxtPlugin (plugin: unknown) {
@ -438,7 +438,7 @@ export function callWithNuxt<T extends (...args: any[]) => any> (nuxt: NuxtApp |
}
}
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
/**
* Returns the current Nuxt instance.
*
@ -455,7 +455,7 @@ export function tryUseNuxtApp (): NuxtApp | null {
return nuxtAppInstance || null
}
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
/**
* Returns the current Nuxt instance.
*
@ -475,7 +475,7 @@ export function useNuxtApp (): NuxtApp {
return nuxtAppInstance
}
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
export function useRuntimeConfig (_event?: H3Event<EventHandlerRequest>): RuntimeConfig {
return useNuxtApp().$config
}

View File

@ -83,7 +83,7 @@ export const islandsTransform = createUnplugin((options: ServerOnlyComponentTran
if (children.length) {
const attrString = Object.entries(attributes).map(([name, value]) => name ? `${name}="${value}" ` : value).join(' ')
const slice = code.slice(startingIndex + loc[0].end, startingIndex + loc[1].start).replaceAll(/:?key="[^"]"/g, '')
s.overwrite(startingIndex + loc[0].start, startingIndex + loc[1].end, `<slot ${attrString} /><template #fallback>${attributes["v-for"] ? wrapWithVForDiv(slice, attributes['v-for']) : slice}</template>`)
s.overwrite(startingIndex + loc[0].start, startingIndex + loc[1].end, `<slot ${attrString} /><template #fallback>${attributes['v-for'] ? wrapWithVForDiv(slice, attributes['v-for']) : slice}</template>`)
}
const slotName = attributes.name ?? 'default'

View File

@ -231,20 +231,20 @@ export default defineNuxtModule<ComponentsOptions>({
if (isClient && selectiveClient) {
fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}')
if(!nuxt.options.dev) {
if (!nuxt.options.dev) {
config.plugins.push(componentsChunkPlugin.vite({
getComponents,
buildDir: nuxt.options.buildDir
}))
} else {
fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'),`export const paths = ${JSON.stringify(
fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), `export const paths = ${JSON.stringify(
getComponents().filter(c => c.mode === 'client' || c.mode === 'all').reduce((acc, c) => {
if(c.filePath.endsWith('.vue') || c.filePath.endsWith('.js') || c.filePath.endsWith('.ts')) return Object.assign(acc, {[c.pascalName]: `/@fs/${c.filePath}`})
const filePath = fs.existsSync( `${c.filePath}.vue`) ? `${c.filePath}.vue` : fs.existsSync( `${c.filePath}.js`) ? `${c.filePath}.js` : `${c.filePath}.ts`
return Object.assign(acc, {[c.pascalName]: `/@fs/${filePath}`})
if (c.filePath.endsWith('.vue') || c.filePath.endsWith('.js') || c.filePath.endsWith('.ts')) { return Object.assign(acc, { [c.pascalName]: `/@fs/${c.filePath}` }) }
const filePath = fs.existsSync(`${c.filePath}.vue`) ? `${c.filePath}.vue` : fs.existsSync(`${c.filePath}.js`) ? `${c.filePath}.js` : `${c.filePath}.ts`
return Object.assign(acc, { [c.pascalName]: `/@fs/${filePath}` })
}, {} as Record<string, string>)
)}`)
}
}
}
if (isServer) {
@ -254,7 +254,7 @@ export default defineNuxtModule<ComponentsOptions>({
isDev: nuxt.options.dev,
selectiveClient
}))
}
}
}
if (!isServer && nuxt.options.experimental.componentIslands) {
config.plugins.push({

View File

@ -1,8 +1,8 @@
import { defineAsyncComponent, defineComponent, h } from 'vue'
import type { AsyncComponentLoader } from 'vue'
import { default as ClientOnly } from '#app/components/client-only'
import ClientOnly from '#app/components/client-only'
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
export const createClientPage = (loader: AsyncComponentLoader) => {
const page = defineAsyncComponent(loader)

View File

@ -3,7 +3,7 @@ import NuxtIsland from '#app/components/nuxt-island'
import { useRoute } from '#app/composables/router'
import { isPrerendered } from '#app/composables/payload'
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
export const createServerComponent = (name: string) => {
return defineComponent({
name,
@ -32,7 +32,7 @@ export const createServerComponent = (name: string) => {
})
}
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
export const createIslandPage = (name: string) => {
return defineComponent({
name,

View File

@ -227,7 +227,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
output: {},
plugins: []
},
logLevel: logLevelMapReverse[nuxt.options.logLevel],
logLevel: logLevelMapReverse[nuxt.options.logLevel]
} satisfies NitroConfig)
// Resolve user-provided paths

View File

@ -64,11 +64,11 @@ async function initNuxt (nuxt: Nuxt) {
nuxt.hook('close', () => nuxtCtx.unset())
const coreTypePackages = ['nitropack', 'defu', 'h3', '@unhead/vue', 'vue', 'vue-router', '@nuxt/schema']
const paths = Object.fromEntries(await Promise.all(coreTypePackages.map(async pkg => {
const paths = Object.fromEntries(await Promise.all(coreTypePackages.map(async (pkg) => {
const path = await _resolvePath(pkg, { url: nuxt.options.modulesDir }).then(r => resolvePackageJSON(r)).catch(() => null)
if (!path) { return }
return [pkg, [dirname(path)]]
})).then((r) => r.filter(Boolean) as [string, [string]][]))
})).then(r => r.filter(Boolean) as [string, [string]][]))
// Set nitro resolutions for types that might be obscured with shamefully-hoist=false
nuxt.options.nitro.typescript = defu(nuxt.options.nitro.typescript, {

View File

@ -17,7 +17,7 @@ export const UnctxTransformPlugin = createUnplugin((options: UnctxTransformPlugi
name: 'unctx:transform',
enforce: 'post',
transformInclude (id) {
return isVue(id, { type: ['template', 'script']}) || isJS(id)
return isVue(id, { type: ['template', 'script'] }) || isJS(id)
},
transform (code) {
// TODO: needed for webpack - update transform in unctx/unplugin?

View File

@ -21,6 +21,6 @@ export default defineDriver((opts: { base: string }) => {
},
async getItem (key, opts) {
return await lru.getItem(key, opts) || await fs.getItem(normalizeFsKey(key), opts)
},
}
}
})

View File

@ -54,13 +54,15 @@ export default <NitroErrorHandler> async function errorhandler (error: H3Error,
const isRenderingError = event.path.startsWith('/__nuxt_error') || !!reqHeaders['x-nuxt-error']
// HTML response (via SSR)
const res = isRenderingError ? null : await useNitroApp().localFetch(
withQuery(joinURL(useRuntimeConfig(event).app.baseURL, '/__nuxt_error'), errorObject),
{
headers: { ...reqHeaders, 'x-nuxt-error': 'true' },
redirect: 'manual'
}
).catch(() => null)
const res = isRenderingError
? null
: await useNitroApp().localFetch(
withQuery(joinURL(useRuntimeConfig(event).app.baseURL, '/__nuxt_error'), errorObject),
{
headers: { ...reqHeaders, 'x-nuxt-error': 'true' },
redirect: 'manual'
}
).catch(() => null)
// Fallback to static rendered error page
if (!res) {

View File

@ -53,6 +53,18 @@ export interface NuxtRenderHTMLContext {
bodyAppend: string[]
}
export interface NuxtIslandSlotResponse {
props: Array<unknown>
fallback?: string
}
export interface NuxtIslandClientResponse {
html: string
props: unknown
chunk: string
slots?: Record<string, string>
}
export interface NuxtIslandContext {
id?: string
name: string
@ -62,17 +74,6 @@ export interface NuxtIslandContext {
components: Record<string, Omit<NuxtIslandClientResponse, 'html'>>
}
export interface NuxtIslandSlotResponse {
props: Array<unknown>
fallback?: string
}
export interface NuxtIslandClientResponse {
html: string
props: unknown
chunk: string
slots?: Record<string, string>
}
export interface NuxtIslandResponse {
id?: string
html: string
@ -186,20 +187,22 @@ const islandCache = import.meta.prerender ? useStorage('internal:nuxt:prerender:
const islandPropCache = import.meta.prerender ? useStorage('internal:nuxt:prerender:island-props') : null
const sharedPrerenderPromises = import.meta.prerender && process.env.NUXT_SHARED_DATA ? new Map<string, Promise<any>>() : null
const sharedPrerenderKeys = new Set<string>()
const sharedPrerenderCache = import.meta.prerender && process.env.NUXT_SHARED_DATA ? {
get <T = unknown>(key: string): Promise<T> | undefined {
if (sharedPrerenderKeys.has(key)) {
return sharedPrerenderPromises!.get(key) ?? useStorage('internal:nuxt:prerender:shared').getItem(key) as Promise<T>
const sharedPrerenderCache = import.meta.prerender && process.env.NUXT_SHARED_DATA
? {
get<T = unknown> (key: string): Promise<T> | undefined {
if (sharedPrerenderKeys.has(key)) {
return sharedPrerenderPromises!.get(key) ?? useStorage('internal:nuxt:prerender:shared').getItem(key) as Promise<T>
}
},
async set<T> (key: string, value: Promise<T>): Promise<void> {
sharedPrerenderKeys.add(key)
sharedPrerenderPromises!.set(key, value)
useStorage('internal:nuxt:prerender:shared').setItem(key, await value as any)
// free up memory after the promise is resolved
.finally(() => sharedPrerenderPromises!.delete(key))
}
}
},
async set <T>(key: string, value: Promise<T>): Promise<void> {
sharedPrerenderKeys.add(key)
sharedPrerenderPromises!.set(key, value)
useStorage('internal:nuxt:prerender:shared').setItem(key, await value as any)
// free up memory after the promise is resolved
.finally(() => sharedPrerenderPromises!.delete(key))
},
} : null
: null
async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
// TODO: Strict validation for url
@ -221,7 +224,7 @@ async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
name: componentName,
props: destr(context.props) || {},
slots: {},
components: {},
components: {}
}
return ctx
@ -302,8 +305,8 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
payload: (ssrError ? { error: ssrError } : {}) as NuxtPayload,
_payloadReducers: {},
modules: new Set(),
set _registeredComponents(value) { this.modules = value },
get _registeredComponents() { return this.modules },
set _registeredComponents (value) { this.modules = value },
get _registeredComponents () { return this.modules },
islandContext
}
@ -327,7 +330,6 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
writeEarlyHints(event, link)
}
if (process.env.NUXT_INLINE_STYLES && !isRenderingIsland) {
for (const id of await getEntryIds()) {
ssrContext.modules!.add(id)
@ -537,16 +539,16 @@ function joinTags (tags: string[]) {
}
function joinAttrs (chunks: string[]) {
if (chunks.length === 0) return ''
if (chunks.length === 0) { return '' }
return ' ' + chunks.join(' ')
}
function renderHTMLDocument (html: NuxtRenderHTMLContext) {
return '<!DOCTYPE html>'
+ `<html${joinAttrs(html.htmlAttrs)}>`
+ `<head>${joinTags(html.head)}</head>`
+ `<body${joinAttrs(html.bodyAttrs)}>${joinTags(html.bodyPrepend)}${joinTags(html.body)}${joinTags(html.bodyAppend)}</body>`
+ '</html>'
return '<!DOCTYPE html>' +
`<html${joinAttrs(html.htmlAttrs)}>` +
`<head>${joinTags(html.head)}</head>` +
`<body${joinAttrs(html.bodyAttrs)}>${joinTags(html.bodyPrepend)}${joinTags(html.body)}${joinTags(html.bodyAppend)}</body>` +
'</html>'
}
async function renderInlineStyles (usedModules: Set<string> | string[]): Promise<Style[]> {
@ -639,7 +641,7 @@ function getSlotIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse[
for (const slot in ssrContext.islandContext.slots) {
response[slot] = {
...ssrContext.islandContext.slots[slot],
fallback: ssrContext.teleports?.[`island-fallback=${slot}`],
fallback: ssrContext.teleports?.[`island-fallback=${slot}`]
}
}
return response

View File

@ -48,7 +48,7 @@ export const errorComponentTemplate: NuxtTemplate = {
// TODO: Use an alias
export const testComponentWrapperTemplate: NuxtTemplate = {
filename: 'test-component-wrapper.mjs',
getContents: (ctx) => genExport(resolve(ctx.nuxt.options.appDir, 'components/test-component-wrapper'), ['default'])
getContents: ctx => genExport(resolve(ctx.nuxt.options.appDir, 'components/test-component-wrapper'), ['default'])
}
export const cssTemplate: NuxtTemplate = {

View File

@ -17,7 +17,7 @@ const removeUndefinedProps = (props: Props) => {
for (const key in props) {
const value = props[key]
if (value !== undefined) {
filteredProps[key] = value;
filteredProps[key] = value
}
}
return filteredProps

View File

@ -354,14 +354,14 @@ export default defineNuxtModule({
if (nuxt.options.experimental.appManifest) {
// Add all redirect paths as valid routes to router; we will handle these in a client-side middleware
// when the app manifest is enabled.
nuxt.hook('pages:extend', routes => {
nuxt.hook('pages:extend', (routes) => {
const nitro = useNitro()
for (const path in nitro.options.routeRules) {
const rule = nitro.options.routeRules[path]
if (!rule.redirect) { continue }
routes.push({
path: path.replace(/\/[^/]*\*\*/, '/:pathMatch(.*)'),
file: resolve(runtimeDir, 'component-stub'),
file: resolve(runtimeDir, 'component-stub')
})
}
})
@ -400,7 +400,7 @@ export default defineNuxtModule({
const sourceFiles = nuxt.apps.default?.pages?.length ? getSources(nuxt.apps.default.pages) : []
for (const key in manifest) {
if (manifest[key].src && Object.values(nuxt.apps).some(app => app.pages?.some(page => page.mode === 'server' && page.file === join(nuxt.options.srcDir, manifest[key].src!) ))) {
if (manifest[key].src && Object.values(nuxt.apps).some(app => app.pages?.some(page => page.mode === 'server' && page.file === join(nuxt.options.srcDir, manifest[key].src!)))) {
delete manifest[key]
continue
}
@ -415,7 +415,7 @@ export default defineNuxtModule({
addTemplate({
filename: 'routes.mjs',
getContents ({ app }) {
if (!app.pages) return 'export default []'
if (!app.pages) { return 'export default []' }
const { routes, imports } = normalizeRoutes(app.pages, new Set(), nuxt.options.experimental.scanPageMeta)
return [...imports, `export default ${routes}`].join('\n')
}
@ -490,7 +490,6 @@ export default defineNuxtModule({
}
})
// add page meta types if enabled
if (nuxt.options.experimental.viewTransition) {
addTypeTemplate({
@ -502,9 +501,9 @@ export default defineNuxtModule({
'import type { ComputedRef, MaybeRef } from \'vue\'',
`declare module ${genString(composablesFile)} {`,
' interface PageMeta {',
` viewTransition?: boolean | 'always'`,
' viewTransition?: boolean | \'always\'',
' }',
'}',
'}'
].join('\n')
}
})

View File

@ -78,6 +78,6 @@ export const definePageMeta = (meta: PageMeta): void => {
* For more control, such as if you are using a custom `path` or `alias` set in the page's `definePageMeta`, you
* should set `routeRules` directly within your `nuxt.config`.
*/
/*@__NO_SIDE_EFFECTS__*/
/* @__NO_SIDE_EFFECTS__ */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const defineRouteRules = (rules: NitroRouteConfig): void => {}

View File

@ -4,9 +4,8 @@ import { RouterView } from '#vue-router'
import { defu } from 'defu'
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from '#vue-router'
import { toArray } from './utils'
import { generateRouteKey, toArray, wrapInKeepAlive } from './utils'
import type { RouterViewSlotProps } from './utils'
import { generateRouteKey, wrapInKeepAlive } from './utils'
import { RouteProvider } from '#app/components/route-provider'
import { useNuxtApp } from '#app/nuxt'
import { useRouter } from '#app/composables/router'

View File

@ -11,9 +11,9 @@ export default defineNuxtPlugin({
function checkIfPageUnused () {
if (!error.value && !nuxtApp._isNuxtPageUsed) {
console.warn(
'[nuxt] Your project has pages but the `<NuxtPage />` component has not been used.'
+ ' You might be using the `<RouterView />` component instead, which will not work correctly in Nuxt.'
+ ' You can set `pages: false` in `nuxt.config` if you do not wish to use the Nuxt `vue-router` integration.'
'[nuxt] Your project has pages but the `<NuxtPage />` component has not been used.' +
' You might be using the `<RouterView />` component instead, which will not work correctly in Nuxt.' +
' You can set `pages: false` in `nuxt.config` if you do not wish to use the Nuxt `vue-router` integration.'
)
}
}

View File

@ -84,7 +84,7 @@ export async function generateRoutesFromFiles (files: ScannedFile[], options: Ge
name: '',
path: '',
file: file.absolutePath,
children: [],
children: []
}
// Array where routes should be added, useful when adding child routes
@ -399,7 +399,7 @@ function prepareRoutes (routes: NuxtPage[], parent?: NuxtPage, names = new Set<s
}
function serializeRouteValue (value: any, skipSerialisation = false) {
if (skipSerialisation || value === undefined) return undefined
if (skipSerialisation || value === undefined) { return undefined }
return JSON.stringify(value)
}
@ -425,7 +425,7 @@ export function normalizeRoutes (routes: NuxtPage[], metaImports: Set<string> =
name: serializeRouteValue(page.name),
meta: serializeRouteValue(metaFiltered, skipMeta),
alias: serializeRouteValue(toArray(page.alias), skipAlias),
redirect: serializeRouteValue(page.redirect),
redirect: serializeRouteValue(page.redirect)
}
for (const key of ['path', 'name', 'meta', 'alias', 'redirect'] satisfies NormalizedRouteKeys) {
@ -487,13 +487,13 @@ async function createClientPage(loader) {
// skip and retain fallback if marked dynamic
// set to extracted value or fallback if none extracted
for (const key of ['name', 'path'] satisfies NormalizedRouteKeys) {
if (markedDynamic.has(key)) continue
if (markedDynamic.has(key)) { continue }
metaRoute[key] = route[key] ?? metaRoute[key]
}
// set to extracted value or delete if none extracted
for (const key of ['meta', 'alias', 'redirect'] satisfies NormalizedRouteKeys) {
if (markedDynamic.has(key)) continue
if (markedDynamic.has(key)) { continue }
if (route[key] == null) {
delete metaRoute[key]

View File

@ -87,7 +87,7 @@ describe('resolveApp', () => {
'middleware/other.ts',
'layouts/index.vue',
'layouts/default/index.vue',
'layouts/other.vue',
'layouts/other.vue'
])
// Middleware are not resolved in a nested manner
expect(app.middleware.filter(m => m.path.startsWith('<rootDir>'))).toMatchInlineSnapshot(`

View File

@ -57,7 +57,7 @@ describe('test devonly transform ', () => {
expect(result).not.toContain('LazyDevOnly')
})
it('should not remove class -> nuxt#24491', async () => {
it('should not remove class -> nuxt#24491', async () => {
const source = `<template>
<DevOnly>
<div class="red">This is red.</div>
@ -68,7 +68,7 @@ describe('test devonly transform ', () => {
</template>
`
const result = await viteTransform(source, 'some id')
const result = await viteTransform(source, 'some id')
expect(result).toMatchInlineSnapshot(`
"<template>

View File

@ -58,7 +58,7 @@ describe('islandTransform - server and island components', () => {
const someData = 'some data'
</script>`
, 'hello.server.vue')
, 'hello.server.vue')
expect(normalizeLineEndings(result)).toMatchInlineSnapshot(`
"<template>
@ -94,7 +94,7 @@ describe('islandTransform - server and island components', () => {
const someData = 'some data'
</script>`
, 'hello.server.vue')
, 'hello.server.vue')
expect(normalizeLineEndings(result)).toMatchInlineSnapshot(`
"<template>
@ -145,7 +145,7 @@ describe('islandTransform - server and island components', () => {
const message = "Hello World";
</script>
`
, 'hello.server.vue')
, 'hello.server.vue')
expect(normalizeLineEndings(result)).toMatchInlineSnapshot(`
"<template>
@ -351,7 +351,7 @@ describe('islandTransform - server and island components', () => {
"
`)
expect(result).toContain(`import NuxtTeleportIslandComponent from '#app/components/nuxt-teleport-island-component'`)
expect(result).toContain('import NuxtTeleportIslandComponent from \'#app/components/nuxt-teleport-island-component\'')
})
})

View File

@ -14,7 +14,7 @@ describe('loadNuxt', () => {
ready: true,
overrides: {
hooks: {
ready() {
ready () {
hookRan = true
}
}

View File

@ -11,10 +11,10 @@ describe('pages:generateRoutesFromFiles', () => {
vi.mock('knitwork', async (original) => {
return {
...(await original<typeof import('knitwork')>()),
'genArrayFromRaw': (val: any) => val,
'genSafeVariableName': (..._args: string[]) => {
genArrayFromRaw: (val: any) => val,
genSafeVariableName: (..._args: string[]) => {
return 'mock'
},
}
}
})
@ -471,7 +471,7 @@ describe('pages:generateRoutesFromFiles', () => {
name: 'index',
path: '/'
}
],
]
},
{
description: 'should use fallbacks when normalized with `overrideMeta: true`',
@ -527,7 +527,7 @@ describe('pages:generateRoutesFromFiles', () => {
alias: ['sweet-home'],
redirect: '/',
children: [],
meta: { [DYNAMIC_META_KEY]: new Set(['meta']) },
meta: { [DYNAMIC_META_KEY]: new Set(['meta']) }
}
]
},
@ -538,7 +538,7 @@ describe('pages:generateRoutesFromFiles', () => {
name: 'home',
path: '/',
alias: ['sweet-home'],
meta: { hello: 'world' },
meta: { hello: 'world' }
}
]
},
@ -550,10 +550,10 @@ describe('pages:generateRoutesFromFiles', () => {
path: '/',
alias: ['pushed-route-alias'],
meta: { someMetaData: true },
file: `${pagesDir}/route-file.vue`,
file: `${pagesDir}/route-file.vue`
}
]
},
}
]
const normalizedResults: Record<string, any> = {}
@ -561,7 +561,6 @@ describe('pages:generateRoutesFromFiles', () => {
for (const test of tests) {
it(test.description, async () => {
let result
if (test.files) {
const vfs = Object.fromEntries(

View File

@ -1,11 +1,11 @@
/// <reference types="nitropack" />
export * from './dist/index'
import type { DefineNuxtConfig } from 'nuxt/config'
import type { RuntimeConfig, SchemaDefinition } from 'nuxt/schema'
import type { H3Event } from 'h3'
import type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from './dist/app/types'
export * from './dist/index'
declare global {
const defineNuxtConfig: DefineNuxtConfig
const defineNuxtSchema: (schema: SchemaDefinition) => SchemaDefinition

View File

@ -27,7 +27,7 @@ export default defineUntypedSchema({
* @see [Vue RFC#502](https://github.com/vuejs/rfcs/discussions/502)
* @type {boolean}
*/
propsDestructure: false,
propsDestructure: false
},
/**
@ -157,7 +157,7 @@ export default defineUntypedSchema({
*/
viewTransition: {
$resolve: async (val, get) => val ?? await (get('experimental') as Promise<Record<string, any>>).then(
(e) => e?.viewTransition
e => e?.viewTransition
) ?? false
},

View File

@ -27,7 +27,7 @@ export default defineUntypedSchema({
}
return true
}
},
}
},
/**
* Some features of Nuxt are available on an opt-in basis, or can be disabled based on your needs.
@ -61,7 +61,7 @@ export default defineUntypedSchema({
// TODO: remove in v3.10
return val ?? await (get('experimental') as Promise<Record<string, any>>).then((e: Record<string, any>) => e?.noScripts) ?? false
}
},
}
},
experimental: {
/**
@ -335,6 +335,6 @@ export default defineUntypedSchema({
* ```
* @type {boolean}
*/
clientNodeCompat: false,
clientNodeCompat: false
}
})

View File

@ -70,7 +70,7 @@ export default defineUntypedSchema({
exclude: {
$resolve: async (val: string[] | undefined, get) => [
...val || [],
...(await get('build.transpile') as Array<string | RegExp | ((ctx: { isClient?: boolean; isServer?: boolean; isDev: boolean }) => string | RegExp | false)>).filter((i) => typeof i === 'string'),
...(await get('build.transpile') as Array<string | RegExp | ((ctx: { isClient?: boolean; isServer?: boolean; isDev: boolean }) => string | RegExp | false)>).filter(i => typeof i === 'string'),
'vue-demi'
]
}

View File

@ -206,7 +206,7 @@ export default defineUntypedSchema({
embed: 'src'
},
compilerOptions: { $resolve: async (val, get) => val ?? (await get('vue.compilerOptions')) },
propsDestructure: { $resolve: async (val, get) => val ?? Boolean(await get('vue.propsDestructure')) },
propsDestructure: { $resolve: async (val, get) => val ?? Boolean(await get('vue.propsDestructure')) }
},
css: {

View File

@ -36,6 +36,7 @@ export interface NuxtTemplate<Options = TemplateDefaultOptions> {
/** The resolved path to the source file to be template */
src?: string
/** Provided compile option instead of src */
// eslint-disable-next-line no-use-before-define
getContents?: (data: { nuxt: Nuxt, app: NuxtApp, options: Options }) => string | Promise<string>
/** Write to filesystem */
write?: boolean

View File

@ -20,12 +20,14 @@ import { viteNodePlugin } from './vite-node'
import { createViteLogger } from './utils/logger'
export async function buildClient (ctx: ViteBuildContext) {
const nodeCompat = ctx.nuxt.options.experimental.clientNodeCompat ? {
alias: env(nodeless).alias,
define: {
global: 'globalThis',
}
} : { alias: {}, define: {} }
const nodeCompat = ctx.nuxt.options.experimental.clientNodeCompat
? {
alias: env(nodeless).alias,
define: {
global: 'globalThis'
}
}
: { alias: {}, define: {} }
const clientConfig: ViteConfig = vite.mergeConfig(ctx.config, vite.mergeConfig({
configFile: false,
@ -67,7 +69,7 @@ export async function buildClient (ctx: ViteBuildContext) {
...nodeCompat.alias,
...ctx.config.resolve?.alias,
'#build/plugins': resolve(ctx.nuxt.options.buildDir, 'plugins/client'),
'#internal/nitro': resolve(ctx.nuxt.options.buildDir, 'nitro.client.mjs'),
'#internal/nitro': resolve(ctx.nuxt.options.buildDir, 'nitro.client.mjs')
},
dedupe: [
'vue'

View File

@ -44,11 +44,11 @@ export async function buildServer (ctx: ViteBuildContext) {
'import.meta.server': true,
'import.meta.client': false,
'import.meta.browser': false,
'window': 'undefined',
'document': 'undefined',
'navigator': 'undefined',
'location': 'undefined',
'XMLHttpRequest': 'undefined'
window: 'undefined',
document: 'undefined',
navigator: 'undefined',
location: 'undefined',
XMLHttpRequest: 'undefined'
},
optimizeDeps: {
entries: ctx.nuxt.options.ssr ? [ctx.entry] : []
@ -99,7 +99,7 @@ export async function buildServer (ctx: ViteBuildContext) {
// https://github.com/vitest-dev/vitest/issues/229#issuecomment-1002685027
preTransformRequests: false,
hmr: false
},
}
} satisfies vite.InlineConfig, ctx.nuxt.options.vite.$server || {}))
if (!ctx.nuxt.options.dev) {

View File

@ -158,7 +158,7 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
// Trigger vite to optimize dependencies imported within a layer, just as if they were imported in final project
await this.resolve(source, join(nuxt.options.srcDir, 'index.html'), { skipSelf: true }).catch(() => null)
}
},
}
})
}
}

View File

@ -22,7 +22,7 @@ export function client (ctx: WebpackConfigContext) {
clientDevtool,
clientPerformance,
clientHMR,
clientNodeCompat,
clientNodeCompat
])
}
@ -50,21 +50,21 @@ function clientPerformance (ctx: WebpackConfigContext) {
}
}
function clientNodeCompat(ctx: WebpackConfigContext) {
function clientNodeCompat (ctx: WebpackConfigContext) {
if (!ctx.nuxt.options.experimental.clientNodeCompat) {
return
}
ctx.config.plugins!.push(new webpack.DefinePlugin({ global: 'globalThis', }))
ctx.config.plugins!.push(new webpack.DefinePlugin({ global: 'globalThis' }))
ctx.config.resolve = ctx.config.resolve || {}
ctx.config.resolve.fallback = {
...env(nodeless).alias,
...ctx.config.resolve.fallback,
...ctx.config.resolve.fallback
}
// https://github.com/webpack/webpack/issues/13290#issuecomment-1188760779
ctx.config.plugins!.unshift(new webpack.NormalModuleReplacementPlugin(/node:/, (resource) => {
resource.request = resource.request.replace(/^node:/, '');
resource.request = resource.request.replace(/^node:/, '')
}))
}

View File

@ -217,7 +217,7 @@ function getEnv (ctx: WebpackConfigContext) {
const _env: Record<string, string | boolean> = {
'process.env.NODE_ENV': JSON.stringify(ctx.config.mode),
__NUXT_VERSION__: JSON.stringify(ctx.nuxt._version),
__NUXT_ASYNC_CONTEXT__: ctx.options.experimental.asyncContext,
__NUXT_ASYNC_CONTEXT__: ctx.options.experimental.asyncContext,
'process.env.VUE_ENV': JSON.stringify(ctx.name),
'process.dev': ctx.options.dev,
'process.test': isTest,

View File

@ -67,6 +67,9 @@ importers:
eslint:
specifier: 8.57.0
version: 8.57.0
eslint-config-standard:
specifier: ^17.1.0
version: 17.1.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.57.0)
eslint-plugin-import:
specifier: 2.29.1
version: 2.29.1(@typescript-eslint/parser@6.8.0)(eslint@8.57.0)
@ -4201,7 +4204,6 @@ packages:
resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==}
dependencies:
semver: 7.6.0
dev: false
/bundle-name@3.0.0:
resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==}
@ -5427,6 +5429,30 @@ packages:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
/eslint-compat-utils@0.1.2(eslint@8.57.0):
resolution: {integrity: sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==}
engines: {node: '>=12'}
peerDependencies:
eslint: '>=6.0.0'
dependencies:
eslint: 8.57.0
dev: true
/eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2)(eslint-plugin-promise@6.1.1)(eslint@8.57.0):
resolution: {integrity: sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==}
engines: {node: '>=12.0.0'}
peerDependencies:
eslint: ^8.0.1
eslint-plugin-import: ^2.25.2
eslint-plugin-n: '^15.0.0 || ^16.0.0 '
eslint-plugin-promise: ^6.0.0
dependencies:
eslint: 8.57.0
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.8.0)(eslint@8.57.0)
eslint-plugin-n: 16.6.2(eslint@8.57.0)
eslint-plugin-promise: 6.1.1(eslint@8.57.0)
dev: true
/eslint-import-resolver-node@0.3.9:
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
dependencies:
@ -5466,6 +5492,18 @@ packages:
- supports-color
dev: true
/eslint-plugin-es-x@7.5.0(eslint@8.57.0):
resolution: {integrity: sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
eslint: '>=8'
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
'@eslint-community/regexpp': 4.9.1
eslint: 8.57.0
eslint-compat-utils: 0.1.2(eslint@8.57.0)
dev: true
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.8.0)(eslint@8.57.0):
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
engines: {node: '>=4'}
@ -5521,11 +5559,40 @@ packages:
- supports-color
dev: true
/eslint-plugin-n@16.6.2(eslint@8.57.0):
resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==}
engines: {node: '>=16.0.0'}
peerDependencies:
eslint: '>=7.0.0'
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
builtins: 5.0.1
eslint: 8.57.0
eslint-plugin-es-x: 7.5.0(eslint@8.57.0)
get-tsconfig: 4.7.2
globals: 13.24.0
ignore: 5.3.1
is-builtin-module: 3.2.1
is-core-module: 2.13.1
minimatch: 3.1.2
resolve: 1.22.8
semver: 7.6.0
dev: true
/eslint-plugin-no-only-tests@3.1.0:
resolution: {integrity: sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==}
engines: {node: '>=5.0.0'}
dev: true
/eslint-plugin-promise@6.1.1(eslint@8.57.0):
resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
dependencies:
eslint: 8.57.0
dev: true
/eslint-plugin-unicorn@51.0.1(eslint@8.57.0):
resolution: {integrity: sha512-MuR/+9VuB0fydoI0nIn2RDA5WISRn4AsJyNSaNKLVwie9/ONvQhxOBbkfSICBPnzKrB77Fh6CZZXjgTt/4Latw==}
engines: {node: '>=16'}
@ -6168,6 +6235,13 @@ packages:
dependencies:
type-fest: 0.20.2
/globals@13.24.0:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
engines: {node: '>=8'}
dependencies:
type-fest: 0.20.2
dev: true
/globalthis@1.0.3:
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
engines: {node: '>= 0.4'}

View File

@ -45,7 +45,7 @@ async function main () {
.replace(/^## v.*?\n/, '')
.replace(`...${releaseBranch}`, `...v${newVersion}`)
.replace(/### ❤️ Contributors[\s\S]*$/, ''),
`### ❤️ Contributors`,
'### ❤️ Contributors',
contributors.map(c => `- ${c.name} (@${c.username})`).join('\n')
].join('\n')

View File

@ -363,7 +363,7 @@ describe('pages', () => {
// don't expect any errors or warning on client-side navigation
const { page: page2, consoleLogs: consoleLogs2 } = await renderPage('/')
await page2.locator('#to-client-only-components').click()
await page2.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, `/client-only-components`)
await page2.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/client-only-components')
expect(consoleLogs2.some(log => log.type === 'error' || log.type === 'warning')).toBeFalsy()
await page2.close()
})
@ -485,14 +485,14 @@ describe('pages', () => {
}"
`)
expect(await clientInitialPage.locator('#server-rendered').textContent()).toMatchInlineSnapshot(`"false"`)
expect(await clientInitialPage.locator('#server-rendered').textContent()).toMatchInlineSnapshot('"false"')
// Then go to non client only page
await clientInitialPage.click('a')
await new Promise((r) => setTimeout(r, 50)) // little delay to finish transition
await new Promise(resolve => setTimeout(resolve, 50)) // little delay to finish transition
// that page should be client rendered
expect(await clientInitialPage.locator('#server-rendered').textContent()).toMatchInlineSnapshot(`"false"`)
expect(await clientInitialPage.locator('#server-rendered').textContent()).toMatchInlineSnapshot('"false"')
// and not contain any errors or warnings
expect(errors.length).toBe(0)
@ -509,7 +509,7 @@ describe('pages', () => {
})
// Now non client only page should be sever rendered
expect(await normalInitialPage.locator('#server-rendered').textContent()).toMatchInlineSnapshot(`"true"`)
expect(await normalInitialPage.locator('#server-rendered').textContent()).toMatchInlineSnapshot('"true"')
// Go to client only page
await normalInitialPage.click('a')
@ -563,7 +563,7 @@ describe('nuxt composables', () => {
expect(text).toContain('baz')
await page.getByText('Change cookie').click()
expect(await extractCookie()).toEqual({ foo: 'bar' })
await page.evaluate(() => document.cookie = `browser-object-default=${encodeURIComponent('{"foo":"foobar"}')}`)
await page.evaluate(() => { document.cookie = `browser-object-default=${encodeURIComponent('{"foo":"foobar"}')}` })
await page.getByText('Refresh cookie').click()
text = await page.innerText('pre')
expect(text).toContain('foobar')
@ -639,7 +639,7 @@ describe('rich payloads', () => {
'BigInt ref:',
'Reactive: true',
'Ref: true',
'Recursive objects: true',
'Recursive objects: true'
]) {
expect(html).toContain(test)
}
@ -731,13 +731,13 @@ describe('nuxt links', () => {
await page.locator('#big-page-2').scrollIntoViewIfNeeded()
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
await page.locator('#big-page-2').click()
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, `/big-page-2`)
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/big-page-2')
expect(await page.evaluate(() => window.scrollY)).toBe(0)
await page.locator('#big-page-1').scrollIntoViewIfNeeded()
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
await page.locator('#big-page-1').click()
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, `/big-page-1`)
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/big-page-1')
expect(await page.evaluate(() => window.scrollY)).toBe(0)
await page.close()
},
@ -754,18 +754,18 @@ describe('nuxt links', () => {
height: 1000
}
})
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, `/nested/foo/test`)
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/nested/foo/test')
await page.locator('#user-test').scrollIntoViewIfNeeded()
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
await page.locator('#user-test').click()
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, `/nested/foo/user-test`)
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/nested/foo/user-test')
expect(await page.evaluate(() => window.scrollY)).toBe(0)
await page.locator('#test').scrollIntoViewIfNeeded()
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
await page.locator('#test').click()
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, `/nested/foo/test`)
await page.waitForFunction(path => window.useNuxtApp?.()._route.fullPath === path, '/nested/foo/test')
expect(await page.evaluate(() => window.scrollY)).toBe(0)
await page.close()
},
@ -879,7 +879,7 @@ describe('navigate', () => {
const res = await fetch('/navigate-some-path/', { redirect: 'manual', headers: { 'trailing-slash': 'true' } })
expect(res.headers.get('location')).toEqual('/navigate-some-path')
expect(res.status).toEqual(307)
expect(await res.text()).toMatchInlineSnapshot(`"<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=/navigate-some-path"></head></html>"`)
expect(await res.text()).toMatchInlineSnapshot('"<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=/navigate-some-path"></head></html>"')
})
it('should not overwrite headers', async () => {
@ -1729,9 +1729,9 @@ describe('server components/islands', () => {
const text = (await page.innerText('pre')).replaceAll(/ data-island-uid="([^"]*)"/g, '').replace(/data-island-component="([^"]*)"/g, (_, content) => `data-island-component="${content.split('-')[0]}"`)
if (isWebpack) {
expect(text).toMatchInlineSnapshot(`" End page <pre></pre><section id="fallback"><div> This is a .server (20ms) async component that was very long ... <div id="async-server-component-count">42</div><div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><!--[--><div style="display: contents;" data-island-slot="default"><!--teleport start--><!--teleport end--></div><!--]--></div></section><section id="no-fallback"><div> This is a .server (20ms) async component that was very long ... <div id="async-server-component-count">42</div><div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><!--[--><div style="display: contents;" data-island-slot="default"><!--teleport start--><!--teleport end--></div><!--]--></div></section><div> ServerWithClient.server.vue : <p>count: 0</p> This component should not be preloaded <div><!--[--><div>a</div><div>b</div><div>c</div><!--]--></div> This is not interactive <div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><div class="interactive-component-wrapper" style="border:solid 1px red;"> The component bellow is not a slot but declared as interactive <div class="sugar-counter" nuxt-client=""> Sugar Counter 12 x 1 = 12 <button> Inc </button></div></div></div>"`)
expect(text).toMatchInlineSnapshot('" End page <pre></pre><section id="fallback"><div> This is a .server (20ms) async component that was very long ... <div id="async-server-component-count">42</div><div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><!--[--><div style="display: contents;" data-island-slot="default"><!--teleport start--><!--teleport end--></div><!--]--></div></section><section id="no-fallback"><div> This is a .server (20ms) async component that was very long ... <div id="async-server-component-count">42</div><div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><!--[--><div style="display: contents;" data-island-slot="default"><!--teleport start--><!--teleport end--></div><!--]--></div></section><div> ServerWithClient.server.vue : <p>count: 0</p> This component should not be preloaded <div><!--[--><div>a</div><div>b</div><div>c</div><!--]--></div> This is not interactive <div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><div class="interactive-component-wrapper" style="border:solid 1px red;"> The component bellow is not a slot but declared as interactive <div class="sugar-counter" nuxt-client=""> Sugar Counter 12 x 1 = 12 <button> Inc </button></div></div></div>"')
} else {
expect(text).toMatchInlineSnapshot(`" End page <pre></pre><section id="fallback"><div> This is a .server (20ms) async component that was very long ... <div id="async-server-component-count">42</div><div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><!--[--><div style="display: contents;" data-island-slot="default"><!--teleport start--><!--teleport end--></div><!--]--></div></section><section id="no-fallback"><div> This is a .server (20ms) async component that was very long ... <div id="async-server-component-count">42</div><div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><!--[--><div style="display: contents;" data-island-slot="default"><!--teleport start--><!--teleport end--></div><!--]--></div></section><div> ServerWithClient.server.vue : <p>count: 0</p> This component should not be preloaded <div><!--[--><div>a</div><div>b</div><div>c</div><!--]--></div> This is not interactive <div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><div class="interactive-component-wrapper" style="border:solid 1px red;"> The component bellow is not a slot but declared as interactive <!--[--><div style="display: contents;" data-island-component="Counter"></div><!--teleport start--><!--teleport end--><!--]--></div></div>"`)
expect(text).toMatchInlineSnapshot('" End page <pre></pre><section id="fallback"><div> This is a .server (20ms) async component that was very long ... <div id="async-server-component-count">42</div><div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><!--[--><div style="display: contents;" data-island-slot="default"><!--teleport start--><!--teleport end--></div><!--]--></div></section><section id="no-fallback"><div> This is a .server (20ms) async component that was very long ... <div id="async-server-component-count">42</div><div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><!--[--><div style="display: contents;" data-island-slot="default"><!--teleport start--><!--teleport end--></div><!--]--></div></section><div> ServerWithClient.server.vue : <p>count: 0</p> This component should not be preloaded <div><!--[--><div>a</div><div>b</div><div>c</div><!--]--></div> This is not interactive <div class="sugar-counter"> Sugar Counter 12 x 1 = 12 <button> Inc </button></div><div class="interactive-component-wrapper" style="border:solid 1px red;"> The component bellow is not a slot but declared as interactive <!--[--><div style="display: contents;" data-island-component="Counter"></div><!--teleport start--><!--teleport end--><!--]--></div></div>"')
}
expect(text).toContain('async component that was very long')
@ -1847,7 +1847,7 @@ describe.skipIf(isDev())('dynamic paths', () => {
await startServer({
env: {
NUXT_APP_BUILD_ASSETS_DIR: '/_other/',
NUXT_APP_BASE_URL: '/foo/',
NUXT_APP_BASE_URL: '/foo/'
}
})
@ -1889,7 +1889,7 @@ describe.skipIf(isDev())('dynamic paths', () => {
await startServer({
env: {
NUXT_APP_BUILD_ASSETS_DIR: '/_other/',
NUXT_APP_BASE_URL: '/foo/',
NUXT_APP_BASE_URL: '/foo/'
}
})
const { headers } = await fetch('/foo/navigate-to/', { redirect: 'manual' })
@ -2444,7 +2444,7 @@ describe('keepalive', () => {
'keepalive-in-nuxtpage-2',
'keepalive-in-nuxtpage',
'not-keepalive',
'keepalive-in-nuxtpage-2',
'keepalive-in-nuxtpage-2'
]
for (const slug of slugs) {

View File

@ -19,7 +19,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
for (const outputDir of ['.output', '.output-inline']) {
it('default client bundle size', async () => {
const clientStats = await analyzeSizes('**/*.js', join(rootDir, outputDir, 'public'))
expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot(`"105k"`)
expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot('"105k"')
expect(clientStats.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
[
"_nuxt/entry.js",
@ -32,10 +32,10 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
const serverDir = join(rootDir, '.output/server')
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"205k"`)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"205k"')
const modules = await analyzeSizes('node_modules/**/*', serverDir)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1335k"`)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"1335k"')
const packages = modules.files
.filter(m => m.endsWith('package.json'))
@ -72,10 +72,10 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
const serverDir = join(rootDir, '.output-inline/server')
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"524k"`)
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"524k"')
const modules = await analyzeSizes('node_modules/**/*', serverDir)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"78.0k"`)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"78.0k"')
const packages = modules.files
.filter(m => m.endsWith('package.json'))

View File

@ -3,7 +3,7 @@ import { addTypeTemplate } from 'nuxt/kit'
export default defineNuxtConfig({
experimental: {
typedPages: true,
appManifest: true,
appManifest: true
},
future: {
typescriptBundlerResolution: process.env.MODULE_RESOLUTION === 'bundler'

View File

@ -331,7 +331,7 @@ describe('head', () => {
})
it('types head for defineNuxtComponent', () => {
defineNuxtComponent({
head(nuxtApp) {
head (nuxtApp) {
expectTypeOf(nuxtApp).not.toBeAny()
return {
title: 'Site Title'
@ -341,9 +341,9 @@ describe('head', () => {
defineNuxtComponent({
// @ts-expect-error wrong return type for head function
head() {
head () {
return {
'test': true
test: true
}
}
})

View File

@ -10,40 +10,40 @@ export default defineNuxtModule({
addComponent({
name: 'DCompClient',
filePath: resolve('./runtime/components'),
mode: 'client',
mode: 'client'
})
addComponent({
name: 'DCompServer',
filePath: resolve('./runtime/components'),
mode: 'server',
mode: 'server'
})
addComponent({
name: 'DCompAll',
filePath: resolve('./runtime/components'),
mode: 'all',
mode: 'all'
})
addComponent({
name: 'NCompClient',
export: 'NComp',
filePath: resolve('./runtime/components'),
mode: 'client',
mode: 'client'
})
addComponent({
name: 'NCompServer',
export: 'NComp',
filePath: resolve('./runtime/components'),
mode: 'server',
mode: 'server'
})
addComponent({
name: 'NCompAll',
export: 'NComp',
filePath: resolve('./runtime/components'),
mode: 'all',
mode: 'all'
})
},
}
})

View File

@ -3,11 +3,11 @@ import { defineComponent, h } from 'vue'
export default defineComponent({
name: 'DComp',
props: { message: String },
render: (props: any) => h('h1', props.message),
render: (props: any) => h('h1', props.message)
})
export const NComp = defineComponent({
name: 'NComp',
props: { message: String },
render: (props: any) => h('h1', props.message),
render: (props: any) => h('h1', props.message)
})

View File

@ -11,21 +11,21 @@ export default defineNuxtModule({
name: 'NCompClient',
export: 'NComp',
filePath: resolve('./runtime/components'),
mode: 'client',
mode: 'client'
})
addComponent({
name: 'NCompServer',
export: 'NComp',
filePath: resolve('./runtime/components'),
mode: 'server',
mode: 'server'
})
addComponent({
name: 'NCompAll',
export: 'NComp',
filePath: resolve('./runtime/components'),
mode: 'all',
mode: 'all'
})
},
}
})

View File

@ -3,5 +3,5 @@ import { defineComponent, h } from 'vue'
export const NComp = defineComponent({
name: 'NComp',
props: { message: String },
render: (props: any) => h('h1', props.message),
render: (props: any) => h('h1', props.message)
})

View File

@ -1,5 +1,5 @@
import { defineNuxtModule } from 'nuxt/kit'
export default defineNuxtModule({
meta: { name: 'subpath' },
meta: { name: 'subpath' }
})

View File

@ -101,10 +101,10 @@ export default defineNuxtConfig({
addBuildPlugin(plugin)
},
function (_options, nuxt) {
nuxt.hook('pages:extend', pages => {
nuxt.hook('pages:extend', (pages) => {
pages.push({
path: '/manual-redirect',
redirect: '/',
redirect: '/'
})
})
},
@ -201,7 +201,7 @@ export default defineNuxtConfig({
}
},
features: {
inlineStyles: id => !!id && !id.includes('assets.vue'),
inlineStyles: id => !!id && !id.includes('assets.vue')
},
experimental: {
typedPages: true,

View File

@ -3,7 +3,7 @@ const state = useState('test', () => {
let hasAccessToWindow = null as null | boolean
try {
hasAccessToWindow = Object.keys(window).at(0) ? true : false
hasAccessToWindow = !!Object.keys(window).at(0)
} catch {
hasAccessToWindow = null
}

View File

@ -5,4 +5,3 @@ import css from '~/assets/inline-only.css?inline'
<template>
<pre>{{ css }}</pre>
</template>

View File

@ -20,7 +20,7 @@ const count = ref(0)
name="PureComponent"
:props="islandProps"
/>
<div id="wrapped-client-only">
<div id="wrapped-client-only">
<ClientOnly>
<NuxtIsland
name="PureComponent"

View File

@ -3,7 +3,7 @@ import { Buffer } from 'node:buffer'
import process from 'node:process'
const base64 = atob(Buffer.from('Nuxt is Awesome!', 'utf8').toString('base64'))
const cwd = typeof process.cwd == 'function' && "[available]"
const cwd = typeof process.cwd === 'function' && '[available]'
</script>
<template>

View File

@ -12,4 +12,3 @@ const id = useId()
<ComponentWithIds />
</form>
</template>

View File

@ -1,3 +1,3 @@
export default defineEventHandler(async () => {
export default defineEventHandler(() => {
throw createError({ statusCode: 400 })
})

View File

@ -120,21 +120,21 @@ if (process.env.TEST_ENV !== 'built' && !isWindows) {
// initial state
await expectWithPolling(
resolveHmrId,
0,
0
)
// first edit
await triggerHmr()
await expectWithPolling(
resolveHmrId,
1,
1
)
// just in-case
await triggerHmr()
await expectWithPolling(
resolveHmrId,
2,
2
)
// ensure no errors

View File

@ -42,7 +42,7 @@ registerEndpoint('/_nuxt/builds/meta/override.json', defineEventHandler(() => ({
},
prerendered: ['/specific-prerendered']
})))
registerEndpoint('/api/test', defineEventHandler((event) => ({
registerEndpoint('/api/test', defineEventHandler(event => ({
method: event.method,
headers: Object.fromEntries(event.headers.entries())
})))
@ -106,7 +106,7 @@ describe('composables', () => {
'navigateTo',
'abortNavigation',
'setPageLayout',
'defineNuxtComponent',
'defineNuxtComponent'
]
const skippedComposables: string[] = [
'addRouteMiddleware',
@ -248,7 +248,7 @@ describe('useAsyncData', () => {
expect(data.value).toMatchInlineSnapshot('"default"')
})
it('should execute the promise function once when dedupe option is "defer" for multiple calls', async () => {
it('should execute the promise function once when dedupe option is "defer" for multiple calls', () => {
const promiseFn = vi.fn(() => Promise.resolve('test'))
useAsyncData('dedupedKey', promiseFn, { dedupe: 'defer' })
useAsyncData('dedupedKey', promiseFn, { dedupe: 'defer' })
@ -257,7 +257,7 @@ describe('useAsyncData', () => {
expect(promiseFn).toHaveBeenCalledTimes(1)
})
it('should execute the promise function multiple times when dedupe option is not specified for multiple calls', async () => {
it('should execute the promise function multiple times when dedupe option is not specified for multiple calls', () => {
const promiseFn = vi.fn(() => Promise.resolve('test'))
useAsyncData('dedupedKey', promiseFn)
useAsyncData('dedupedKey', promiseFn)
@ -266,7 +266,7 @@ describe('useAsyncData', () => {
expect(promiseFn).toHaveBeenCalledTimes(3)
})
it('should execute the promise function as per dedupe option when different dedupe options are used for multiple calls', async () => {
it('should execute the promise function as per dedupe option when different dedupe options are used for multiple calls', () => {
const promiseFn = vi.fn(() => Promise.resolve('test'))
useAsyncData('dedupedKey', promiseFn, { dedupe: 'defer' })
useAsyncData('dedupedKey', promiseFn)
@ -556,13 +556,13 @@ describe.skipIf(process.env.TEST_MANIFEST === 'manifest-off')('app manifests', (
describe('routing utilities: `navigateTo`', () => {
it('navigateTo should disallow navigation to external URLs by default', () => {
expect(() => navigateTo('https://test.com')).toThrowErrorMatchingInlineSnapshot(`[Error: Navigating to an external URL is not allowed by default. Use \`navigateTo(url, { external: true })\`.]`)
expect(() => navigateTo('https://test.com')).toThrowErrorMatchingInlineSnapshot('[Error: Navigating to an external URL is not allowed by default. Use `navigateTo(url, { external: true })`.]')
expect(() => navigateTo('https://test.com', { external: true })).not.toThrow()
})
it('navigateTo should disallow navigation to data/script URLs', () => {
const urls = [
['data:alert("hi")', 'data'],
['\0data:alert("hi")', 'data'],
['\0data:alert("hi")', 'data']
]
for (const [url, protocol] of urls) {
expect(() => navigateTo(url, { external: true })).toThrowError(`Cannot navigate to a URL with '${protocol}:' protocol.`)
@ -571,7 +571,7 @@ describe('routing utilities: `navigateTo`', () => {
})
describe('routing utilities: `useRoute`', () => {
it('should show provide a mock route', async () => {
it('should show provide a mock route', () => {
expect(useRoute()).toMatchObject({
fullPath: '/',
hash: '',
@ -582,7 +582,7 @@ describe('routing utilities: `useRoute`', () => {
params: {},
path: '/',
query: {},
redirectedFrom: undefined,
redirectedFrom: undefined
})
})
})
@ -590,7 +590,7 @@ describe('routing utilities: `useRoute`', () => {
describe('routing utilities: `abortNavigation`', () => {
it('should throw an error if one is provided', () => {
const error = useError()
expect(() => abortNavigation({ message: 'Page not found' })).toThrowErrorMatchingInlineSnapshot(`[Error: Page not found]`)
expect(() => abortNavigation({ message: 'Page not found' })).toThrowErrorMatchingInlineSnapshot('[Error: Page not found]')
expect(error.value).toBeFalsy()
})
it('should block navigation if no error is provided', () => {
@ -607,7 +607,7 @@ describe('routing utilities: `setPageLayout`', () => {
route.meta.layout = undefined
})
it('should not set layout directly if run within middleware', async () => {
it('should not set layout directly if run within middleware', () => {
const route = useRoute()
const nuxtApp = useNuxtApp()
nuxtApp._processingMiddleware = true
@ -632,7 +632,7 @@ describe('useCookie', () => {
it('should watch custom cookie refs', () => {
const user = useCookie('userInfo', {
default: () => ({ score: -1 }),
maxAge: 60 * 60,
maxAge: 60 * 60
})
const computedVal = computed(() => user.value.score)
expect(computedVal.value).toBe(-1)

View File

@ -135,7 +135,6 @@ describe('runtime server component', () => {
})
})
describe('client components', () => {
it('expect swapping nuxt-client should not trigger errors #25289', async () => {
const mockPath = '/nuxt-client.js'
@ -198,7 +197,7 @@ describe('client components', () => {
// @ts-expect-error mock
vi.mocked(fetch).mockImplementation(() => ({
id: '123',
html: `<div data-island-uid>hello<div><div>fallback</div></div></div>`,
html: '<div data-island-uid>hello<div><div>fallback</div></div></div>',
state: {},
head: {
link: [],
@ -267,7 +266,7 @@ describe('client components', () => {
default: {
name: 'ClientWithSlot',
setup (_, { slots }) {
return () => h('div', { class: "client-component" }, slots.default())
return () => h('div', { class: 'client-component' }, slots.default())
}
}
}))
@ -300,7 +299,7 @@ describe('client components', () => {
vi.stubGlobal('fetch', stubFetch)
const wrapper = await mountSuspended(NuxtIsland, {
props: {
name: 'NuxtClientWithSlot',
name: 'NuxtClientWithSlot'
},
attachTo: 'body'
})

View File

@ -206,7 +206,7 @@ describe('plugin dependsOn', () => {
pluginFactory('A', ['B'], sequence),
pluginFactory('B', ['C'], sequence),
pluginFactory('C', ['D'], sequence),
pluginFactory('D', [], sequence),
pluginFactory('D', [], sequence)
]
await applyPlugins(nuxtApp, plugins)
@ -251,7 +251,7 @@ describe('plugin dependsOn', () => {
const plugins = [
pluginFactory('A', undefined, sequence, false),
pluginFactory('B', ['A', 'C'], sequence, false),
pluginFactory('C', undefined, sequence, false),
pluginFactory('C', undefined, sequence, false)
]
await applyPlugins(nuxtApp, plugins)
@ -261,7 +261,7 @@ describe('plugin dependsOn', () => {
'start C',
'end C',
'start B',
'end B',
'end B'
])
})
@ -269,8 +269,8 @@ describe('plugin dependsOn', () => {
const nuxtApp = useNuxtApp()
const sequence: string[] = []
const plugins = [
pluginFactory('B', undefined, sequence,),
pluginFactory('C', ['A', 'B'], sequence,),
pluginFactory('B', undefined, sequence),
pluginFactory('C', ['A', 'B'], sequence)
]
await applyPlugins(nuxtApp, plugins)
@ -278,7 +278,7 @@ describe('plugin dependsOn', () => {
'start B',
'end B',
'start C',
'end C',
'end C'
])
})
})