@nuxt/docs-nightly 4.4.0-29550724.be97f20e → 4.4.0-29551604.0a8a57da
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/1.getting-started/17.testing.md +62 -8
- package/1.getting-started/18.upgrade.md +47 -0
- package/2.directory-structure/1.app/1.layouts.md +1 -1
- package/3.guide/2.best-practices/hydration.md +11 -11
- package/3.guide/6.going-further/1.experimental-features.md +31 -4
- package/4.api/2.composables/use-fetch.md +2 -0
- package/4.api/2.composables/use-lazy-fetch.md +1 -0
- package/package.json +1 -1
|
@@ -300,6 +300,10 @@ it('can also mount an app', async () => {
|
|
|
300
300
|
})
|
|
301
301
|
```
|
|
302
302
|
|
|
303
|
+
The options object accepts `@vue/test-utils` mount options and the following properties:
|
|
304
|
+
|
|
305
|
+
- `route`: the initial route, or `false` to skip the initial route change (default `/`).
|
|
306
|
+
|
|
303
307
|
#### `renderSuspended`
|
|
304
308
|
|
|
305
309
|
`renderSuspended` allows you to render any Vue component within the Nuxt environment using `@testing-library/vue`, allowing async setup and access to injections from your Nuxt plugins.
|
|
@@ -352,14 +356,18 @@ it('can also render an app', async () => {
|
|
|
352
356
|
})
|
|
353
357
|
```
|
|
354
358
|
|
|
359
|
+
The options object accepts `@testing-library/vue` render options and the following properties:
|
|
360
|
+
|
|
361
|
+
- `route`: the initial route, or `false` to skip the initial route change (default `/`).
|
|
362
|
+
|
|
355
363
|
#### `mockNuxtImport`
|
|
356
364
|
|
|
357
|
-
`mockNuxtImport` allows you to mock Nuxt's auto import functionality. For example, to mock `
|
|
365
|
+
`mockNuxtImport` allows you to mock Nuxt's auto import functionality. For example, to mock `useState`, you can do so like this:
|
|
358
366
|
|
|
359
367
|
```ts twoslash
|
|
360
368
|
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
|
|
361
369
|
|
|
362
|
-
mockNuxtImport('
|
|
370
|
+
mockNuxtImport('useState', () => {
|
|
363
371
|
return () => {
|
|
364
372
|
return { value: 'mocked storage' }
|
|
365
373
|
}
|
|
@@ -368,6 +376,27 @@ mockNuxtImport('useStorage', () => {
|
|
|
368
376
|
// your tests here
|
|
369
377
|
```
|
|
370
378
|
|
|
379
|
+
You can explicitly type the mock for type safety, and use the original implementation passed to the factory function when mocking complex functionality.
|
|
380
|
+
|
|
381
|
+
```ts twoslash [test/nuxt/import.test.ts]
|
|
382
|
+
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
|
|
383
|
+
|
|
384
|
+
mockNuxtImport<typeof useState>('useState', (original) => {
|
|
385
|
+
return (...args) => {
|
|
386
|
+
return { ...original('some-key'), value: 'mocked state' }
|
|
387
|
+
}
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
// or specify the target to mock
|
|
391
|
+
mockNuxtImport(useState, (original) => {
|
|
392
|
+
return (...args) => {
|
|
393
|
+
return { ...original('some-key'), value: 'mocked state' }
|
|
394
|
+
}
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
// your tests here
|
|
398
|
+
```
|
|
399
|
+
|
|
371
400
|
::note
|
|
372
401
|
`mockNuxtImport` can only be used once per mocked import per test file. It is actually a macro that gets transformed to `vi.mock` and `vi.mock` is hoisted, as described [in the Vitest docs](https://vitest.dev/api/vi#vi-mock).
|
|
373
402
|
::
|
|
@@ -378,24 +407,43 @@ If you need to mock a Nuxt import and provide different implementations between
|
|
|
378
407
|
import { vi } from 'vitest'
|
|
379
408
|
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
|
|
380
409
|
|
|
381
|
-
const {
|
|
410
|
+
const { useStateMock } = vi.hoisted(() => {
|
|
382
411
|
return {
|
|
383
|
-
|
|
412
|
+
useStateMock: vi.fn(() => {
|
|
384
413
|
return { value: 'mocked storage' }
|
|
385
414
|
}),
|
|
386
415
|
}
|
|
387
416
|
})
|
|
388
417
|
|
|
389
|
-
mockNuxtImport('
|
|
390
|
-
return
|
|
418
|
+
mockNuxtImport('useState', () => {
|
|
419
|
+
return useStateMock
|
|
391
420
|
})
|
|
392
421
|
|
|
393
422
|
// Then, inside a test
|
|
394
|
-
|
|
423
|
+
useStateMock.mockImplementation(() => {
|
|
395
424
|
return { value: 'something else' }
|
|
396
425
|
})
|
|
397
426
|
```
|
|
398
427
|
|
|
428
|
+
If you need to mock behavior only inside a test, you can also use the following approach.
|
|
429
|
+
|
|
430
|
+
```ts twoslash
|
|
431
|
+
import { beforeEach, vi } from 'vitest'
|
|
432
|
+
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
|
|
433
|
+
|
|
434
|
+
mockNuxtImport(useRoute, original => vi.fn(original))
|
|
435
|
+
|
|
436
|
+
beforeEach(() => {
|
|
437
|
+
vi.resetAllMocks()
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
// Then, inside a test
|
|
441
|
+
const useRouteOriginal = vi.mocked(useRoute).getMockImplementation()!
|
|
442
|
+
vi.mocked(useRoute).mockImplementation(
|
|
443
|
+
(...args) => ({ ...useRouteOriginal(...args), path: '/mocked' }),
|
|
444
|
+
)
|
|
445
|
+
```
|
|
446
|
+
|
|
399
447
|
#### `mockComponent`
|
|
400
448
|
|
|
401
449
|
`mockComponent` allows you to mock Nuxt's component.
|
|
@@ -477,6 +525,12 @@ registerEndpoint('/test/', {
|
|
|
477
525
|
})
|
|
478
526
|
```
|
|
479
527
|
|
|
528
|
+
This object accepts the following properties:
|
|
529
|
+
|
|
530
|
+
- `handler`: the event handler function
|
|
531
|
+
- `method`: (optional) HTTP method to match (e.g., 'GET', 'POST')
|
|
532
|
+
- `once`: (optional) if true, the handler will only be used for the first matching request and then automatically removed
|
|
533
|
+
|
|
480
534
|
> **Note**: If your requests in a component go to an external API, you can use `baseURL` and then make it empty using [Nuxt Environment Override Config](/docs/4.x/getting-started/configuration#environment-overrides) (`$test`) so all your requests will go to Nitro server.
|
|
481
535
|
|
|
482
536
|
#### Conflict with End-To-End Testing
|
|
@@ -490,7 +544,7 @@ If you would like to use both the end-to-end and unit testing functionality of `
|
|
|
490
544
|
```ts twoslash
|
|
491
545
|
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
|
|
492
546
|
|
|
493
|
-
mockNuxtImport('
|
|
547
|
+
mockNuxtImport('useState', () => {
|
|
494
548
|
return () => {
|
|
495
549
|
return { value: 'mocked storage' }
|
|
496
550
|
}
|
|
@@ -61,6 +61,7 @@ When you set your `future.compatibilityVersion` to `5`, defaults throughout your
|
|
|
61
61
|
- **Vite Environment API**: Automatically enables the new [Vite Environment API](/docs/4.x/getting-started/upgrade#migration-to-vite-environment-api) for improved build configuration
|
|
62
62
|
- **Normalized Page Names**: Page component names will [match their route names](/docs/4.x/getting-started/upgrade#normalized-page-component-names) for consistent `<KeepAlive>` behavior
|
|
63
63
|
- **`clearNuxtState` resets to defaults**: `clearNuxtState` will [reset state to its initial value](/docs/4.x/getting-started/upgrade#respect-defaults-when-clearing-usestate) instead of setting it to `undefined`
|
|
64
|
+
- **Non-async `callHook`**: [`callHook` may return `void`](/docs/4.x/getting-started/upgrade#non-async-callhook) instead of always returning a `Promise`
|
|
64
65
|
- Other Nuxt 5 improvements and changes as they become available
|
|
65
66
|
|
|
66
67
|
::note
|
|
@@ -180,6 +181,52 @@ addVitePlugin(() => ({
|
|
|
180
181
|
Learn more about Vite's Environment API
|
|
181
182
|
::
|
|
182
183
|
|
|
184
|
+
### Non-Async `callHook`
|
|
185
|
+
|
|
186
|
+
🚦 **Impact Level**: Minimal
|
|
187
|
+
|
|
188
|
+
#### What Changed
|
|
189
|
+
|
|
190
|
+
With the upgrade to [hookable v6](https://github.com/unjs/hookable), `callHook` may now return `void` instead of always returning `Promise<void>`. This is a significant performance improvement that avoids unnecessary `Promise` allocations when there are no registered hooks or all hooks are synchronous.
|
|
191
|
+
|
|
192
|
+
By default (with `compatibilityVersion: 4`), Nuxt wraps `callHook` with `Promise.resolve()` so that existing `.then()` and `.catch()` chaining continues to work. With `compatibilityVersion: 5`, this wrapper is removed.
|
|
193
|
+
|
|
194
|
+
::tip
|
|
195
|
+
This affects both build-time Nuxt hooks (used by Nuxt modules) and runtime Nuxt hooks (which you might use in your application code).
|
|
196
|
+
::
|
|
197
|
+
|
|
198
|
+
#### Reasons for Change
|
|
199
|
+
|
|
200
|
+
Hookable v6's `callHook` is 20-40x faster because it avoids creating a `Promise` when one is not needed. This benefits applications with many hook call sites.
|
|
201
|
+
|
|
202
|
+
#### Migration Steps
|
|
203
|
+
|
|
204
|
+
If you or your modules use `callHook` with `.then()` or `.catch()` chaining, switch to `await`:
|
|
205
|
+
|
|
206
|
+
```diff
|
|
207
|
+
- nuxtApp.callHook('my:hook', data).then(() => { ... })
|
|
208
|
+
+ await nuxtApp.callHook('my:hook', data)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
```diff
|
|
212
|
+
- nuxtApp.hooks.callHook('my:hook', data).catch(err => { ... })
|
|
213
|
+
+ try { await nuxtApp.hooks.callHook('my:hook', data) } catch (err) { ... }
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
::tip
|
|
217
|
+
You can test this feature early by setting `future.compatibilityVersion: 5` (see [Testing Nuxt 5](/docs/4.x/getting-started/upgrade#testing-nuxt-5)) or by enabling it explicitly with `experimental.asyncCallHook: false`.
|
|
218
|
+
::
|
|
219
|
+
|
|
220
|
+
Alternatively, you can ensure `callHook` always returns a `Promise` with:
|
|
221
|
+
|
|
222
|
+
```ts twoslash [nuxt.config.ts]
|
|
223
|
+
export default defineNuxtConfig({
|
|
224
|
+
experimental: {
|
|
225
|
+
asyncCallHook: true,
|
|
226
|
+
},
|
|
227
|
+
})
|
|
228
|
+
```
|
|
229
|
+
|
|
183
230
|
## Migrating to Nuxt 4
|
|
184
231
|
|
|
185
232
|
Nuxt 4 includes significant improvements and changes. This guide will help you migrate your existing Nuxt 3 application to Nuxt 4.
|
|
@@ -122,7 +122,7 @@ File | Layout Name
|
|
|
122
122
|
|
|
123
123
|
You can also use the [`setPageLayout`](/docs/4.x/api/utils/set-page-layout) helper to change the layout dynamically:
|
|
124
124
|
|
|
125
|
-
```vue twoslash
|
|
125
|
+
```vue twoslash [app/pages/index.vue]
|
|
126
126
|
<script setup lang="ts">
|
|
127
127
|
declare module 'nuxt/app' {
|
|
128
128
|
interface NuxtLayouts {
|
|
@@ -6,32 +6,32 @@ description: Why fixing hydration issues is important
|
|
|
6
6
|
|
|
7
7
|
When developing, you may face hydration issues. Don't ignore those warnings.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Why is it important to fix them?
|
|
10
10
|
|
|
11
11
|
Hydration mismatches are not just warnings - they are indicators of serious problems that can break your application:
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
### Performance Impact
|
|
14
14
|
|
|
15
15
|
- **Increased time to interactive**: Hydration errors force Vue to re-render the entire component tree, which will increase the time for your Nuxt app to become interactive
|
|
16
16
|
- **Poor user experience**: Users may see content flashing or unexpected layout shifts
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
### Functionality Issues
|
|
19
19
|
|
|
20
20
|
- **Broken interactivity**: Event listeners may not attach properly, leaving buttons and forms non-functional
|
|
21
21
|
- **State inconsistencies**: Application state can become out of sync between what the user sees and what the application thinks is rendered
|
|
22
22
|
- **SEO problems**: Search engines may index different content than what users actually see
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
## How to detect them
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
### Development Console Warnings
|
|
27
27
|
|
|
28
28
|
Vue will log hydration mismatch warnings in the browser console during development:
|
|
29
29
|
|
|
30
30
|

|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
## Common reasons
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
### Browser-only APIs in Server Context
|
|
35
35
|
|
|
36
36
|
**Problem**: Using browser-specific APIs during server-side rendering.
|
|
37
37
|
|
|
@@ -60,7 +60,7 @@ const userTheme = useCookie('theme', { default: () => 'light' })
|
|
|
60
60
|
</script>
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
### Inconsistent Data
|
|
64
64
|
|
|
65
65
|
**Problem**: Different data between server and client.
|
|
66
66
|
|
|
@@ -82,7 +82,7 @@ const state = useState('random', () => Math.random())
|
|
|
82
82
|
</script>
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
### Conditional Rendering Based on Client State
|
|
86
86
|
|
|
87
87
|
**Problem**: Using client-only conditions during SSR.
|
|
88
88
|
|
|
@@ -105,7 +105,7 @@ const state = useState('random', () => Math.random())
|
|
|
105
105
|
</template>
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
### Third-party Libraries with Side Effects
|
|
109
109
|
|
|
110
110
|
**Problem**: Libraries that modify the DOM or have browser dependencies (this happens a LOT with tag managers).
|
|
111
111
|
|
|
@@ -129,7 +129,7 @@ onMounted(async () => {
|
|
|
129
129
|
</script>
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
### Dynamic Content Based on Time
|
|
133
133
|
|
|
134
134
|
**Problem**: Content that changes based on current time.
|
|
135
135
|
|
|
@@ -238,12 +238,19 @@ export default defineNuxtConfig({
|
|
|
238
238
|
|
|
239
239
|
## payloadExtraction
|
|
240
240
|
|
|
241
|
-
|
|
241
|
+
Controls how payload data is delivered for prerendered and cached (ISR/SWR) pages.
|
|
242
|
+
|
|
243
|
+
- `'client'` - Payload is inlined in HTML for the initial server render, and extracted to `_payload.json` files for client-side navigation. This avoids a separate network request on initial load while still enabling efficient client-side navigation.
|
|
244
|
+
- `true` - Payload is extracted to a separate `_payload.json` file for both the initial server render and client-side navigation.
|
|
245
|
+
- `false` - Payload extraction is disabled entirely. Payload is always inlined in HTML and no `_payload.json` files are generated.
|
|
246
|
+
|
|
247
|
+
The default is `true`, or `'client'` when `compatibilityVersion: 5` is set.
|
|
242
248
|
|
|
243
249
|
```ts twoslash [nuxt.config.ts]
|
|
244
250
|
export default defineNuxtConfig({
|
|
245
251
|
experimental: {
|
|
246
|
-
|
|
252
|
+
// Inline payload in HTML, extract for client-side navigation only
|
|
253
|
+
payloadExtraction: 'client',
|
|
247
254
|
},
|
|
248
255
|
})
|
|
249
256
|
```
|
|
@@ -253,7 +260,7 @@ Payload extraction also works for routes using ISR (Incremental Static Regenerat
|
|
|
253
260
|
```ts twoslash [nuxt.config.ts]
|
|
254
261
|
export default defineNuxtConfig({
|
|
255
262
|
experimental: {
|
|
256
|
-
payloadExtraction:
|
|
263
|
+
payloadExtraction: 'client',
|
|
257
264
|
},
|
|
258
265
|
routeRules: {
|
|
259
266
|
// Payload files will be generated for these cached routes
|
|
@@ -766,7 +773,9 @@ export default defineNuxtConfig({
|
|
|
766
773
|
|
|
767
774
|
## decorators
|
|
768
775
|
|
|
769
|
-
This option enables
|
|
776
|
+
This option enables decorator syntax across your entire Nuxt/Nitro app.
|
|
777
|
+
|
|
778
|
+
When using the Vite builder (default), decorators are lowered via [Babel](https://babeljs.io/) using [`@babel/plugin-proposal-decorators`](https://babeljs.io/docs/babel-plugin-proposal-decorators). When using the webpack or rspack builders, decorators are lowered via [esbuild](https://github.com/evanw/esbuild/releases/tag/v0.21.3).
|
|
770
779
|
|
|
771
780
|
For a long time, TypeScript has had support for decorators via `compilerOptions.experimentalDecorators`. This implementation predated the TC39 standardization process. Now, decorators are a [Stage 3 Proposal](https://github.com/tc39/proposal-decorators), and supported without special configuration in TS 5.0+ (see https://github.com/microsoft/TypeScript/pull/52582 and https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#decorators).
|
|
772
781
|
|
|
@@ -786,6 +795,24 @@ export default defineNuxtConfig({
|
|
|
786
795
|
})
|
|
787
796
|
```
|
|
788
797
|
|
|
798
|
+
When using the Vite builder or the Nitro server build, you will need to install additional Babel packages as dev dependencies:
|
|
799
|
+
|
|
800
|
+
::code-group
|
|
801
|
+
```bash [npm]
|
|
802
|
+
npm install -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
|
|
803
|
+
```
|
|
804
|
+
```bash [pnpm]
|
|
805
|
+
pnpm add -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
|
|
806
|
+
```
|
|
807
|
+
```bash [yarn]
|
|
808
|
+
yarn add -D @babel/plugin-proposal-decorators @babel/plugin-syntax-jsx
|
|
809
|
+
```
|
|
810
|
+
::
|
|
811
|
+
|
|
812
|
+
::tip
|
|
813
|
+
Nuxt will prompt you to install these automatically if they are not already present.
|
|
814
|
+
::
|
|
815
|
+
|
|
789
816
|
```ts [app/app.vue]
|
|
790
817
|
function something (_method: () => unknown) {
|
|
791
818
|
return () => 'decorated'
|
|
@@ -161,6 +161,7 @@ type AsyncDataRequestContext = {
|
|
|
161
161
|
|
|
162
162
|
type AsyncData<DataT, ErrorT> = {
|
|
163
163
|
data: Ref<DataT | undefined>
|
|
164
|
+
pending: Ref<boolean>
|
|
164
165
|
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
|
165
166
|
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
|
166
167
|
clear: () => void
|
|
@@ -229,6 +230,7 @@ This only caches data when `experimental.payloadExtraction` in `nuxt.config` is
|
|
|
229
230
|
| `execute` | `(opts?: AsyncDataExecuteOptions) => Promise<void>` | Alias for `refresh`. |
|
|
230
231
|
| `error` | `Ref<ErrorT \| undefined>` | Error object if the data fetching failed. |
|
|
231
232
|
| `status` | `Ref<'idle' \| 'pending' \| 'success' \| 'error'>` | Status of the data request. See below for possible values. |
|
|
233
|
+
| `pending` | `Ref<boolean>` | Boolean flag indicating whether the current request is in progress. |
|
|
232
234
|
| `clear` | `() => void` | Resets `data` to `undefined` (or the value of `options.default()` if provided), `error` to `undefined`, set `status` to `idle`, and cancels any pending requests. |
|
|
233
235
|
|
|
234
236
|
### Status values
|
|
@@ -76,6 +76,7 @@ Returns the same `AsyncData` object as [`useFetch`](/docs/4.x/api/composables/us
|
|
|
76
76
|
| `execute` | `(opts?: AsyncDataExecuteOptions) => Promise<void>` | Alias for `refresh`. |
|
|
77
77
|
| `error` | `Ref<ErrorT \| undefined>` | Error object if the data fetching failed. |
|
|
78
78
|
| `status` | `Ref<'idle' \| 'pending' \| 'success' \| 'error'>` | Status of the data request. |
|
|
79
|
+
| `pending` | `Ref<boolean>` | Boolean flag indicating whether the current request is in progress. |
|
|
79
80
|
| `clear` | `() => void` | Resets `data` to `undefined`, `error` to `undefined`, sets `status` to `idle`, and cancels any pending requests. |
|
|
80
81
|
|
|
81
82
|
:read-more{to="/docs/4.x/api/composables/use-fetch#return-values"}
|