mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
chore: add back stylistic rules and lint project
This commit is contained in:
parent
3782ac0a2c
commit
7252b56d52
56
.eslintrc
56
.eslintrc
@ -12,11 +12,67 @@
|
|||||||
},
|
},
|
||||||
"plugins": ["jsdoc", "import", "unicorn", "no-only-tests"],
|
"plugins": ["jsdoc", "import", "unicorn", "no-only-tests"],
|
||||||
"extends": [
|
"extends": [
|
||||||
|
"standard",
|
||||||
"plugin:jsdoc/recommended",
|
"plugin:jsdoc/recommended",
|
||||||
"@nuxt/eslint-config",
|
"@nuxt/eslint-config",
|
||||||
"plugin:import/typescript"
|
"plugin:import/typescript"
|
||||||
],
|
],
|
||||||
"rules": {
|
"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": [
|
"sort-imports": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
|
@ -9,8 +9,8 @@ export default defineNuxtConfig({
|
|||||||
function () {
|
function () {
|
||||||
addPluginTemplate({
|
addPluginTemplate({
|
||||||
filename: 'plugins/my-plugin.mjs',
|
filename: 'plugins/my-plugin.mjs',
|
||||||
getContents: () => `export default defineNuxtPlugin({ name: 'my-plugin' })`
|
getContents: () => 'export default defineNuxtPlugin({ name: \'my-plugin\' })'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
})
|
})
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
"consola": "3.2.3",
|
"consola": "3.2.3",
|
||||||
"devalue": "4.3.2",
|
"devalue": "4.3.2",
|
||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
|
"eslint-config-standard": "^17.1.0",
|
||||||
"eslint-plugin-import": "2.29.1",
|
"eslint-plugin-import": "2.29.1",
|
||||||
"eslint-plugin-jsdoc": "48.2.1",
|
"eslint-plugin-jsdoc": "48.2.1",
|
||||||
"eslint-plugin-no-only-tests": "3.1.0",
|
"eslint-plugin-no-only-tests": "3.1.0",
|
||||||
|
@ -9,7 +9,7 @@ import { toArray } from '../utils'
|
|||||||
|
|
||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
// TODO: Remove support for compiling ejs templates in v4
|
// 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 }
|
const data = { ...ctx, options: template.options }
|
||||||
if (template.src) {
|
if (template.src) {
|
||||||
try {
|
try {
|
||||||
|
@ -3,13 +3,13 @@ import { describe, expect, it, vi } from 'vitest'
|
|||||||
import { consola } from 'consola'
|
import { consola } from 'consola'
|
||||||
import { logger, useLogger } from './logger'
|
import { logger, useLogger } from './logger'
|
||||||
|
|
||||||
vi.mock("consola", () => {
|
vi.mock('consola', () => {
|
||||||
const logger = {} as any;
|
const logger = {} as any
|
||||||
|
|
||||||
logger.create = vi.fn(() => ({...logger}));
|
logger.create = vi.fn(() => ({ ...logger }))
|
||||||
logger.withTag = vi.fn(() => ({...logger}));
|
logger.withTag = vi.fn(() => ({ ...logger }))
|
||||||
|
|
||||||
return { consola: logger };
|
return { consola: logger }
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('logger', () => {
|
describe('logger', () => {
|
||||||
@ -20,29 +20,28 @@ describe('logger', () => {
|
|||||||
|
|
||||||
describe('useLogger', () => {
|
describe('useLogger', () => {
|
||||||
it('should expose consola when not passing a tag', () => {
|
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', () => {
|
it('should create a new instance when passing a tag', () => {
|
||||||
const logger = vi.mocked(consola);
|
const logger = vi.mocked(consola)
|
||||||
|
|
||||||
const instance = useLogger("tag");
|
const instance = useLogger('tag')
|
||||||
|
|
||||||
expect(instance).toEqual(logger);
|
expect(instance).toEqual(logger)
|
||||||
expect(instance).not.toBe(logger);
|
expect(instance).not.toBe(logger)
|
||||||
expect(logger.create).toBeCalledWith({});
|
expect(logger.create).toBeCalledWith({})
|
||||||
expect(logger.withTag).toBeCalledWith("tag");
|
expect(logger.withTag).toBeCalledWith('tag')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should create a new instance when passing a tag and options', () => {
|
it('should create a new instance when passing a tag and options', () => {
|
||||||
const logger = vi.mocked(consola);
|
const logger = vi.mocked(consola)
|
||||||
|
|
||||||
const instance = useLogger("tag", { level: 0 });
|
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");
|
|
||||||
});
|
|
||||||
|
|
||||||
|
expect(instance).toEqual(logger)
|
||||||
|
expect(instance).not.toBe(logger)
|
||||||
|
expect(logger.create).toBeCalledWith({ level: 0 })
|
||||||
|
expect(logger.withTag).toBeCalledWith('tag')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { consola } from 'consola'
|
import { consola } from 'consola'
|
||||||
import type { ConsolaOptions } from 'consola';
|
import type { ConsolaOptions } from 'consola'
|
||||||
|
|
||||||
export const logger = consola
|
export const logger = consola
|
||||||
|
|
||||||
|
@ -22,9 +22,9 @@ const mockNuxt = {
|
|||||||
modules: [],
|
modules: [],
|
||||||
_layers: [{ config: { srcDir: '/my-app' } }],
|
_layers: [{ config: { srcDir: '/my-app' } }],
|
||||||
_installedModules: [],
|
_installedModules: [],
|
||||||
_modules: [],
|
_modules: []
|
||||||
},
|
},
|
||||||
callHook: () => {},
|
callHook: () => {}
|
||||||
} satisfies DeepPartial<Nuxt> as unknown as Nuxt
|
} satisfies DeepPartial<Nuxt> as unknown as Nuxt
|
||||||
|
|
||||||
const mockNuxtWithOptions = (options: NuxtConfig) => defu({ options }, mockNuxt) as Nuxt
|
const mockNuxtWithOptions = (options: NuxtConfig) => defu({ options }, mockNuxt) as Nuxt
|
||||||
|
@ -9,7 +9,7 @@ const fixtures = {
|
|||||||
'basic test fixture': 'test/fixtures/basic',
|
'basic test fixture': 'test/fixtures/basic',
|
||||||
'basic test fixture (types)': 'test/fixtures/basic-types',
|
'basic test fixture (types)': 'test/fixtures/basic-types',
|
||||||
'minimal test fixture': 'test/fixtures/minimal',
|
'minimal test fixture': 'test/fixtures/minimal',
|
||||||
'minimal test fixture (types)': 'test/fixtures/minimal-types',
|
'minimal test fixture (types)': 'test/fixtures/minimal-types'
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('loadNuxtConfig', () => {
|
describe('loadNuxtConfig', () => {
|
||||||
|
@ -2,7 +2,9 @@ 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`.'
|
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 : () => {
|
export const setInterval = import.meta.client
|
||||||
|
? window.setInterval
|
||||||
|
: () => {
|
||||||
if (import.meta.dev) {
|
if (import.meta.dev) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
@ -11,4 +13,4 @@ export const setInterval = import.meta.client ? window.setInterval : () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.error(intervalError)
|
console.error(intervalError)
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
const cache = new WeakMap()
|
const cache = new WeakMap()
|
||||||
|
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export function createClientOnly<T extends ComponentOptions> (component: T) {
|
export function createClientOnly<T extends ComponentOptions> (component: T) {
|
||||||
if (cache.has(component)) {
|
if (cache.has(component)) {
|
||||||
return cache.get(component)
|
return cache.get(component)
|
||||||
|
@ -213,7 +213,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
expose({
|
expose({
|
||||||
refresh: () => fetchComponent(true),
|
refresh: () => fetchComponent(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (import.meta.hot) {
|
if (import.meta.hot) {
|
||||||
@ -264,7 +264,7 @@ export default defineComponent({
|
|||||||
const { html, slots } = info
|
const { html, slots } = info
|
||||||
let replaced = html.replaceAll('data-island-uid', `data-island-uid="${uid.value}"`)
|
let replaced = html.replaceAll('data-island-uid', `data-island-uid="${uid.value}"`)
|
||||||
for (const slot in slots) {
|
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}` }, {
|
teleports.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}` }, {
|
||||||
default: () => [createStaticVNode(replaced, 1)]
|
default: () => [createStaticVNode(replaced, 1)]
|
||||||
|
@ -22,29 +22,6 @@ const firstNonUndefined = <T> (...args: (T | undefined)[]) => args.find(arg => a
|
|||||||
|
|
||||||
const NuxtLinkDevKeySymbol: InjectionKey<boolean> = Symbol('nuxt-link-dev-key')
|
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.
|
* <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
|
* @see https://nuxt.com/docs/api/components/nuxt-link
|
||||||
@ -88,7 +65,30 @@ export interface NuxtLinkProps extends Omit<RouterLinkProps, 'to'> {
|
|||||||
noPrefetch?: boolean
|
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) {
|
export function defineNuxtLink (options: NuxtLinkOptions) {
|
||||||
const componentName = options.componentName || 'NuxtLink'
|
const componentName = options.componentName || 'NuxtLink'
|
||||||
|
|
||||||
|
@ -23,13 +23,13 @@ export default defineComponent({
|
|||||||
estimatedProgress: {
|
estimatedProgress: {
|
||||||
type: Function as unknown as () => (duration: number, elapsed: number) => number,
|
type: Function as unknown as () => (duration: number, elapsed: number) => number,
|
||||||
required: false
|
required: false
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
setup (props, { slots, expose }) {
|
setup (props, { slots, expose }) {
|
||||||
const { progress, isLoading, start, finish, clear } = useLoadingIndicator({
|
const { progress, isLoading, start, finish, clear } = useLoadingIndicator({
|
||||||
duration: props.duration,
|
duration: props.duration,
|
||||||
throttle: props.throttle,
|
throttle: props.throttle,
|
||||||
estimatedProgress: props.estimatedProgress,
|
estimatedProgress: props.estimatedProgress
|
||||||
})
|
})
|
||||||
|
|
||||||
expose({
|
expose({
|
||||||
|
@ -40,7 +40,7 @@ export default defineComponent({
|
|||||||
vnodes.push(h('div', {
|
vnodes.push(h('div', {
|
||||||
style: 'display: contents;',
|
style: 'display: contents;',
|
||||||
'data-island-uid': '',
|
'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
|
// Teleport in slot to not be hydrated client-side with the staticVNode
|
||||||
default: () => [createVNode(Teleport, { to: `island-slot=${componentName};${props.name}` }, slots.default?.())]
|
default: () => [createVNode(Teleport, { to: `island-slot=${componentName};${props.name}` }, slots.default?.())]
|
||||||
@ -49,7 +49,7 @@ export default defineComponent({
|
|||||||
vnodes.push(h('div', {
|
vnodes.push(h('div', {
|
||||||
style: 'display: contents;',
|
style: 'display: contents;',
|
||||||
'data-island-uid': '',
|
'data-island-uid': '',
|
||||||
'data-island-slot': props.name,
|
'data-island-slot': props.name
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +214,9 @@ export function useAsyncData<
|
|||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
|
|
||||||
// When prerendering, share payload data automatically between requests
|
// When prerendering, share payload data automatically between requests
|
||||||
const handler = import.meta.client || !import.meta.prerender || !nuxtApp.ssrContext?._sharedPrerenderCache ? _handler : () => {
|
const handler = import.meta.client || !import.meta.prerender || !nuxtApp.ssrContext?._sharedPrerenderCache
|
||||||
|
? _handler
|
||||||
|
: () => {
|
||||||
const value = nuxtApp.ssrContext!._sharedPrerenderCache!.get(key)
|
const value = nuxtApp.ssrContext!._sharedPrerenderCache!.get(key)
|
||||||
if (value) { return value as Promise<ResT> }
|
if (value) { return value as Promise<ResT> }
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ async function runLegacyAsyncData (res: Record<string, any> | Promise<Record<str
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @since 3.0.0 */
|
/** @since 3.0.0 */
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export const defineNuxtComponent: typeof defineComponent =
|
export const defineNuxtComponent: typeof defineComponent =
|
||||||
function defineNuxtComponent (...args: any[]): any {
|
function defineNuxtComponent (...args: any[]): any {
|
||||||
const [options, key] = args
|
const [options, key] = args
|
||||||
|
@ -92,7 +92,7 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
|||||||
if (store) {
|
if (store) {
|
||||||
store.onchange = (event) => {
|
store.onchange = (event) => {
|
||||||
const cookie = event.changed.find((c: any) => c.name === name)
|
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) {
|
} else if (channel) {
|
||||||
channel.onmessage = ({ data }) => handleChange(data)
|
channel.onmessage = ({ data }) => handleChange(data)
|
||||||
@ -124,7 +124,7 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
|||||||
}
|
}
|
||||||
/** @since 3.10.0 */
|
/** @since 3.10.0 */
|
||||||
export function refreshCookie (name: string) {
|
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 })
|
new BroadcastChannel(`nuxt:cookies:${name}`)?.postMessage({ refresh: true })
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,7 @@ export const clearError = async (options: { redirect?: string } = {}) => {
|
|||||||
/** @since 3.0.0 */
|
/** @since 3.0.0 */
|
||||||
export const isNuxtError = <DataT = unknown>(
|
export const isNuxtError = <DataT = unknown>(
|
||||||
error?: string | object
|
error?: string | object
|
||||||
): error is NuxtError<DataT> => (
|
): error is NuxtError<DataT> => !!error && typeof error === 'object' && NUXT_ERROR_SIGNATURE in error
|
||||||
!!error && typeof error === 'object' && NUXT_ERROR_SIGNATURE in error
|
|
||||||
)
|
|
||||||
|
|
||||||
/** @since 3.0.0 */
|
/** @since 3.0.0 */
|
||||||
export const createError = <DataT = unknown>(
|
export const createError = <DataT = unknown>(
|
||||||
|
@ -243,10 +243,10 @@ export function useLazyFetch<
|
|||||||
autoKey)
|
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>> = [
|
const segments: Array<string | undefined | Record<string, string>> = [
|
||||||
toValue(opts.method as MaybeRef<string | undefined> | undefined)?.toUpperCase() || 'GET',
|
toValue(opts.method as MaybeRef<string | undefined> | undefined)?.toUpperCase() || 'GET',
|
||||||
toValue(opts.baseURL),
|
toValue(opts.baseURL)
|
||||||
]
|
]
|
||||||
for (const _obj of [opts.params || opts.query]) {
|
for (const _obj of [opts.params || opts.query]) {
|
||||||
const obj = toValue(_obj)
|
const obj = toValue(_obj)
|
||||||
|
@ -29,7 +29,7 @@ export function usePreviewMode<S extends EnteredState> (options: PreviewModeOpti
|
|||||||
if (preview.value._initialized) {
|
if (preview.value._initialized) {
|
||||||
return {
|
return {
|
||||||
enabled: toRef(preview.value, 'enabled'),
|
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) {
|
if (import.meta.client && !unregisterRefreshHook) {
|
||||||
refreshNuxtData()
|
refreshNuxtData()
|
||||||
|
|
||||||
unregisterRefreshHook = useRouter().afterEach((() => refreshNuxtData()))
|
unregisterRefreshHook = useRouter().afterEach(() => refreshNuxtData())
|
||||||
}
|
}
|
||||||
} else if (unregisterRefreshHook) {
|
} else if (unregisterRefreshHook) {
|
||||||
unregisterRefreshHook()
|
unregisterRefreshHook()
|
||||||
@ -67,7 +67,7 @@ export function usePreviewMode<S extends EnteredState> (options: PreviewModeOpti
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
enabled: toRef(preview.value, 'enabled'),
|
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'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ export interface RouteMiddleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @since 3.0.0 */
|
/** @since 3.0.0 */
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export function defineNuxtRouteMiddleware (middleware: RouteMiddleware) {
|
export function defineNuxtRouteMiddleware (middleware: RouteMiddleware) {
|
||||||
return middleware
|
return middleware
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ if (import.meta.client) {
|
|||||||
|
|
||||||
const nuxt = createNuxtApp({ vueApp })
|
const nuxt = createNuxtApp({ vueApp })
|
||||||
|
|
||||||
async function handleVueError(error: any) {
|
async function handleVueError (error: any) {
|
||||||
await nuxt.callHook('app:error', error)
|
await nuxt.callHook('app:error', error)
|
||||||
nuxt.payload.error = nuxt.payload.error || createError(error as any)
|
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 the errorHandler is not overridden by the user, we unset it
|
||||||
if (vueApp.config.errorHandler === handleVueError)
|
if (vueApp.config.errorHandler === handleVueError) { vueApp.config.errorHandler = undefined }
|
||||||
vueApp.config.errorHandler = undefined
|
|
||||||
|
|
||||||
return vueApp
|
return vueApp
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import type { ViewTransition } from './plugins/view-transitions.client'
|
|||||||
|
|
||||||
import type { NuxtAppLiterals } from '#app'
|
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
|
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] }
|
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> {
|
export function defineNuxtPlugin<T extends Record<string, unknown>> (plugin: Plugin<T> | ObjectPlugin<T>): Plugin<T> & ObjectPlugin<T> {
|
||||||
if (typeof plugin === 'function') { return plugin }
|
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)
|
return Object.assign(plugin.setup || (() => {}), plugin, { [NuxtPluginIndicator]: true, _name } as const)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export const definePayloadPlugin = defineNuxtPlugin
|
export const definePayloadPlugin = defineNuxtPlugin
|
||||||
|
|
||||||
export function isNuxtPlugin (plugin: unknown) {
|
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.
|
* Returns the current Nuxt instance.
|
||||||
*
|
*
|
||||||
@ -455,7 +455,7 @@ export function tryUseNuxtApp (): NuxtApp | null {
|
|||||||
return nuxtAppInstance || null
|
return nuxtAppInstance || null
|
||||||
}
|
}
|
||||||
|
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
/**
|
/**
|
||||||
* Returns the current Nuxt instance.
|
* Returns the current Nuxt instance.
|
||||||
*
|
*
|
||||||
@ -475,7 +475,7 @@ export function useNuxtApp (): NuxtApp {
|
|||||||
return nuxtAppInstance
|
return nuxtAppInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export function useRuntimeConfig (_event?: H3Event<EventHandlerRequest>): RuntimeConfig {
|
export function useRuntimeConfig (_event?: H3Event<EventHandlerRequest>): RuntimeConfig {
|
||||||
return useNuxtApp().$config
|
return useNuxtApp().$config
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ export const islandsTransform = createUnplugin((options: ServerOnlyComponentTran
|
|||||||
if (children.length) {
|
if (children.length) {
|
||||||
const attrString = Object.entries(attributes).map(([name, value]) => name ? `${name}="${value}" ` : value).join(' ')
|
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, '')
|
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'
|
const slotName = attributes.name ?? 'default'
|
||||||
|
@ -231,17 +231,17 @@ export default defineNuxtModule<ComponentsOptions>({
|
|||||||
|
|
||||||
if (isClient && selectiveClient) {
|
if (isClient && selectiveClient) {
|
||||||
fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}')
|
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({
|
config.plugins.push(componentsChunkPlugin.vite({
|
||||||
getComponents,
|
getComponents,
|
||||||
buildDir: nuxt.options.buildDir
|
buildDir: nuxt.options.buildDir
|
||||||
}))
|
}))
|
||||||
} else {
|
} 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) => {
|
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}`})
|
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`
|
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}`})
|
return Object.assign(acc, { [c.pascalName]: `/@fs/${filePath}` })
|
||||||
}, {} as Record<string, string>)
|
}, {} as Record<string, string>)
|
||||||
)}`)
|
)}`)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { defineAsyncComponent, defineComponent, h } from 'vue'
|
import { defineAsyncComponent, defineComponent, h } from 'vue'
|
||||||
import type { AsyncComponentLoader } 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) => {
|
export const createClientPage = (loader: AsyncComponentLoader) => {
|
||||||
const page = defineAsyncComponent(loader)
|
const page = defineAsyncComponent(loader)
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import NuxtIsland from '#app/components/nuxt-island'
|
|||||||
import { useRoute } from '#app/composables/router'
|
import { useRoute } from '#app/composables/router'
|
||||||
import { isPrerendered } from '#app/composables/payload'
|
import { isPrerendered } from '#app/composables/payload'
|
||||||
|
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export const createServerComponent = (name: string) => {
|
export const createServerComponent = (name: string) => {
|
||||||
return defineComponent({
|
return defineComponent({
|
||||||
name,
|
name,
|
||||||
@ -32,7 +32,7 @@ export const createServerComponent = (name: string) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export const createIslandPage = (name: string) => {
|
export const createIslandPage = (name: string) => {
|
||||||
return defineComponent({
|
return defineComponent({
|
||||||
name,
|
name,
|
||||||
|
@ -227,7 +227,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
output: {},
|
output: {},
|
||||||
plugins: []
|
plugins: []
|
||||||
},
|
},
|
||||||
logLevel: logLevelMapReverse[nuxt.options.logLevel],
|
logLevel: logLevelMapReverse[nuxt.options.logLevel]
|
||||||
} satisfies NitroConfig)
|
} satisfies NitroConfig)
|
||||||
|
|
||||||
// Resolve user-provided paths
|
// Resolve user-provided paths
|
||||||
|
@ -64,11 +64,11 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
nuxt.hook('close', () => nuxtCtx.unset())
|
nuxt.hook('close', () => nuxtCtx.unset())
|
||||||
|
|
||||||
const coreTypePackages = ['nitropack', 'defu', 'h3', '@unhead/vue', 'vue', 'vue-router', '@nuxt/schema']
|
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)
|
const path = await _resolvePath(pkg, { url: nuxt.options.modulesDir }).then(r => resolvePackageJSON(r)).catch(() => null)
|
||||||
if (!path) { return }
|
if (!path) { return }
|
||||||
return [pkg, [dirname(path)]]
|
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
|
// Set nitro resolutions for types that might be obscured with shamefully-hoist=false
|
||||||
nuxt.options.nitro.typescript = defu(nuxt.options.nitro.typescript, {
|
nuxt.options.nitro.typescript = defu(nuxt.options.nitro.typescript, {
|
||||||
|
@ -17,7 +17,7 @@ export const UnctxTransformPlugin = createUnplugin((options: UnctxTransformPlugi
|
|||||||
name: 'unctx:transform',
|
name: 'unctx:transform',
|
||||||
enforce: 'post',
|
enforce: 'post',
|
||||||
transformInclude (id) {
|
transformInclude (id) {
|
||||||
return isVue(id, { type: ['template', 'script']}) || isJS(id)
|
return isVue(id, { type: ['template', 'script'] }) || isJS(id)
|
||||||
},
|
},
|
||||||
transform (code) {
|
transform (code) {
|
||||||
// TODO: needed for webpack - update transform in unctx/unplugin?
|
// TODO: needed for webpack - update transform in unctx/unplugin?
|
||||||
|
@ -21,6 +21,6 @@ export default defineDriver((opts: { base: string }) => {
|
|||||||
},
|
},
|
||||||
async getItem (key, opts) {
|
async getItem (key, opts) {
|
||||||
return await lru.getItem(key, opts) || await fs.getItem(normalizeFsKey(key), opts)
|
return await lru.getItem(key, opts) || await fs.getItem(normalizeFsKey(key), opts)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -54,7 +54,9 @@ export default <NitroErrorHandler> async function errorhandler (error: H3Error,
|
|||||||
const isRenderingError = event.path.startsWith('/__nuxt_error') || !!reqHeaders['x-nuxt-error']
|
const isRenderingError = event.path.startsWith('/__nuxt_error') || !!reqHeaders['x-nuxt-error']
|
||||||
|
|
||||||
// HTML response (via SSR)
|
// HTML response (via SSR)
|
||||||
const res = isRenderingError ? null : await useNitroApp().localFetch(
|
const res = isRenderingError
|
||||||
|
? null
|
||||||
|
: await useNitroApp().localFetch(
|
||||||
withQuery(joinURL(useRuntimeConfig(event).app.baseURL, '/__nuxt_error'), errorObject),
|
withQuery(joinURL(useRuntimeConfig(event).app.baseURL, '/__nuxt_error'), errorObject),
|
||||||
{
|
{
|
||||||
headers: { ...reqHeaders, 'x-nuxt-error': 'true' },
|
headers: { ...reqHeaders, 'x-nuxt-error': 'true' },
|
||||||
|
@ -53,6 +53,18 @@ export interface NuxtRenderHTMLContext {
|
|||||||
bodyAppend: string[]
|
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 {
|
export interface NuxtIslandContext {
|
||||||
id?: string
|
id?: string
|
||||||
name: string
|
name: string
|
||||||
@ -62,17 +74,6 @@ export interface NuxtIslandContext {
|
|||||||
components: Record<string, Omit<NuxtIslandClientResponse, 'html'>>
|
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 {
|
export interface NuxtIslandResponse {
|
||||||
id?: string
|
id?: string
|
||||||
html: 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 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 sharedPrerenderPromises = import.meta.prerender && process.env.NUXT_SHARED_DATA ? new Map<string, Promise<any>>() : null
|
||||||
const sharedPrerenderKeys = new Set<string>()
|
const sharedPrerenderKeys = new Set<string>()
|
||||||
const sharedPrerenderCache = import.meta.prerender && process.env.NUXT_SHARED_DATA ? {
|
const sharedPrerenderCache = import.meta.prerender && process.env.NUXT_SHARED_DATA
|
||||||
get <T = unknown>(key: string): Promise<T> | undefined {
|
? {
|
||||||
|
get<T = unknown> (key: string): Promise<T> | undefined {
|
||||||
if (sharedPrerenderKeys.has(key)) {
|
if (sharedPrerenderKeys.has(key)) {
|
||||||
return sharedPrerenderPromises!.get(key) ?? useStorage('internal:nuxt:prerender:shared').getItem(key) as Promise<T>
|
return sharedPrerenderPromises!.get(key) ?? useStorage('internal:nuxt:prerender:shared').getItem(key) as Promise<T>
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async set <T>(key: string, value: Promise<T>): Promise<void> {
|
async set<T> (key: string, value: Promise<T>): Promise<void> {
|
||||||
sharedPrerenderKeys.add(key)
|
sharedPrerenderKeys.add(key)
|
||||||
sharedPrerenderPromises!.set(key, value)
|
sharedPrerenderPromises!.set(key, value)
|
||||||
useStorage('internal:nuxt:prerender:shared').setItem(key, await value as any)
|
useStorage('internal:nuxt:prerender:shared').setItem(key, await value as any)
|
||||||
// free up memory after the promise is resolved
|
// free up memory after the promise is resolved
|
||||||
.finally(() => sharedPrerenderPromises!.delete(key))
|
.finally(() => sharedPrerenderPromises!.delete(key))
|
||||||
},
|
}
|
||||||
} : null
|
}
|
||||||
|
: null
|
||||||
|
|
||||||
async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
|
async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
|
||||||
// TODO: Strict validation for url
|
// TODO: Strict validation for url
|
||||||
@ -221,7 +224,7 @@ async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
|
|||||||
name: componentName,
|
name: componentName,
|
||||||
props: destr(context.props) || {},
|
props: destr(context.props) || {},
|
||||||
slots: {},
|
slots: {},
|
||||||
components: {},
|
components: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
@ -302,8 +305,8 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
payload: (ssrError ? { error: ssrError } : {}) as NuxtPayload,
|
payload: (ssrError ? { error: ssrError } : {}) as NuxtPayload,
|
||||||
_payloadReducers: {},
|
_payloadReducers: {},
|
||||||
modules: new Set(),
|
modules: new Set(),
|
||||||
set _registeredComponents(value) { this.modules = value },
|
set _registeredComponents (value) { this.modules = value },
|
||||||
get _registeredComponents() { return this.modules },
|
get _registeredComponents () { return this.modules },
|
||||||
islandContext
|
islandContext
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,7 +330,6 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
writeEarlyHints(event, link)
|
writeEarlyHints(event, link)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (process.env.NUXT_INLINE_STYLES && !isRenderingIsland) {
|
if (process.env.NUXT_INLINE_STYLES && !isRenderingIsland) {
|
||||||
for (const id of await getEntryIds()) {
|
for (const id of await getEntryIds()) {
|
||||||
ssrContext.modules!.add(id)
|
ssrContext.modules!.add(id)
|
||||||
@ -537,16 +539,16 @@ function joinTags (tags: string[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function joinAttrs (chunks: string[]) {
|
function joinAttrs (chunks: string[]) {
|
||||||
if (chunks.length === 0) return ''
|
if (chunks.length === 0) { return '' }
|
||||||
return ' ' + chunks.join(' ')
|
return ' ' + chunks.join(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderHTMLDocument (html: NuxtRenderHTMLContext) {
|
function renderHTMLDocument (html: NuxtRenderHTMLContext) {
|
||||||
return '<!DOCTYPE html>'
|
return '<!DOCTYPE html>' +
|
||||||
+ `<html${joinAttrs(html.htmlAttrs)}>`
|
`<html${joinAttrs(html.htmlAttrs)}>` +
|
||||||
+ `<head>${joinTags(html.head)}</head>`
|
`<head>${joinTags(html.head)}</head>` +
|
||||||
+ `<body${joinAttrs(html.bodyAttrs)}>${joinTags(html.bodyPrepend)}${joinTags(html.body)}${joinTags(html.bodyAppend)}</body>`
|
`<body${joinAttrs(html.bodyAttrs)}>${joinTags(html.bodyPrepend)}${joinTags(html.body)}${joinTags(html.bodyAppend)}</body>` +
|
||||||
+ '</html>'
|
'</html>'
|
||||||
}
|
}
|
||||||
|
|
||||||
async function renderInlineStyles (usedModules: Set<string> | string[]): Promise<Style[]> {
|
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) {
|
for (const slot in ssrContext.islandContext.slots) {
|
||||||
response[slot] = {
|
response[slot] = {
|
||||||
...ssrContext.islandContext.slots[slot],
|
...ssrContext.islandContext.slots[slot],
|
||||||
fallback: ssrContext.teleports?.[`island-fallback=${slot}`],
|
fallback: ssrContext.teleports?.[`island-fallback=${slot}`]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
|
@ -48,7 +48,7 @@ export const errorComponentTemplate: NuxtTemplate = {
|
|||||||
// TODO: Use an alias
|
// TODO: Use an alias
|
||||||
export const testComponentWrapperTemplate: NuxtTemplate = {
|
export const testComponentWrapperTemplate: NuxtTemplate = {
|
||||||
filename: 'test-component-wrapper.mjs',
|
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 = {
|
export const cssTemplate: NuxtTemplate = {
|
||||||
|
@ -17,7 +17,7 @@ const removeUndefinedProps = (props: Props) => {
|
|||||||
for (const key in props) {
|
for (const key in props) {
|
||||||
const value = props[key]
|
const value = props[key]
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
filteredProps[key] = value;
|
filteredProps[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return filteredProps
|
return filteredProps
|
||||||
|
@ -354,14 +354,14 @@ export default defineNuxtModule({
|
|||||||
if (nuxt.options.experimental.appManifest) {
|
if (nuxt.options.experimental.appManifest) {
|
||||||
// Add all redirect paths as valid routes to router; we will handle these in a client-side middleware
|
// Add all redirect paths as valid routes to router; we will handle these in a client-side middleware
|
||||||
// when the app manifest is enabled.
|
// when the app manifest is enabled.
|
||||||
nuxt.hook('pages:extend', routes => {
|
nuxt.hook('pages:extend', (routes) => {
|
||||||
const nitro = useNitro()
|
const nitro = useNitro()
|
||||||
for (const path in nitro.options.routeRules) {
|
for (const path in nitro.options.routeRules) {
|
||||||
const rule = nitro.options.routeRules[path]
|
const rule = nitro.options.routeRules[path]
|
||||||
if (!rule.redirect) { continue }
|
if (!rule.redirect) { continue }
|
||||||
routes.push({
|
routes.push({
|
||||||
path: path.replace(/\/[^/]*\*\*/, '/:pathMatch(.*)'),
|
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) : []
|
const sourceFiles = nuxt.apps.default?.pages?.length ? getSources(nuxt.apps.default.pages) : []
|
||||||
|
|
||||||
for (const key in manifest) {
|
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]
|
delete manifest[key]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -415,7 +415,7 @@ export default defineNuxtModule({
|
|||||||
addTemplate({
|
addTemplate({
|
||||||
filename: 'routes.mjs',
|
filename: 'routes.mjs',
|
||||||
getContents ({ app }) {
|
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)
|
const { routes, imports } = normalizeRoutes(app.pages, new Set(), nuxt.options.experimental.scanPageMeta)
|
||||||
return [...imports, `export default ${routes}`].join('\n')
|
return [...imports, `export default ${routes}`].join('\n')
|
||||||
}
|
}
|
||||||
@ -490,7 +490,6 @@ export default defineNuxtModule({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// add page meta types if enabled
|
// add page meta types if enabled
|
||||||
if (nuxt.options.experimental.viewTransition) {
|
if (nuxt.options.experimental.viewTransition) {
|
||||||
addTypeTemplate({
|
addTypeTemplate({
|
||||||
@ -502,9 +501,9 @@ export default defineNuxtModule({
|
|||||||
'import type { ComputedRef, MaybeRef } from \'vue\'',
|
'import type { ComputedRef, MaybeRef } from \'vue\'',
|
||||||
`declare module ${genString(composablesFile)} {`,
|
`declare module ${genString(composablesFile)} {`,
|
||||||
' interface PageMeta {',
|
' interface PageMeta {',
|
||||||
` viewTransition?: boolean | 'always'`,
|
' viewTransition?: boolean | \'always\'',
|
||||||
' }',
|
' }',
|
||||||
'}',
|
'}'
|
||||||
].join('\n')
|
].join('\n')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -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
|
* 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`.
|
* should set `routeRules` directly within your `nuxt.config`.
|
||||||
*/
|
*/
|
||||||
/*@__NO_SIDE_EFFECTS__*/
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
export const defineRouteRules = (rules: NitroRouteConfig): void => {}
|
export const defineRouteRules = (rules: NitroRouteConfig): void => {}
|
||||||
|
@ -4,9 +4,8 @@ import { RouterView } from '#vue-router'
|
|||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from '#vue-router'
|
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from '#vue-router'
|
||||||
|
|
||||||
import { toArray } from './utils'
|
import { generateRouteKey, toArray, wrapInKeepAlive } from './utils'
|
||||||
import type { RouterViewSlotProps } from './utils'
|
import type { RouterViewSlotProps } from './utils'
|
||||||
import { generateRouteKey, wrapInKeepAlive } from './utils'
|
|
||||||
import { RouteProvider } from '#app/components/route-provider'
|
import { RouteProvider } from '#app/components/route-provider'
|
||||||
import { useNuxtApp } from '#app/nuxt'
|
import { useNuxtApp } from '#app/nuxt'
|
||||||
import { useRouter } from '#app/composables/router'
|
import { useRouter } from '#app/composables/router'
|
||||||
|
@ -11,9 +11,9 @@ export default defineNuxtPlugin({
|
|||||||
function checkIfPageUnused () {
|
function checkIfPageUnused () {
|
||||||
if (!error.value && !nuxtApp._isNuxtPageUsed) {
|
if (!error.value && !nuxtApp._isNuxtPageUsed) {
|
||||||
console.warn(
|
console.warn(
|
||||||
'[nuxt] Your project has pages but the `<NuxtPage />` component has not been used.'
|
'[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 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.'
|
' You can set `pages: false` in `nuxt.config` if you do not wish to use the Nuxt `vue-router` integration.'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ export async function generateRoutesFromFiles (files: ScannedFile[], options: Ge
|
|||||||
name: '',
|
name: '',
|
||||||
path: '',
|
path: '',
|
||||||
file: file.absolutePath,
|
file: file.absolutePath,
|
||||||
children: [],
|
children: []
|
||||||
}
|
}
|
||||||
|
|
||||||
// Array where routes should be added, useful when adding child routes
|
// 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) {
|
function serializeRouteValue (value: any, skipSerialisation = false) {
|
||||||
if (skipSerialisation || value === undefined) return undefined
|
if (skipSerialisation || value === undefined) { return undefined }
|
||||||
return JSON.stringify(value)
|
return JSON.stringify(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +425,7 @@ export function normalizeRoutes (routes: NuxtPage[], metaImports: Set<string> =
|
|||||||
name: serializeRouteValue(page.name),
|
name: serializeRouteValue(page.name),
|
||||||
meta: serializeRouteValue(metaFiltered, skipMeta),
|
meta: serializeRouteValue(metaFiltered, skipMeta),
|
||||||
alias: serializeRouteValue(toArray(page.alias), skipAlias),
|
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) {
|
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
|
// skip and retain fallback if marked dynamic
|
||||||
// set to extracted value or fallback if none extracted
|
// set to extracted value or fallback if none extracted
|
||||||
for (const key of ['name', 'path'] satisfies NormalizedRouteKeys) {
|
for (const key of ['name', 'path'] satisfies NormalizedRouteKeys) {
|
||||||
if (markedDynamic.has(key)) continue
|
if (markedDynamic.has(key)) { continue }
|
||||||
metaRoute[key] = route[key] ?? metaRoute[key]
|
metaRoute[key] = route[key] ?? metaRoute[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
// set to extracted value or delete if none extracted
|
// set to extracted value or delete if none extracted
|
||||||
for (const key of ['meta', 'alias', 'redirect'] satisfies NormalizedRouteKeys) {
|
for (const key of ['meta', 'alias', 'redirect'] satisfies NormalizedRouteKeys) {
|
||||||
if (markedDynamic.has(key)) continue
|
if (markedDynamic.has(key)) { continue }
|
||||||
|
|
||||||
if (route[key] == null) {
|
if (route[key] == null) {
|
||||||
delete metaRoute[key]
|
delete metaRoute[key]
|
||||||
|
@ -87,7 +87,7 @@ describe('resolveApp', () => {
|
|||||||
'middleware/other.ts',
|
'middleware/other.ts',
|
||||||
'layouts/index.vue',
|
'layouts/index.vue',
|
||||||
'layouts/default/index.vue',
|
'layouts/default/index.vue',
|
||||||
'layouts/other.vue',
|
'layouts/other.vue'
|
||||||
])
|
])
|
||||||
// Middleware are not resolved in a nested manner
|
// Middleware are not resolved in a nested manner
|
||||||
expect(app.middleware.filter(m => m.path.startsWith('<rootDir>'))).toMatchInlineSnapshot(`
|
expect(app.middleware.filter(m => m.path.startsWith('<rootDir>'))).toMatchInlineSnapshot(`
|
||||||
|
@ -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\'')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ describe('loadNuxt', () => {
|
|||||||
ready: true,
|
ready: true,
|
||||||
overrides: {
|
overrides: {
|
||||||
hooks: {
|
hooks: {
|
||||||
ready() {
|
ready () {
|
||||||
hookRan = true
|
hookRan = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@ describe('pages:generateRoutesFromFiles', () => {
|
|||||||
vi.mock('knitwork', async (original) => {
|
vi.mock('knitwork', async (original) => {
|
||||||
return {
|
return {
|
||||||
...(await original<typeof import('knitwork')>()),
|
...(await original<typeof import('knitwork')>()),
|
||||||
'genArrayFromRaw': (val: any) => val,
|
genArrayFromRaw: (val: any) => val,
|
||||||
'genSafeVariableName': (..._args: string[]) => {
|
genSafeVariableName: (..._args: string[]) => {
|
||||||
return 'mock'
|
return 'mock'
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -471,7 +471,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
|||||||
name: 'index',
|
name: 'index',
|
||||||
path: '/'
|
path: '/'
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: 'should use fallbacks when normalized with `overrideMeta: true`',
|
description: 'should use fallbacks when normalized with `overrideMeta: true`',
|
||||||
@ -527,7 +527,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
|||||||
alias: ['sweet-home'],
|
alias: ['sweet-home'],
|
||||||
redirect: '/',
|
redirect: '/',
|
||||||
children: [],
|
children: [],
|
||||||
meta: { [DYNAMIC_META_KEY]: new Set(['meta']) },
|
meta: { [DYNAMIC_META_KEY]: new Set(['meta']) }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -538,7 +538,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
|||||||
name: 'home',
|
name: 'home',
|
||||||
path: '/',
|
path: '/',
|
||||||
alias: ['sweet-home'],
|
alias: ['sweet-home'],
|
||||||
meta: { hello: 'world' },
|
meta: { hello: 'world' }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -550,10 +550,10 @@ describe('pages:generateRoutesFromFiles', () => {
|
|||||||
path: '/',
|
path: '/',
|
||||||
alias: ['pushed-route-alias'],
|
alias: ['pushed-route-alias'],
|
||||||
meta: { someMetaData: true },
|
meta: { someMetaData: true },
|
||||||
file: `${pagesDir}/route-file.vue`,
|
file: `${pagesDir}/route-file.vue`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const normalizedResults: Record<string, any> = {}
|
const normalizedResults: Record<string, any> = {}
|
||||||
@ -561,7 +561,6 @@ describe('pages:generateRoutesFromFiles', () => {
|
|||||||
|
|
||||||
for (const test of tests) {
|
for (const test of tests) {
|
||||||
it(test.description, async () => {
|
it(test.description, async () => {
|
||||||
|
|
||||||
let result
|
let result
|
||||||
if (test.files) {
|
if (test.files) {
|
||||||
const vfs = Object.fromEntries(
|
const vfs = Object.fromEntries(
|
||||||
|
4
packages/nuxt/types.d.ts
vendored
4
packages/nuxt/types.d.ts
vendored
@ -1,11 +1,11 @@
|
|||||||
/// <reference types="nitropack" />
|
/// <reference types="nitropack" />
|
||||||
export * from './dist/index'
|
|
||||||
|
|
||||||
import type { DefineNuxtConfig } from 'nuxt/config'
|
import type { DefineNuxtConfig } from 'nuxt/config'
|
||||||
import type { RuntimeConfig, SchemaDefinition } from 'nuxt/schema'
|
import type { RuntimeConfig, SchemaDefinition } from 'nuxt/schema'
|
||||||
import type { H3Event } from 'h3'
|
import type { H3Event } from 'h3'
|
||||||
import type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from './dist/app/types'
|
import type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from './dist/app/types'
|
||||||
|
|
||||||
|
export * from './dist/index'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
const defineNuxtConfig: DefineNuxtConfig
|
const defineNuxtConfig: DefineNuxtConfig
|
||||||
const defineNuxtSchema: (schema: SchemaDefinition) => SchemaDefinition
|
const defineNuxtSchema: (schema: SchemaDefinition) => SchemaDefinition
|
||||||
|
@ -27,7 +27,7 @@ export default defineUntypedSchema({
|
|||||||
* @see [Vue RFC#502](https://github.com/vuejs/rfcs/discussions/502)
|
* @see [Vue RFC#502](https://github.com/vuejs/rfcs/discussions/502)
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
propsDestructure: false,
|
propsDestructure: false
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,7 +157,7 @@ export default defineUntypedSchema({
|
|||||||
*/
|
*/
|
||||||
viewTransition: {
|
viewTransition: {
|
||||||
$resolve: async (val, get) => val ?? await (get('experimental') as Promise<Record<string, any>>).then(
|
$resolve: async (val, get) => val ?? await (get('experimental') as Promise<Record<string, any>>).then(
|
||||||
(e) => e?.viewTransition
|
e => e?.viewTransition
|
||||||
) ?? false
|
) ?? false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ export default defineUntypedSchema({
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Some features of Nuxt are available on an opt-in basis, or can be disabled based on your needs.
|
* 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
|
// TODO: remove in v3.10
|
||||||
return val ?? await (get('experimental') as Promise<Record<string, any>>).then((e: Record<string, any>) => e?.noScripts) ?? false
|
return val ?? await (get('experimental') as Promise<Record<string, any>>).then((e: Record<string, any>) => e?.noScripts) ?? false
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
experimental: {
|
experimental: {
|
||||||
/**
|
/**
|
||||||
@ -335,6 +335,6 @@ export default defineUntypedSchema({
|
|||||||
* ```
|
* ```
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
clientNodeCompat: false,
|
clientNodeCompat: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -70,7 +70,7 @@ export default defineUntypedSchema({
|
|||||||
exclude: {
|
exclude: {
|
||||||
$resolve: async (val: string[] | undefined, get) => [
|
$resolve: async (val: string[] | undefined, get) => [
|
||||||
...val || [],
|
...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'
|
'vue-demi'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ export default defineUntypedSchema({
|
|||||||
embed: 'src'
|
embed: 'src'
|
||||||
},
|
},
|
||||||
compilerOptions: { $resolve: async (val, get) => val ?? (await get('vue.compilerOptions')) },
|
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: {
|
css: {
|
||||||
|
@ -36,6 +36,7 @@ export interface NuxtTemplate<Options = TemplateDefaultOptions> {
|
|||||||
/** The resolved path to the source file to be template */
|
/** The resolved path to the source file to be template */
|
||||||
src?: string
|
src?: string
|
||||||
/** Provided compile option instead of src */
|
/** 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>
|
getContents?: (data: { nuxt: Nuxt, app: NuxtApp, options: Options }) => string | Promise<string>
|
||||||
/** Write to filesystem */
|
/** Write to filesystem */
|
||||||
write?: boolean
|
write?: boolean
|
||||||
|
@ -20,12 +20,14 @@ import { viteNodePlugin } from './vite-node'
|
|||||||
import { createViteLogger } from './utils/logger'
|
import { createViteLogger } from './utils/logger'
|
||||||
|
|
||||||
export async function buildClient (ctx: ViteBuildContext) {
|
export async function buildClient (ctx: ViteBuildContext) {
|
||||||
const nodeCompat = ctx.nuxt.options.experimental.clientNodeCompat ? {
|
const nodeCompat = ctx.nuxt.options.experimental.clientNodeCompat
|
||||||
|
? {
|
||||||
alias: env(nodeless).alias,
|
alias: env(nodeless).alias,
|
||||||
define: {
|
define: {
|
||||||
global: 'globalThis',
|
global: 'globalThis'
|
||||||
}
|
}
|
||||||
} : { alias: {}, define: {} }
|
}
|
||||||
|
: { alias: {}, define: {} }
|
||||||
|
|
||||||
const clientConfig: ViteConfig = vite.mergeConfig(ctx.config, vite.mergeConfig({
|
const clientConfig: ViteConfig = vite.mergeConfig(ctx.config, vite.mergeConfig({
|
||||||
configFile: false,
|
configFile: false,
|
||||||
@ -67,7 +69,7 @@ export async function buildClient (ctx: ViteBuildContext) {
|
|||||||
...nodeCompat.alias,
|
...nodeCompat.alias,
|
||||||
...ctx.config.resolve?.alias,
|
...ctx.config.resolve?.alias,
|
||||||
'#build/plugins': resolve(ctx.nuxt.options.buildDir, 'plugins/client'),
|
'#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: [
|
dedupe: [
|
||||||
'vue'
|
'vue'
|
||||||
|
@ -44,11 +44,11 @@ export async function buildServer (ctx: ViteBuildContext) {
|
|||||||
'import.meta.server': true,
|
'import.meta.server': true,
|
||||||
'import.meta.client': false,
|
'import.meta.client': false,
|
||||||
'import.meta.browser': false,
|
'import.meta.browser': false,
|
||||||
'window': 'undefined',
|
window: 'undefined',
|
||||||
'document': 'undefined',
|
document: 'undefined',
|
||||||
'navigator': 'undefined',
|
navigator: 'undefined',
|
||||||
'location': 'undefined',
|
location: 'undefined',
|
||||||
'XMLHttpRequest': 'undefined'
|
XMLHttpRequest: 'undefined'
|
||||||
},
|
},
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
entries: ctx.nuxt.options.ssr ? [ctx.entry] : []
|
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
|
// https://github.com/vitest-dev/vitest/issues/229#issuecomment-1002685027
|
||||||
preTransformRequests: false,
|
preTransformRequests: false,
|
||||||
hmr: false
|
hmr: false
|
||||||
},
|
}
|
||||||
} satisfies vite.InlineConfig, ctx.nuxt.options.vite.$server || {}))
|
} satisfies vite.InlineConfig, ctx.nuxt.options.vite.$server || {}))
|
||||||
|
|
||||||
if (!ctx.nuxt.options.dev) {
|
if (!ctx.nuxt.options.dev) {
|
||||||
|
@ -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
|
// 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)
|
await this.resolve(source, join(nuxt.options.srcDir, 'index.html'), { skipSelf: true }).catch(() => null)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export function client (ctx: WebpackConfigContext) {
|
|||||||
clientDevtool,
|
clientDevtool,
|
||||||
clientPerformance,
|
clientPerformance,
|
||||||
clientHMR,
|
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) {
|
if (!ctx.nuxt.options.experimental.clientNodeCompat) {
|
||||||
return
|
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 = ctx.config.resolve || {}
|
||||||
ctx.config.resolve.fallback = {
|
ctx.config.resolve.fallback = {
|
||||||
...env(nodeless).alias,
|
...env(nodeless).alias,
|
||||||
...ctx.config.resolve.fallback,
|
...ctx.config.resolve.fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/webpack/webpack/issues/13290#issuecomment-1188760779
|
// https://github.com/webpack/webpack/issues/13290#issuecomment-1188760779
|
||||||
ctx.config.plugins!.unshift(new webpack.NormalModuleReplacementPlugin(/node:/, (resource) => {
|
ctx.config.plugins!.unshift(new webpack.NormalModuleReplacementPlugin(/node:/, (resource) => {
|
||||||
resource.request = resource.request.replace(/^node:/, '');
|
resource.request = resource.request.replace(/^node:/, '')
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,9 @@ importers:
|
|||||||
eslint:
|
eslint:
|
||||||
specifier: 8.57.0
|
specifier: 8.57.0
|
||||||
version: 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:
|
eslint-plugin-import:
|
||||||
specifier: 2.29.1
|
specifier: 2.29.1
|
||||||
version: 2.29.1(@typescript-eslint/parser@6.8.0)(eslint@8.57.0)
|
version: 2.29.1(@typescript-eslint/parser@6.8.0)(eslint@8.57.0)
|
||||||
@ -4201,7 +4204,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==}
|
resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
semver: 7.6.0
|
semver: 7.6.0
|
||||||
dev: false
|
|
||||||
|
|
||||||
/bundle-name@3.0.0:
|
/bundle-name@3.0.0:
|
||||||
resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==}
|
resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==}
|
||||||
@ -5427,6 +5429,30 @@ packages:
|
|||||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||||
engines: {node: '>=12'}
|
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:
|
/eslint-import-resolver-node@0.3.9:
|
||||||
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
|
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -5466,6 +5492,18 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
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):
|
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.8.0)(eslint@8.57.0):
|
||||||
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
|
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@ -5521,11 +5559,40 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
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:
|
/eslint-plugin-no-only-tests@3.1.0:
|
||||||
resolution: {integrity: sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==}
|
resolution: {integrity: sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==}
|
||||||
engines: {node: '>=5.0.0'}
|
engines: {node: '>=5.0.0'}
|
||||||
dev: true
|
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):
|
/eslint-plugin-unicorn@51.0.1(eslint@8.57.0):
|
||||||
resolution: {integrity: sha512-MuR/+9VuB0fydoI0nIn2RDA5WISRn4AsJyNSaNKLVwie9/ONvQhxOBbkfSICBPnzKrB77Fh6CZZXjgTt/4Latw==}
|
resolution: {integrity: sha512-MuR/+9VuB0fydoI0nIn2RDA5WISRn4AsJyNSaNKLVwie9/ONvQhxOBbkfSICBPnzKrB77Fh6CZZXjgTt/4Latw==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
@ -6168,6 +6235,13 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
type-fest: 0.20.2
|
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:
|
/globalthis@1.0.3:
|
||||||
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
|
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
@ -45,7 +45,7 @@ async function main () {
|
|||||||
.replace(/^## v.*?\n/, '')
|
.replace(/^## v.*?\n/, '')
|
||||||
.replace(`...${releaseBranch}`, `...v${newVersion}`)
|
.replace(`...${releaseBranch}`, `...v${newVersion}`)
|
||||||
.replace(/### ❤️ Contributors[\s\S]*$/, ''),
|
.replace(/### ❤️ Contributors[\s\S]*$/, ''),
|
||||||
`### ❤️ Contributors`,
|
'### ❤️ Contributors',
|
||||||
contributors.map(c => `- ${c.name} (@${c.username})`).join('\n')
|
contributors.map(c => `- ${c.name} (@${c.username})`).join('\n')
|
||||||
].join('\n')
|
].join('\n')
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ describe('pages', () => {
|
|||||||
// don't expect any errors or warning on client-side navigation
|
// don't expect any errors or warning on client-side navigation
|
||||||
const { page: page2, consoleLogs: consoleLogs2 } = await renderPage('/')
|
const { page: page2, consoleLogs: consoleLogs2 } = await renderPage('/')
|
||||||
await page2.locator('#to-client-only-components').click()
|
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()
|
expect(consoleLogs2.some(log => log.type === 'error' || log.type === 'warning')).toBeFalsy()
|
||||||
await page2.close()
|
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
|
// Then go to non client only page
|
||||||
await clientInitialPage.click('a')
|
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
|
// 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
|
// and not contain any errors or warnings
|
||||||
expect(errors.length).toBe(0)
|
expect(errors.length).toBe(0)
|
||||||
|
|
||||||
@ -509,7 +509,7 @@ describe('pages', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Now non client only page should be sever rendered
|
// 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
|
// Go to client only page
|
||||||
await normalInitialPage.click('a')
|
await normalInitialPage.click('a')
|
||||||
@ -563,7 +563,7 @@ describe('nuxt composables', () => {
|
|||||||
expect(text).toContain('baz')
|
expect(text).toContain('baz')
|
||||||
await page.getByText('Change cookie').click()
|
await page.getByText('Change cookie').click()
|
||||||
expect(await extractCookie()).toEqual({ foo: 'bar' })
|
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()
|
await page.getByText('Refresh cookie').click()
|
||||||
text = await page.innerText('pre')
|
text = await page.innerText('pre')
|
||||||
expect(text).toContain('foobar')
|
expect(text).toContain('foobar')
|
||||||
@ -639,7 +639,7 @@ describe('rich payloads', () => {
|
|||||||
'BigInt ref:',
|
'BigInt ref:',
|
||||||
'Reactive: true',
|
'Reactive: true',
|
||||||
'Ref: true',
|
'Ref: true',
|
||||||
'Recursive objects: true',
|
'Recursive objects: true'
|
||||||
]) {
|
]) {
|
||||||
expect(html).toContain(test)
|
expect(html).toContain(test)
|
||||||
}
|
}
|
||||||
@ -731,13 +731,13 @@ describe('nuxt links', () => {
|
|||||||
await page.locator('#big-page-2').scrollIntoViewIfNeeded()
|
await page.locator('#big-page-2').scrollIntoViewIfNeeded()
|
||||||
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
|
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
|
||||||
await page.locator('#big-page-2').click()
|
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)
|
expect(await page.evaluate(() => window.scrollY)).toBe(0)
|
||||||
|
|
||||||
await page.locator('#big-page-1').scrollIntoViewIfNeeded()
|
await page.locator('#big-page-1').scrollIntoViewIfNeeded()
|
||||||
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
|
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
|
||||||
await page.locator('#big-page-1').click()
|
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)
|
expect(await page.evaluate(() => window.scrollY)).toBe(0)
|
||||||
await page.close()
|
await page.close()
|
||||||
},
|
},
|
||||||
@ -754,18 +754,18 @@ describe('nuxt links', () => {
|
|||||||
height: 1000
|
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()
|
await page.locator('#user-test').scrollIntoViewIfNeeded()
|
||||||
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
|
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
|
||||||
await page.locator('#user-test').click()
|
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)
|
expect(await page.evaluate(() => window.scrollY)).toBe(0)
|
||||||
|
|
||||||
await page.locator('#test').scrollIntoViewIfNeeded()
|
await page.locator('#test').scrollIntoViewIfNeeded()
|
||||||
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
|
expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0)
|
||||||
await page.locator('#test').click()
|
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)
|
expect(await page.evaluate(() => window.scrollY)).toBe(0)
|
||||||
await page.close()
|
await page.close()
|
||||||
},
|
},
|
||||||
@ -879,7 +879,7 @@ describe('navigate', () => {
|
|||||||
const res = await fetch('/navigate-some-path/', { redirect: 'manual', headers: { 'trailing-slash': 'true' } })
|
const res = await fetch('/navigate-some-path/', { redirect: 'manual', headers: { 'trailing-slash': 'true' } })
|
||||||
expect(res.headers.get('location')).toEqual('/navigate-some-path')
|
expect(res.headers.get('location')).toEqual('/navigate-some-path')
|
||||||
expect(res.status).toEqual(307)
|
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 () => {
|
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]}"`)
|
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) {
|
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 {
|
} 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')
|
expect(text).toContain('async component that was very long')
|
||||||
|
|
||||||
@ -1847,7 +1847,7 @@ describe.skipIf(isDev())('dynamic paths', () => {
|
|||||||
await startServer({
|
await startServer({
|
||||||
env: {
|
env: {
|
||||||
NUXT_APP_BUILD_ASSETS_DIR: '/_other/',
|
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({
|
await startServer({
|
||||||
env: {
|
env: {
|
||||||
NUXT_APP_BUILD_ASSETS_DIR: '/_other/',
|
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' })
|
const { headers } = await fetch('/foo/navigate-to/', { redirect: 'manual' })
|
||||||
@ -2444,7 +2444,7 @@ describe('keepalive', () => {
|
|||||||
'keepalive-in-nuxtpage-2',
|
'keepalive-in-nuxtpage-2',
|
||||||
'keepalive-in-nuxtpage',
|
'keepalive-in-nuxtpage',
|
||||||
'not-keepalive',
|
'not-keepalive',
|
||||||
'keepalive-in-nuxtpage-2',
|
'keepalive-in-nuxtpage-2'
|
||||||
]
|
]
|
||||||
|
|
||||||
for (const slug of slugs) {
|
for (const slug of slugs) {
|
||||||
|
@ -19,7 +19,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
for (const outputDir of ['.output', '.output-inline']) {
|
for (const outputDir of ['.output', '.output-inline']) {
|
||||||
it('default client bundle size', async () => {
|
it('default client bundle size', async () => {
|
||||||
const clientStats = await analyzeSizes('**/*.js', join(rootDir, outputDir, 'public'))
|
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(`
|
expect(clientStats.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
|
||||||
[
|
[
|
||||||
"_nuxt/entry.js",
|
"_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 serverDir = join(rootDir, '.output/server')
|
||||||
|
|
||||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
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)
|
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
|
const packages = modules.files
|
||||||
.filter(m => m.endsWith('package.json'))
|
.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 serverDir = join(rootDir, '.output-inline/server')
|
||||||
|
|
||||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
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)
|
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
|
const packages = modules.files
|
||||||
.filter(m => m.endsWith('package.json'))
|
.filter(m => m.endsWith('package.json'))
|
||||||
|
2
test/fixtures/basic-types/nuxt.config.ts
vendored
2
test/fixtures/basic-types/nuxt.config.ts
vendored
@ -3,7 +3,7 @@ import { addTypeTemplate } from 'nuxt/kit'
|
|||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
experimental: {
|
experimental: {
|
||||||
typedPages: true,
|
typedPages: true,
|
||||||
appManifest: true,
|
appManifest: true
|
||||||
},
|
},
|
||||||
future: {
|
future: {
|
||||||
typescriptBundlerResolution: process.env.MODULE_RESOLUTION === 'bundler'
|
typescriptBundlerResolution: process.env.MODULE_RESOLUTION === 'bundler'
|
||||||
|
6
test/fixtures/basic-types/types.ts
vendored
6
test/fixtures/basic-types/types.ts
vendored
@ -331,7 +331,7 @@ describe('head', () => {
|
|||||||
})
|
})
|
||||||
it('types head for defineNuxtComponent', () => {
|
it('types head for defineNuxtComponent', () => {
|
||||||
defineNuxtComponent({
|
defineNuxtComponent({
|
||||||
head(nuxtApp) {
|
head (nuxtApp) {
|
||||||
expectTypeOf(nuxtApp).not.toBeAny()
|
expectTypeOf(nuxtApp).not.toBeAny()
|
||||||
return {
|
return {
|
||||||
title: 'Site Title'
|
title: 'Site Title'
|
||||||
@ -341,9 +341,9 @@ describe('head', () => {
|
|||||||
|
|
||||||
defineNuxtComponent({
|
defineNuxtComponent({
|
||||||
// @ts-expect-error wrong return type for head function
|
// @ts-expect-error wrong return type for head function
|
||||||
head() {
|
head () {
|
||||||
return {
|
return {
|
||||||
'test': true
|
test: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -10,40 +10,40 @@ export default defineNuxtModule({
|
|||||||
addComponent({
|
addComponent({
|
||||||
name: 'DCompClient',
|
name: 'DCompClient',
|
||||||
filePath: resolve('./runtime/components'),
|
filePath: resolve('./runtime/components'),
|
||||||
mode: 'client',
|
mode: 'client'
|
||||||
})
|
})
|
||||||
|
|
||||||
addComponent({
|
addComponent({
|
||||||
name: 'DCompServer',
|
name: 'DCompServer',
|
||||||
filePath: resolve('./runtime/components'),
|
filePath: resolve('./runtime/components'),
|
||||||
mode: 'server',
|
mode: 'server'
|
||||||
})
|
})
|
||||||
|
|
||||||
addComponent({
|
addComponent({
|
||||||
name: 'DCompAll',
|
name: 'DCompAll',
|
||||||
filePath: resolve('./runtime/components'),
|
filePath: resolve('./runtime/components'),
|
||||||
mode: 'all',
|
mode: 'all'
|
||||||
})
|
})
|
||||||
|
|
||||||
addComponent({
|
addComponent({
|
||||||
name: 'NCompClient',
|
name: 'NCompClient',
|
||||||
export: 'NComp',
|
export: 'NComp',
|
||||||
filePath: resolve('./runtime/components'),
|
filePath: resolve('./runtime/components'),
|
||||||
mode: 'client',
|
mode: 'client'
|
||||||
})
|
})
|
||||||
|
|
||||||
addComponent({
|
addComponent({
|
||||||
name: 'NCompServer',
|
name: 'NCompServer',
|
||||||
export: 'NComp',
|
export: 'NComp',
|
||||||
filePath: resolve('./runtime/components'),
|
filePath: resolve('./runtime/components'),
|
||||||
mode: 'server',
|
mode: 'server'
|
||||||
})
|
})
|
||||||
|
|
||||||
addComponent({
|
addComponent({
|
||||||
name: 'NCompAll',
|
name: 'NCompAll',
|
||||||
export: 'NComp',
|
export: 'NComp',
|
||||||
filePath: resolve('./runtime/components'),
|
filePath: resolve('./runtime/components'),
|
||||||
mode: 'all',
|
mode: 'all'
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
@ -3,11 +3,11 @@ import { defineComponent, h } from 'vue'
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'DComp',
|
name: 'DComp',
|
||||||
props: { message: String },
|
props: { message: String },
|
||||||
render: (props: any) => h('h1', props.message),
|
render: (props: any) => h('h1', props.message)
|
||||||
})
|
})
|
||||||
|
|
||||||
export const NComp = defineComponent({
|
export const NComp = defineComponent({
|
||||||
name: 'NComp',
|
name: 'NComp',
|
||||||
props: { message: String },
|
props: { message: String },
|
||||||
render: (props: any) => h('h1', props.message),
|
render: (props: any) => h('h1', props.message)
|
||||||
})
|
})
|
||||||
|
@ -11,21 +11,21 @@ export default defineNuxtModule({
|
|||||||
name: 'NCompClient',
|
name: 'NCompClient',
|
||||||
export: 'NComp',
|
export: 'NComp',
|
||||||
filePath: resolve('./runtime/components'),
|
filePath: resolve('./runtime/components'),
|
||||||
mode: 'client',
|
mode: 'client'
|
||||||
})
|
})
|
||||||
|
|
||||||
addComponent({
|
addComponent({
|
||||||
name: 'NCompServer',
|
name: 'NCompServer',
|
||||||
export: 'NComp',
|
export: 'NComp',
|
||||||
filePath: resolve('./runtime/components'),
|
filePath: resolve('./runtime/components'),
|
||||||
mode: 'server',
|
mode: 'server'
|
||||||
})
|
})
|
||||||
|
|
||||||
addComponent({
|
addComponent({
|
||||||
name: 'NCompAll',
|
name: 'NCompAll',
|
||||||
export: 'NComp',
|
export: 'NComp',
|
||||||
filePath: resolve('./runtime/components'),
|
filePath: resolve('./runtime/components'),
|
||||||
mode: 'all',
|
mode: 'all'
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
@ -3,5 +3,5 @@ import { defineComponent, h } from 'vue'
|
|||||||
export const NComp = defineComponent({
|
export const NComp = defineComponent({
|
||||||
name: 'NComp',
|
name: 'NComp',
|
||||||
props: { message: String },
|
props: { message: String },
|
||||||
render: (props: any) => h('h1', props.message),
|
render: (props: any) => h('h1', props.message)
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { defineNuxtModule } from 'nuxt/kit'
|
import { defineNuxtModule } from 'nuxt/kit'
|
||||||
|
|
||||||
export default defineNuxtModule({
|
export default defineNuxtModule({
|
||||||
meta: { name: 'subpath' },
|
meta: { name: 'subpath' }
|
||||||
})
|
})
|
||||||
|
6
test/fixtures/basic/nuxt.config.ts
vendored
6
test/fixtures/basic/nuxt.config.ts
vendored
@ -101,10 +101,10 @@ export default defineNuxtConfig({
|
|||||||
addBuildPlugin(plugin)
|
addBuildPlugin(plugin)
|
||||||
},
|
},
|
||||||
function (_options, nuxt) {
|
function (_options, nuxt) {
|
||||||
nuxt.hook('pages:extend', pages => {
|
nuxt.hook('pages:extend', (pages) => {
|
||||||
pages.push({
|
pages.push({
|
||||||
path: '/manual-redirect',
|
path: '/manual-redirect',
|
||||||
redirect: '/',
|
redirect: '/'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -201,7 +201,7 @@ export default defineNuxtConfig({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
features: {
|
features: {
|
||||||
inlineStyles: id => !!id && !id.includes('assets.vue'),
|
inlineStyles: id => !!id && !id.includes('assets.vue')
|
||||||
},
|
},
|
||||||
experimental: {
|
experimental: {
|
||||||
typedPages: true,
|
typedPages: true,
|
||||||
|
@ -3,7 +3,7 @@ const state = useState('test', () => {
|
|||||||
let hasAccessToWindow = null as null | boolean
|
let hasAccessToWindow = null as null | boolean
|
||||||
|
|
||||||
try {
|
try {
|
||||||
hasAccessToWindow = Object.keys(window).at(0) ? true : false
|
hasAccessToWindow = !!Object.keys(window).at(0)
|
||||||
} catch {
|
} catch {
|
||||||
hasAccessToWindow = null
|
hasAccessToWindow = null
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,3 @@ import css from '~/assets/inline-only.css?inline'
|
|||||||
<template>
|
<template>
|
||||||
<pre>{{ css }}</pre>
|
<pre>{{ css }}</pre>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
2
test/fixtures/basic/pages/node-compat.vue
vendored
2
test/fixtures/basic/pages/node-compat.vue
vendored
@ -3,7 +3,7 @@ import { Buffer } from 'node:buffer'
|
|||||||
import process from 'node:process'
|
import process from 'node:process'
|
||||||
|
|
||||||
const base64 = atob(Buffer.from('Nuxt is Awesome!', 'utf8').toString('base64'))
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
1
test/fixtures/basic/pages/use-id.vue
vendored
1
test/fixtures/basic/pages/use-id.vue
vendored
@ -12,4 +12,3 @@ const id = useId()
|
|||||||
<ComponentWithIds />
|
<ComponentWithIds />
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
2
test/fixtures/basic/server/api/error.ts
vendored
2
test/fixtures/basic/server/api/error.ts
vendored
@ -1,3 +1,3 @@
|
|||||||
export default defineEventHandler(async () => {
|
export default defineEventHandler(() => {
|
||||||
throw createError({ statusCode: 400 })
|
throw createError({ statusCode: 400 })
|
||||||
})
|
})
|
||||||
|
@ -120,21 +120,21 @@ if (process.env.TEST_ENV !== 'built' && !isWindows) {
|
|||||||
// initial state
|
// initial state
|
||||||
await expectWithPolling(
|
await expectWithPolling(
|
||||||
resolveHmrId,
|
resolveHmrId,
|
||||||
0,
|
0
|
||||||
)
|
)
|
||||||
|
|
||||||
// first edit
|
// first edit
|
||||||
await triggerHmr()
|
await triggerHmr()
|
||||||
await expectWithPolling(
|
await expectWithPolling(
|
||||||
resolveHmrId,
|
resolveHmrId,
|
||||||
1,
|
1
|
||||||
)
|
)
|
||||||
|
|
||||||
// just in-case
|
// just in-case
|
||||||
await triggerHmr()
|
await triggerHmr()
|
||||||
await expectWithPolling(
|
await expectWithPolling(
|
||||||
resolveHmrId,
|
resolveHmrId,
|
||||||
2,
|
2
|
||||||
)
|
)
|
||||||
|
|
||||||
// ensure no errors
|
// ensure no errors
|
||||||
|
@ -42,7 +42,7 @@ registerEndpoint('/_nuxt/builds/meta/override.json', defineEventHandler(() => ({
|
|||||||
},
|
},
|
||||||
prerendered: ['/specific-prerendered']
|
prerendered: ['/specific-prerendered']
|
||||||
})))
|
})))
|
||||||
registerEndpoint('/api/test', defineEventHandler((event) => ({
|
registerEndpoint('/api/test', defineEventHandler(event => ({
|
||||||
method: event.method,
|
method: event.method,
|
||||||
headers: Object.fromEntries(event.headers.entries())
|
headers: Object.fromEntries(event.headers.entries())
|
||||||
})))
|
})))
|
||||||
@ -106,7 +106,7 @@ describe('composables', () => {
|
|||||||
'navigateTo',
|
'navigateTo',
|
||||||
'abortNavigation',
|
'abortNavigation',
|
||||||
'setPageLayout',
|
'setPageLayout',
|
||||||
'defineNuxtComponent',
|
'defineNuxtComponent'
|
||||||
]
|
]
|
||||||
const skippedComposables: string[] = [
|
const skippedComposables: string[] = [
|
||||||
'addRouteMiddleware',
|
'addRouteMiddleware',
|
||||||
@ -248,7 +248,7 @@ describe('useAsyncData', () => {
|
|||||||
expect(data.value).toMatchInlineSnapshot('"default"')
|
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'))
|
const promiseFn = vi.fn(() => Promise.resolve('test'))
|
||||||
useAsyncData('dedupedKey', promiseFn, { dedupe: 'defer' })
|
useAsyncData('dedupedKey', promiseFn, { dedupe: 'defer' })
|
||||||
useAsyncData('dedupedKey', promiseFn, { dedupe: 'defer' })
|
useAsyncData('dedupedKey', promiseFn, { dedupe: 'defer' })
|
||||||
@ -257,7 +257,7 @@ describe('useAsyncData', () => {
|
|||||||
expect(promiseFn).toHaveBeenCalledTimes(1)
|
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'))
|
const promiseFn = vi.fn(() => Promise.resolve('test'))
|
||||||
useAsyncData('dedupedKey', promiseFn)
|
useAsyncData('dedupedKey', promiseFn)
|
||||||
useAsyncData('dedupedKey', promiseFn)
|
useAsyncData('dedupedKey', promiseFn)
|
||||||
@ -266,7 +266,7 @@ describe('useAsyncData', () => {
|
|||||||
expect(promiseFn).toHaveBeenCalledTimes(3)
|
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'))
|
const promiseFn = vi.fn(() => Promise.resolve('test'))
|
||||||
useAsyncData('dedupedKey', promiseFn, { dedupe: 'defer' })
|
useAsyncData('dedupedKey', promiseFn, { dedupe: 'defer' })
|
||||||
useAsyncData('dedupedKey', promiseFn)
|
useAsyncData('dedupedKey', promiseFn)
|
||||||
@ -556,13 +556,13 @@ describe.skipIf(process.env.TEST_MANIFEST === 'manifest-off')('app manifests', (
|
|||||||
|
|
||||||
describe('routing utilities: `navigateTo`', () => {
|
describe('routing utilities: `navigateTo`', () => {
|
||||||
it('navigateTo should disallow navigation to external URLs by default', () => {
|
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()
|
expect(() => navigateTo('https://test.com', { external: true })).not.toThrow()
|
||||||
})
|
})
|
||||||
it('navigateTo should disallow navigation to data/script URLs', () => {
|
it('navigateTo should disallow navigation to data/script URLs', () => {
|
||||||
const urls = [
|
const urls = [
|
||||||
['data:alert("hi")', 'data'],
|
['data:alert("hi")', 'data'],
|
||||||
['\0data:alert("hi")', 'data'],
|
['\0data:alert("hi")', 'data']
|
||||||
]
|
]
|
||||||
for (const [url, protocol] of urls) {
|
for (const [url, protocol] of urls) {
|
||||||
expect(() => navigateTo(url, { external: true })).toThrowError(`Cannot navigate to a URL with '${protocol}:' protocol.`)
|
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`', () => {
|
describe('routing utilities: `useRoute`', () => {
|
||||||
it('should show provide a mock route', async () => {
|
it('should show provide a mock route', () => {
|
||||||
expect(useRoute()).toMatchObject({
|
expect(useRoute()).toMatchObject({
|
||||||
fullPath: '/',
|
fullPath: '/',
|
||||||
hash: '',
|
hash: '',
|
||||||
@ -582,7 +582,7 @@ describe('routing utilities: `useRoute`', () => {
|
|||||||
params: {},
|
params: {},
|
||||||
path: '/',
|
path: '/',
|
||||||
query: {},
|
query: {},
|
||||||
redirectedFrom: undefined,
|
redirectedFrom: undefined
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -590,7 +590,7 @@ describe('routing utilities: `useRoute`', () => {
|
|||||||
describe('routing utilities: `abortNavigation`', () => {
|
describe('routing utilities: `abortNavigation`', () => {
|
||||||
it('should throw an error if one is provided', () => {
|
it('should throw an error if one is provided', () => {
|
||||||
const error = useError()
|
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()
|
expect(error.value).toBeFalsy()
|
||||||
})
|
})
|
||||||
it('should block navigation if no error is provided', () => {
|
it('should block navigation if no error is provided', () => {
|
||||||
@ -607,7 +607,7 @@ describe('routing utilities: `setPageLayout`', () => {
|
|||||||
route.meta.layout = undefined
|
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 route = useRoute()
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
nuxtApp._processingMiddleware = true
|
nuxtApp._processingMiddleware = true
|
||||||
@ -632,7 +632,7 @@ describe('useCookie', () => {
|
|||||||
it('should watch custom cookie refs', () => {
|
it('should watch custom cookie refs', () => {
|
||||||
const user = useCookie('userInfo', {
|
const user = useCookie('userInfo', {
|
||||||
default: () => ({ score: -1 }),
|
default: () => ({ score: -1 }),
|
||||||
maxAge: 60 * 60,
|
maxAge: 60 * 60
|
||||||
})
|
})
|
||||||
const computedVal = computed(() => user.value.score)
|
const computedVal = computed(() => user.value.score)
|
||||||
expect(computedVal.value).toBe(-1)
|
expect(computedVal.value).toBe(-1)
|
||||||
|
@ -135,7 +135,6 @@ describe('runtime server component', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
describe('client components', () => {
|
describe('client components', () => {
|
||||||
it('expect swapping nuxt-client should not trigger errors #25289', async () => {
|
it('expect swapping nuxt-client should not trigger errors #25289', async () => {
|
||||||
const mockPath = '/nuxt-client.js'
|
const mockPath = '/nuxt-client.js'
|
||||||
@ -198,7 +197,7 @@ describe('client components', () => {
|
|||||||
// @ts-expect-error mock
|
// @ts-expect-error mock
|
||||||
vi.mocked(fetch).mockImplementation(() => ({
|
vi.mocked(fetch).mockImplementation(() => ({
|
||||||
id: '123',
|
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: {},
|
state: {},
|
||||||
head: {
|
head: {
|
||||||
link: [],
|
link: [],
|
||||||
@ -267,7 +266,7 @@ describe('client components', () => {
|
|||||||
default: {
|
default: {
|
||||||
name: 'ClientWithSlot',
|
name: 'ClientWithSlot',
|
||||||
setup (_, { slots }) {
|
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)
|
vi.stubGlobal('fetch', stubFetch)
|
||||||
const wrapper = await mountSuspended(NuxtIsland, {
|
const wrapper = await mountSuspended(NuxtIsland, {
|
||||||
props: {
|
props: {
|
||||||
name: 'NuxtClientWithSlot',
|
name: 'NuxtClientWithSlot'
|
||||||
},
|
},
|
||||||
attachTo: 'body'
|
attachTo: 'body'
|
||||||
})
|
})
|
||||||
|
@ -206,7 +206,7 @@ describe('plugin dependsOn', () => {
|
|||||||
pluginFactory('A', ['B'], sequence),
|
pluginFactory('A', ['B'], sequence),
|
||||||
pluginFactory('B', ['C'], sequence),
|
pluginFactory('B', ['C'], sequence),
|
||||||
pluginFactory('C', ['D'], sequence),
|
pluginFactory('C', ['D'], sequence),
|
||||||
pluginFactory('D', [], sequence),
|
pluginFactory('D', [], sequence)
|
||||||
]
|
]
|
||||||
|
|
||||||
await applyPlugins(nuxtApp, plugins)
|
await applyPlugins(nuxtApp, plugins)
|
||||||
@ -251,7 +251,7 @@ describe('plugin dependsOn', () => {
|
|||||||
const plugins = [
|
const plugins = [
|
||||||
pluginFactory('A', undefined, sequence, false),
|
pluginFactory('A', undefined, sequence, false),
|
||||||
pluginFactory('B', ['A', 'C'], sequence, false),
|
pluginFactory('B', ['A', 'C'], sequence, false),
|
||||||
pluginFactory('C', undefined, sequence, false),
|
pluginFactory('C', undefined, sequence, false)
|
||||||
]
|
]
|
||||||
await applyPlugins(nuxtApp, plugins)
|
await applyPlugins(nuxtApp, plugins)
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ describe('plugin dependsOn', () => {
|
|||||||
'start C',
|
'start C',
|
||||||
'end C',
|
'end C',
|
||||||
'start B',
|
'start B',
|
||||||
'end B',
|
'end B'
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -269,8 +269,8 @@ describe('plugin dependsOn', () => {
|
|||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
const sequence: string[] = []
|
const sequence: string[] = []
|
||||||
const plugins = [
|
const plugins = [
|
||||||
pluginFactory('B', undefined, sequence,),
|
pluginFactory('B', undefined, sequence),
|
||||||
pluginFactory('C', ['A', 'B'], sequence,),
|
pluginFactory('C', ['A', 'B'], sequence)
|
||||||
]
|
]
|
||||||
await applyPlugins(nuxtApp, plugins)
|
await applyPlugins(nuxtApp, plugins)
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ describe('plugin dependsOn', () => {
|
|||||||
'start B',
|
'start B',
|
||||||
'end B',
|
'end B',
|
||||||
'start C',
|
'start C',
|
||||||
'end C',
|
'end C'
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user