diff --git a/.eslintrc b/.eslintrc index 513682b8ec4a..a72cf012daf9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -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", { diff --git a/nuxt.config.ts b/nuxt.config.ts index 447512fab7d9..cae173464997 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -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\' })' }) } - ], + ] }) diff --git a/package.json b/package.json index 3391dd08621b..f187a88f07c1 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/packages/kit/src/internal/template.ts b/packages/kit/src/internal/template.ts index 389e457d1cb1..1831e6a854bd 100644 --- a/packages/kit/src/internal/template.ts +++ b/packages/kit/src/internal/template.ts @@ -9,7 +9,7 @@ import { toArray } from '../utils' /** @deprecated */ // TODO: Remove support for compiling ejs templates in v4 -export async function compileTemplate (template: NuxtTemplate, ctx: any) { +export async function compileTemplate (template: NuxtTemplate, ctx: any) { const data = { ...ctx, options: template.options } if (template.src) { try { diff --git a/packages/kit/src/logger.test.ts b/packages/kit/src/logger.test.ts index a3cc49541d45..44aa6ed3cd4e 100644 --- a/packages/kit/src/logger.test.ts +++ b/packages/kit/src/logger.test.ts @@ -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') + }) }) diff --git a/packages/kit/src/logger.ts b/packages/kit/src/logger.ts index be9500348088..8572b1155541 100644 --- a/packages/kit/src/logger.ts +++ b/packages/kit/src/logger.ts @@ -1,5 +1,5 @@ import { consola } from 'consola' -import type { ConsolaOptions } from 'consola'; +import type { ConsolaOptions } from 'consola' export const logger = consola diff --git a/packages/kit/test/generate-types.spec.ts b/packages/kit/test/generate-types.spec.ts index ea6cc10f47bc..35646fb197be 100644 --- a/packages/kit/test/generate-types.spec.ts +++ b/packages/kit/test/generate-types.spec.ts @@ -22,9 +22,9 @@ const mockNuxt = { modules: [], _layers: [{ config: { srcDir: '/my-app' } }], _installedModules: [], - _modules: [], + _modules: [] }, - callHook: () => {}, + callHook: () => {} } satisfies DeepPartial as unknown as Nuxt const mockNuxtWithOptions = (options: NuxtConfig) => defu({ options }, mockNuxt) as Nuxt diff --git a/packages/kit/test/load-nuxt-config.bench.ts b/packages/kit/test/load-nuxt-config.bench.ts index ee8ff33eeb7c..bcee6a730b35 100644 --- a/packages/kit/test/load-nuxt-config.bench.ts +++ b/packages/kit/test/load-nuxt-config.bench.ts @@ -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', () => { diff --git a/packages/nuxt/src/app/compat/interval.ts b/packages/nuxt/src/app/compat/interval.ts index 74adf6c39c0e..4251c9f9a2bf 100644 --- a/packages/nuxt/src/app/compat/interval.ts +++ b/packages/nuxt/src/app/compat/interval.ts @@ -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) + } diff --git a/packages/nuxt/src/app/components/client-only.ts b/packages/nuxt/src/app/components/client-only.ts index a52634712275..ec002d460d27 100644 --- a/packages/nuxt/src/app/components/client-only.ts +++ b/packages/nuxt/src/app/components/client-only.ts @@ -33,7 +33,7 @@ export default defineComponent({ const cache = new WeakMap() -/*@__NO_SIDE_EFFECTS__*/ +/* @__NO_SIDE_EFFECTS__ */ export function createClientOnly (component: T) { if (cache.has(component)) { return cache.get(component) diff --git a/packages/nuxt/src/app/components/nuxt-island.ts b/packages/nuxt/src/app/components/nuxt-island.ts index 65a2a9ddc97f..6fb9e97409a4 100644 --- a/packages/nuxt/src/app/components/nuxt-island.ts +++ b/packages/nuxt/src/app/components/nuxt-island.ts @@ -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)] diff --git a/packages/nuxt/src/app/components/nuxt-link.ts b/packages/nuxt/src/app/components/nuxt-link.ts index e3ecfd29a9ce..7ced9e872419 100644 --- a/packages/nuxt/src/app/components/nuxt-link.ts +++ b/packages/nuxt/src/app/components/nuxt-link.ts @@ -22,29 +22,6 @@ const firstNonUndefined = (...args: (T | undefined)[]) => args.find(arg => a const NuxtLinkDevKeySymbol: InjectionKey = 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, - Pick { - /** - * 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' -} - /** * is a drop-in replacement for both Vue Router's component and HTML's tag. * @see https://nuxt.com/docs/api/components/nuxt-link @@ -88,7 +65,30 @@ export interface NuxtLinkProps extends Omit { 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, + Pick { + /** + * 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' diff --git a/packages/nuxt/src/app/components/nuxt-loading-indicator.ts b/packages/nuxt/src/app/components/nuxt-loading-indicator.ts index 1020be8164af..2ccc49767c75 100644 --- a/packages/nuxt/src/app/components/nuxt-loading-indicator.ts +++ b/packages/nuxt/src/app/components/nuxt-loading-indicator.ts @@ -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({ diff --git a/packages/nuxt/src/app/components/nuxt-teleport-island-slot.ts b/packages/nuxt/src/app/components/nuxt-teleport-island-slot.ts index 7fb7287c4537..fd3d52002a95 100644 --- a/packages/nuxt/src/app/components/nuxt-teleport-island-slot.ts +++ b/packages/nuxt/src/app/components/nuxt-teleport-island-slot.ts @@ -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 })) } diff --git a/packages/nuxt/src/app/composables/asyncData.ts b/packages/nuxt/src/app/composables/asyncData.ts index 208b3ea2c18d..7028b3fadba2 100644 --- a/packages/nuxt/src/app/composables/asyncData.ts +++ b/packages/nuxt/src/app/composables/asyncData.ts @@ -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 } + 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 } - 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 diff --git a/packages/nuxt/src/app/composables/component.ts b/packages/nuxt/src/app/composables/component.ts index e23436decfb3..d124c38efa95 100644 --- a/packages/nuxt/src/app/composables/component.ts +++ b/packages/nuxt/src/app/composables/component.ts @@ -28,7 +28,7 @@ async function runLegacyAsyncData (res: Record | Promise (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 (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 }) } diff --git a/packages/nuxt/src/app/composables/error.ts b/packages/nuxt/src/app/composables/error.ts index 80ab8a83a057..dc4dd8e6a2ea 100644 --- a/packages/nuxt/src/app/composables/error.ts +++ b/packages/nuxt/src/app/composables/error.ts @@ -52,10 +52,8 @@ export const clearError = async (options: { redirect?: string } = {}) => { /** @since 3.0.0 */ export const isNuxtError = ( - error?: string | object -): error is NuxtError => ( - !!error && typeof error === 'object' && NUXT_ERROR_SIGNATURE in error -) + error?: string | object +): error is NuxtError => !!error && typeof error === 'object' && NUXT_ERROR_SIGNATURE in error /** @since 3.0.0 */ export const createError = ( diff --git a/packages/nuxt/src/app/composables/fetch.ts b/packages/nuxt/src/app/composables/fetch.ts index 10e4d27faeb2..f907e6d2aed2 100644 --- a/packages/nuxt/src/app/composables/fetch.ts +++ b/packages/nuxt/src/app/composables/fetch.ts @@ -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> = [ toValue(opts.method as MaybeRef | undefined)?.toUpperCase() || 'GET', - toValue(opts.baseURL), + toValue(opts.baseURL) ] for (const _obj of [opts.params || opts.query]) { const obj = toValue(_obj) diff --git a/packages/nuxt/src/app/composables/preview.ts b/packages/nuxt/src/app/composables/preview.ts index af2c3f33cb1f..697ddaad5d57 100644 --- a/packages/nuxt/src/app/composables/preview.ts +++ b/packages/nuxt/src/app/composables/preview.ts @@ -29,7 +29,7 @@ export function usePreviewMode (options: PreviewModeOpti if (preview.value._initialized) { return { enabled: toRef(preview.value, 'enabled'), - state: preview.value.state as S extends void ? Preview['state'] : (NonNullable & Preview['state']), + state: preview.value.state as S extends void ? Preview['state'] : (NonNullable & Preview['state']) } } @@ -56,7 +56,7 @@ export function usePreviewMode (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 (options: PreviewModeOpti return { enabled: toRef(preview.value, 'enabled'), - state: preview.value.state as S extends void ? Preview['state'] : (NonNullable & Preview['state']), + state: preview.value.state as S extends void ? Preview['state'] : (NonNullable & Preview['state']) } } diff --git a/packages/nuxt/src/app/composables/router.ts b/packages/nuxt/src/app/composables/router.ts index 83501f96f3f0..a0c033d73de1 100644 --- a/packages/nuxt/src/app/composables/router.ts +++ b/packages/nuxt/src/app/composables/router.ts @@ -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) => { diff --git a/packages/nuxt/src/app/entry.ts b/packages/nuxt/src/app/entry.ts index 72d889fb2c53..e4a7fad6c5fa 100644 --- a/packages/nuxt/src/app/entry.ts +++ b/packages/nuxt/src/app/entry.ts @@ -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 } diff --git a/packages/nuxt/src/app/nuxt.ts b/packages/nuxt/src/app/nuxt.ts index 4ba36f418656..4071bfc8b273 100644 --- a/packages/nuxt/src/app/nuxt.ts +++ b/packages/nuxt/src/app/nuxt.ts @@ -21,7 +21,7 @@ import type { ViewTransition } from './plugins/view-transitions.client' import type { NuxtAppLiterals } from '#app' -const nuxtAppCtx = /*@__PURE__*/ getContext('nuxt-app', { +const nuxtAppCtx = /* @__PURE__ */ getContext('nuxt-app', { asyncContext: !!__NUXT_ASYNC_CONTEXT__ && import.meta.server }) @@ -406,7 +406,7 @@ export async function applyPlugins (nuxtApp: NuxtApp, plugins: Array> (plugin: Plugin | ObjectPlugin): Plugin & ObjectPlugin { if (typeof plugin === 'function') { return plugin } @@ -415,7 +415,7 @@ export function defineNuxtPlugin> (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 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): RuntimeConfig { return useNuxtApp().$config } diff --git a/packages/nuxt/src/components/islandsTransform.ts b/packages/nuxt/src/components/islandsTransform.ts index 6692277a9c2c..5d4f452508f9 100644 --- a/packages/nuxt/src/components/islandsTransform.ts +++ b/packages/nuxt/src/components/islandsTransform.ts @@ -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, ``) + s.overwrite(startingIndex + loc[0].start, startingIndex + loc[1].end, ``) } const slotName = attributes.name ?? 'default' diff --git a/packages/nuxt/src/components/module.ts b/packages/nuxt/src/components/module.ts index bcc6fb259bbc..7be0c98d61e1 100644 --- a/packages/nuxt/src/components/module.ts +++ b/packages/nuxt/src/components/module.ts @@ -231,20 +231,20 @@ export default defineNuxtModule({ 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) )}`) - } + } } if (isServer) { @@ -254,7 +254,7 @@ export default defineNuxtModule({ isDev: nuxt.options.dev, selectiveClient })) - } + } } if (!isServer && nuxt.options.experimental.componentIslands) { config.plugins.push({ diff --git a/packages/nuxt/src/components/runtime/client-component.ts b/packages/nuxt/src/components/runtime/client-component.ts index c7b68e6660ca..97558c8946ea 100644 --- a/packages/nuxt/src/components/runtime/client-component.ts +++ b/packages/nuxt/src/components/runtime/client-component.ts @@ -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) diff --git a/packages/nuxt/src/components/runtime/server-component.ts b/packages/nuxt/src/components/runtime/server-component.ts index d34176b9fd32..4b52e46a0059 100644 --- a/packages/nuxt/src/components/runtime/server-component.ts +++ b/packages/nuxt/src/components/runtime/server-component.ts @@ -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, diff --git a/packages/nuxt/src/core/nitro.ts b/packages/nuxt/src/core/nitro.ts index e2a1ee456a5e..114ac243385a 100644 --- a/packages/nuxt/src/core/nitro.ts +++ b/packages/nuxt/src/core/nitro.ts @@ -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 diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts index a0746c002226..0ea6c659fd00 100644 --- a/packages/nuxt/src/core/nuxt.ts +++ b/packages/nuxt/src/core/nuxt.ts @@ -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, { diff --git a/packages/nuxt/src/core/plugins/unctx.ts b/packages/nuxt/src/core/plugins/unctx.ts index c6ef9eb0545c..5a0ebe782ab9 100644 --- a/packages/nuxt/src/core/plugins/unctx.ts +++ b/packages/nuxt/src/core/plugins/unctx.ts @@ -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? diff --git a/packages/nuxt/src/core/runtime/nitro/cache-driver.ts b/packages/nuxt/src/core/runtime/nitro/cache-driver.ts index dfd5d701a8ba..b76153a859f9 100644 --- a/packages/nuxt/src/core/runtime/nitro/cache-driver.ts +++ b/packages/nuxt/src/core/runtime/nitro/cache-driver.ts @@ -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) - }, + } } }) diff --git a/packages/nuxt/src/core/runtime/nitro/error.ts b/packages/nuxt/src/core/runtime/nitro/error.ts index c4d0a1361267..ebb7addc8fa1 100644 --- a/packages/nuxt/src/core/runtime/nitro/error.ts +++ b/packages/nuxt/src/core/runtime/nitro/error.ts @@ -54,13 +54,15 @@ export default 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) { diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index e1fabfb458c7..128a30242327 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -53,19 +53,11 @@ export interface NuxtRenderHTMLContext { bodyAppend: string[] } -export interface NuxtIslandContext { - id?: string - name: string - props?: Record - url?: string - slots: Record> - components: Record> -} - export interface NuxtIslandSlotResponse { props: Array fallback?: string } + export interface NuxtIslandClientResponse { html: string props: unknown @@ -73,6 +65,15 @@ export interface NuxtIslandClientResponse { slots?: Record } +export interface NuxtIslandContext { + id?: string + name: string + props?: Record + url?: string + slots: Record> + components: Record> +} + 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>() : null const sharedPrerenderKeys = new Set() -const sharedPrerenderCache = import.meta.prerender && process.env.NUXT_SHARED_DATA ? { - get (key: string): Promise | undefined { - if (sharedPrerenderKeys.has(key)) { - return sharedPrerenderPromises!.get(key) ?? useStorage('internal:nuxt:prerender:shared').getItem(key) as Promise +const sharedPrerenderCache = import.meta.prerender && process.env.NUXT_SHARED_DATA + ? { + get (key: string): Promise | undefined { + if (sharedPrerenderKeys.has(key)) { + return sharedPrerenderPromises!.get(key) ?? useStorage('internal:nuxt:prerender:shared').getItem(key) as Promise + } + }, + async set (key: string, value: Promise): Promise { + 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 (key: string, value: Promise): Promise { - 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 { // TODO: Strict validation for url @@ -221,7 +224,7 @@ async function getIslandContext (event: H3Event): Promise { name: componentName, props: destr(context.props) || {}, slots: {}, - components: {}, + components: {} } return ctx @@ -302,8 +305,8 @@ export default defineRenderHandler(async (event): Promise' - + `` - + `${joinTags(html.head)}` - + `${joinTags(html.bodyPrepend)}${joinTags(html.body)}${joinTags(html.bodyAppend)}` - + '' + return '' + + `` + + `${joinTags(html.head)}` + + `${joinTags(html.bodyPrepend)}${joinTags(html.body)}${joinTags(html.bodyAppend)}` + + '' } async function renderInlineStyles (usedModules: Set | string[]): Promise { @@ -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 diff --git a/packages/nuxt/src/core/templates.ts b/packages/nuxt/src/core/templates.ts index c43964e36300..bbf9c0e7c577 100644 --- a/packages/nuxt/src/core/templates.ts +++ b/packages/nuxt/src/core/templates.ts @@ -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 = { diff --git a/packages/nuxt/src/head/runtime/components.ts b/packages/nuxt/src/head/runtime/components.ts index 3969a082a6a5..f2bbfe2261ea 100644 --- a/packages/nuxt/src/head/runtime/components.ts +++ b/packages/nuxt/src/head/runtime/components.ts @@ -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 diff --git a/packages/nuxt/src/pages/module.ts b/packages/nuxt/src/pages/module.ts index d62b732b7acd..f48a61f1f69e 100644 --- a/packages/nuxt/src/pages/module.ts +++ b/packages/nuxt/src/pages/module.ts @@ -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') } }) diff --git a/packages/nuxt/src/pages/runtime/composables.ts b/packages/nuxt/src/pages/runtime/composables.ts index dd3603b82770..d81b30551297 100644 --- a/packages/nuxt/src/pages/runtime/composables.ts +++ b/packages/nuxt/src/pages/runtime/composables.ts @@ -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 => {} diff --git a/packages/nuxt/src/pages/runtime/page.ts b/packages/nuxt/src/pages/runtime/page.ts index 5e3cf7758c99..aafaeb8e893a 100644 --- a/packages/nuxt/src/pages/runtime/page.ts +++ b/packages/nuxt/src/pages/runtime/page.ts @@ -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' diff --git a/packages/nuxt/src/pages/runtime/plugins/check-if-page-unused.ts b/packages/nuxt/src/pages/runtime/plugins/check-if-page-unused.ts index a347ff11cb6c..57ae91fe6e63 100644 --- a/packages/nuxt/src/pages/runtime/plugins/check-if-page-unused.ts +++ b/packages/nuxt/src/pages/runtime/plugins/check-if-page-unused.ts @@ -11,9 +11,9 @@ export default defineNuxtPlugin({ function checkIfPageUnused () { if (!error.value && !nuxtApp._isNuxtPageUsed) { console.warn( - '[nuxt] Your project has pages but the `` component has not been used.' - + ' You might be using the `` 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 `` component has not been used.' + + ' You might be using the `` 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.' ) } } diff --git a/packages/nuxt/src/pages/utils.ts b/packages/nuxt/src/pages/utils.ts index 3a33b5aa575f..af3386e70e50 100644 --- a/packages/nuxt/src/pages/utils.ts +++ b/packages/nuxt/src/pages/utils.ts @@ -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 = 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] diff --git a/packages/nuxt/test/app.test.ts b/packages/nuxt/test/app.test.ts index cb9075b6c5b2..47bbdbc28aa9 100644 --- a/packages/nuxt/test/app.test.ts +++ b/packages/nuxt/test/app.test.ts @@ -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(''))).toMatchInlineSnapshot(` diff --git a/packages/nuxt/test/devonly.test.ts b/packages/nuxt/test/devonly.test.ts index 1bb497fdc4f4..b49b6ec273dd 100644 --- a/packages/nuxt/test/devonly.test.ts +++ b/packages/nuxt/test/devonly.test.ts @@ -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 = ` ` - const result = await viteTransform(source, 'some id') + const result = await viteTransform(source, 'some id') expect(result).toMatchInlineSnapshot(` "