@nuxt/docs 4.3.1 → 4.4.2
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/02.installation.md +2 -1
- package/1.getting-started/09.transitions.md +100 -0
- package/1.getting-started/16.deployment.md +2 -3
- package/1.getting-started/17.testing.md +63 -8
- package/1.getting-started/18.upgrade.md +138 -2
- package/2.directory-structure/1.app/1.layouts.md +60 -1
- package/3.guide/2.best-practices/hydration.md +13 -13
- package/3.guide/2.best-practices/performance.md +2 -3
- package/3.guide/3.ai/1.mcp.md +1 -1
- package/3.guide/3.ai/2.llms-txt.md +1 -1
- package/3.guide/5.recipes/3.custom-usefetch.md +36 -67
- package/3.guide/5.recipes/4.sessions-and-authentication.md +1 -1
- package/3.guide/6.going-further/1.experimental-features.md +81 -5
- package/4.api/1.components/12.nuxt-route-announcer.md +4 -0
- package/4.api/1.components/14.nuxt-announcer.md +81 -0
- package/4.api/1.components/3.nuxt-layout.md +29 -0
- package/4.api/1.components/8.nuxt-island.md +1 -1
- package/4.api/2.composables/create-use-async-data.md +90 -0
- package/4.api/2.composables/create-use-fetch.md +97 -0
- package/4.api/2.composables/use-announcer.md +128 -0
- package/4.api/2.composables/use-async-data.md +2 -2
- package/4.api/2.composables/use-cookie.md +24 -0
- package/4.api/2.composables/use-fetch.md +5 -5
- package/4.api/2.composables/use-lazy-fetch.md +1 -0
- package/4.api/2.composables/use-route-announcer.md +4 -0
- package/4.api/3.utils/clear-nuxt-state.md +4 -2
- package/4.api/3.utils/define-page-meta.md +61 -4
- package/4.api/4.commands/build.md +3 -2
- package/4.api/4.commands/dev.md +2 -1
- package/4.api/4.commands/generate.md +2 -1
- package/4.api/6.advanced/1.hooks.md +1 -1
- package/5.community/2.getting-help.md +1 -1
- package/package.json +1 -1
|
@@ -20,13 +20,14 @@ Or follow the steps below to set up a new Nuxt project on your computer.
|
|
|
20
20
|
### Prerequisites
|
|
21
21
|
|
|
22
22
|
- **Node.js** - [`20.x`](https://nodejs.org/en) or newer (but we recommend the [active LTS release](https://github.com/nodejs/release#release-schedule))
|
|
23
|
-
- **Text editor** - There is no IDE requirement, but we recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar) or [WebStorm](https://www.jetbrains.com/webstorm/), which, along with [other JetBrains IDEs](https://www.jetbrains.com/ides/), offers great Nuxt support right out-of-the-box.
|
|
23
|
+
- **Text editor** - There is no IDE requirement, but we recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar) or [WebStorm](https://www.jetbrains.com/webstorm/), which, along with [other JetBrains IDEs](https://www.jetbrains.com/ides/), offers great Nuxt support right out-of-the-box. If you use another editor, such as Neovim, you can configure [Vue Language Server](https://github.com/vuejs/language-tools) support by following the [Vue Language Tools setup guides](https://github.com/vuejs/language-tools/wiki).
|
|
24
24
|
- **Terminal** - In order to run Nuxt commands
|
|
25
25
|
|
|
26
26
|
::note
|
|
27
27
|
::details
|
|
28
28
|
:summary[Additional notes for an optimal setup:]
|
|
29
29
|
- **Node.js**: Make sure to use an even numbered version (20, 22, etc.)
|
|
30
|
+
- **Neovim**: When configuring the Vue TypeScript plugin, make sure `location` points to the `@vue/language-server` package directory, not its binary. See the [Neovim setup guide](https://github.com/vuejs/language-tools/wiki/Neovim) for a working configuration.
|
|
30
31
|
- **WSL**: If you are using Windows and experience slow HMR, you may want to try using [WSL (Windows Subsystem for Linux)](https://learn.microsoft.com/en-us/windows/wsl/install) which may solve some performance issues.
|
|
31
32
|
- **Windows slow DNS resolution**: Instead of using `localhost:3000` for local dev server on Windows, use `127.0.0.1` for much faster loading experience on browsers.
|
|
32
33
|
::
|
|
@@ -459,6 +459,106 @@ definePageMeta({
|
|
|
459
459
|
Overriding view transitions on a per-page basis will only have an effect if you have enabled the `experimental.viewTransition` option.
|
|
460
460
|
::
|
|
461
461
|
|
|
462
|
+
### View Transition Types
|
|
463
|
+
|
|
464
|
+
[View transition types](https://developer.chrome.com/blog/view-transitions-update-io24#view-transition-types) allow you to apply different CSS animations depending on the type of navigation. This is useful for creating asymmetric transitions (e.g., a different animation when navigating forward vs. backward).
|
|
465
|
+
|
|
466
|
+
Types are set on the [`ViewTransition`](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) and can be targeted in CSS using the [`:active-view-transition-type()`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:active-view-transition-type) pseudo-class selector.
|
|
467
|
+
|
|
468
|
+
You can set default types globally in your `nuxt.config.ts`:
|
|
469
|
+
|
|
470
|
+
```ts twoslash [nuxt.config.ts]
|
|
471
|
+
export default defineNuxtConfig({
|
|
472
|
+
app: {
|
|
473
|
+
viewTransition: {
|
|
474
|
+
enabled: true,
|
|
475
|
+
types: ['slide'],
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
})
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
Or configure types per-page using `definePageMeta`. Per-page types support both static arrays and functions for dynamic behavior:
|
|
482
|
+
|
|
483
|
+
```vue twoslash [pages/detail.vue]
|
|
484
|
+
<script setup lang="ts">
|
|
485
|
+
definePageMeta({
|
|
486
|
+
viewTransition: {
|
|
487
|
+
enabled: true,
|
|
488
|
+
// Types applied to any transition involving this page
|
|
489
|
+
types: ['slide'],
|
|
490
|
+
// Types applied only when navigating TO this page
|
|
491
|
+
toTypes: ['slide-in'],
|
|
492
|
+
// Types applied only when navigating FROM this page
|
|
493
|
+
fromTypes: ['slide-out'],
|
|
494
|
+
},
|
|
495
|
+
})
|
|
496
|
+
</script>
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
You can also use functions for `types`, `toTypes`, and `fromTypes` in `definePageMeta` to determine types dynamically based on the route:
|
|
500
|
+
|
|
501
|
+
```vue twoslash [pages/[id].vue]
|
|
502
|
+
<script setup lang="ts">
|
|
503
|
+
definePageMeta({
|
|
504
|
+
viewTransition: {
|
|
505
|
+
enabled: true,
|
|
506
|
+
toTypes: (to, from) => {
|
|
507
|
+
// Slide left when going to a higher ID, right otherwise
|
|
508
|
+
return Number(to.params.id) > Number(from.params.id)
|
|
509
|
+
? ['slide-left']
|
|
510
|
+
: ['slide-right']
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
})
|
|
514
|
+
</script>
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Then target these types in your CSS:
|
|
518
|
+
|
|
519
|
+
```css
|
|
520
|
+
/* Default crossfade */
|
|
521
|
+
::view-transition-old(root),
|
|
522
|
+
::view-transition-new(root) {
|
|
523
|
+
animation-duration: 0.3s;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* Slide left animation */
|
|
527
|
+
html:active-view-transition-type(slide-left) {
|
|
528
|
+
&::view-transition-old(root) {
|
|
529
|
+
animation: slide-out-left 0.3s ease-in-out;
|
|
530
|
+
}
|
|
531
|
+
&::view-transition-new(root) {
|
|
532
|
+
animation: slide-in-right 0.3s ease-in-out;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/* Slide right animation */
|
|
537
|
+
html:active-view-transition-type(slide-right) {
|
|
538
|
+
&::view-transition-old(root) {
|
|
539
|
+
animation: slide-out-right 0.3s ease-in-out;
|
|
540
|
+
}
|
|
541
|
+
&::view-transition-new(root) {
|
|
542
|
+
animation: slide-in-left 0.3s ease-in-out;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
::note
|
|
548
|
+
Function values for `types`, `toTypes`, and `fromTypes` only work in `definePageMeta`, not in `nuxt.config.ts` (where only static `string[]` is supported).
|
|
549
|
+
::
|
|
550
|
+
|
|
551
|
+
The `page:view-transition:start` hook provides access to the [`ViewTransition`](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) object, which includes a [`types`](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition/types) property (`ViewTransitionTypeSet`) that can be read or modified at runtime:
|
|
552
|
+
|
|
553
|
+
```ts [plugins/view-transition.client.ts]
|
|
554
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
555
|
+
nuxtApp.hook('page:view-transition:start', (transition) => {
|
|
556
|
+
// Read or modify types at runtime
|
|
557
|
+
console.log([...transition.types])
|
|
558
|
+
})
|
|
559
|
+
})
|
|
560
|
+
```
|
|
561
|
+
|
|
462
562
|
If you are also using Vue transitions like `pageTransition` and `layoutTransition` (see above) to achieve the same result as the new View Transitions API, then you may wish to _disable_ Vue transitions if the user's browser supports the newer, native web API. You can do this by creating `~/middleware/disable-vue-transitions.global.ts` with the following contents:
|
|
463
563
|
|
|
464
564
|
```ts
|
|
@@ -120,9 +120,8 @@ In most cases, Nuxt can work with third-party content that is not generated or c
|
|
|
120
120
|
|
|
121
121
|
Accordingly, you should make sure that the following options are unchecked / disabled in Cloudflare. Otherwise, unnecessary re-rendering or hydration errors could impact your production application.
|
|
122
122
|
|
|
123
|
-
1. Speed >
|
|
124
|
-
2.
|
|
125
|
-
3. Scrape Shield > Disable "Email Address Obfuscation"
|
|
123
|
+
1. Speed > Settings > Content Optimization > Disable "Rocket Loader™"
|
|
124
|
+
2. Security > Settings > Disable "Email Address Obfuscation"
|
|
126
125
|
|
|
127
126
|
With these settings, you can be sure that Cloudflare won't inject scripts into your Nuxt application that may cause unwanted side effects.
|
|
128
127
|
|
|
@@ -108,6 +108,7 @@ If you prefer a simpler setup and want all tests to run in the Nuxt environment,
|
|
|
108
108
|
|
|
109
109
|
```ts twoslash
|
|
110
110
|
import { defineVitestConfig } from '@nuxt/test-utils/config'
|
|
111
|
+
import { fileURLToPath } from 'node:url'
|
|
111
112
|
|
|
112
113
|
export default defineVitestConfig({
|
|
113
114
|
test: {
|
|
@@ -299,6 +300,10 @@ it('can also mount an app', async () => {
|
|
|
299
300
|
})
|
|
300
301
|
```
|
|
301
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
|
+
|
|
302
307
|
#### `renderSuspended`
|
|
303
308
|
|
|
304
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.
|
|
@@ -351,14 +356,18 @@ it('can also render an app', async () => {
|
|
|
351
356
|
})
|
|
352
357
|
```
|
|
353
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
|
+
|
|
354
363
|
#### `mockNuxtImport`
|
|
355
364
|
|
|
356
|
-
`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:
|
|
357
366
|
|
|
358
367
|
```ts twoslash
|
|
359
368
|
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
|
|
360
369
|
|
|
361
|
-
mockNuxtImport('
|
|
370
|
+
mockNuxtImport('useState', () => {
|
|
362
371
|
return () => {
|
|
363
372
|
return { value: 'mocked storage' }
|
|
364
373
|
}
|
|
@@ -367,6 +376,27 @@ mockNuxtImport('useStorage', () => {
|
|
|
367
376
|
// your tests here
|
|
368
377
|
```
|
|
369
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
|
+
|
|
370
400
|
::note
|
|
371
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).
|
|
372
402
|
::
|
|
@@ -377,24 +407,43 @@ If you need to mock a Nuxt import and provide different implementations between
|
|
|
377
407
|
import { vi } from 'vitest'
|
|
378
408
|
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
|
|
379
409
|
|
|
380
|
-
const {
|
|
410
|
+
const { useStateMock } = vi.hoisted(() => {
|
|
381
411
|
return {
|
|
382
|
-
|
|
412
|
+
useStateMock: vi.fn(() => {
|
|
383
413
|
return { value: 'mocked storage' }
|
|
384
414
|
}),
|
|
385
415
|
}
|
|
386
416
|
})
|
|
387
417
|
|
|
388
|
-
mockNuxtImport('
|
|
389
|
-
return
|
|
418
|
+
mockNuxtImport('useState', () => {
|
|
419
|
+
return useStateMock
|
|
390
420
|
})
|
|
391
421
|
|
|
392
422
|
// Then, inside a test
|
|
393
|
-
|
|
423
|
+
useStateMock.mockImplementation(() => {
|
|
394
424
|
return { value: 'something else' }
|
|
395
425
|
})
|
|
396
426
|
```
|
|
397
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
|
+
|
|
398
447
|
#### `mockComponent`
|
|
399
448
|
|
|
400
449
|
`mockComponent` allows you to mock Nuxt's component.
|
|
@@ -476,6 +525,12 @@ registerEndpoint('/test/', {
|
|
|
476
525
|
})
|
|
477
526
|
```
|
|
478
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
|
+
|
|
479
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.
|
|
480
535
|
|
|
481
536
|
#### Conflict with End-To-End Testing
|
|
@@ -489,7 +544,7 @@ If you would like to use both the end-to-end and unit testing functionality of `
|
|
|
489
544
|
```ts twoslash
|
|
490
545
|
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
|
|
491
546
|
|
|
492
|
-
mockNuxtImport('
|
|
547
|
+
mockNuxtImport('useState', () => {
|
|
493
548
|
return () => {
|
|
494
549
|
return { value: 'mocked storage' }
|
|
495
550
|
}
|
|
@@ -59,6 +59,9 @@ export default defineNuxtConfig({
|
|
|
59
59
|
When you set your `future.compatibilityVersion` to `5`, defaults throughout your Nuxt configuration will change to opt in to Nuxt v5 behavior, including:
|
|
60
60
|
|
|
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
|
+
- **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
|
+
- **`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`
|
|
62
65
|
- Other Nuxt 5 improvements and changes as they become available
|
|
63
66
|
|
|
64
67
|
::note
|
|
@@ -178,6 +181,52 @@ addVitePlugin(() => ({
|
|
|
178
181
|
Learn more about Vite's Environment API
|
|
179
182
|
::
|
|
180
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
|
+
|
|
181
230
|
## Migrating to Nuxt 4
|
|
182
231
|
|
|
183
232
|
Nuxt 4 includes significant improvements and changes. This guide will help you migrate your existing Nuxt 3 application to Nuxt 4.
|
|
@@ -272,6 +321,7 @@ Nuxt now defaults to a new directory structure, with backwards compatibility (so
|
|
|
272
321
|
- `layers/`, `modules/` and `public/` are resolved relative to `<rootDir>` by default
|
|
273
322
|
- if using [Nuxt Content v2.13+](https://github.com/nuxt/content/pull/2649), `content/` is resolved relative to `<rootDir>`
|
|
274
323
|
- a new `dir.app` is added, which is the directory we look for `router.options.ts` and `spa-loading-template.html` - this defaults to `<srcDir>/`
|
|
324
|
+
- a new [`shared/`](/docs/4.x/directory-structure/shared) directory is available for code shared between the Vue app and the Nitro server, with auto-imports for `shared/utils/` and `shared/types/`
|
|
275
325
|
|
|
276
326
|
<details>
|
|
277
327
|
|
|
@@ -298,6 +348,8 @@ modules/
|
|
|
298
348
|
node_modules/
|
|
299
349
|
public/
|
|
300
350
|
shared/
|
|
351
|
+
types/
|
|
352
|
+
utils/
|
|
301
353
|
server/
|
|
302
354
|
api/
|
|
303
355
|
middleware/
|
|
@@ -326,14 +378,14 @@ With this new structure, the `~` alias now points to the `app/` directory by def
|
|
|
326
378
|
|
|
327
379
|
1. Create a new directory called `app/`.
|
|
328
380
|
1. Move your `assets/`, `components/`, `composables/`, `app/layouts/`, `app/middleware/`, `app/pages/`, `app/plugins/` and `utils/` folders under it, as well as `app.vue`, `error.vue`, `app.config.ts`. If you have an `app/router-options.ts` or `app/spa-loading-template.html`, these paths remain the same.
|
|
329
|
-
1. Make sure your `nuxt.config.ts`, `content/`, `layers/`, `modules/`, `public/` and `server/` folders remain outside the `app/` folder, in the root of your project.
|
|
381
|
+
1. Make sure your `nuxt.config.ts`, `content/`, `layers/`, `modules/`, `public/`, `shared/` and `server/` folders remain outside the `app/` folder, in the root of your project.
|
|
330
382
|
1. Remember to update any third-party configuration files to work with the new directory structure, such as your `tailwindcss` or `eslint` configuration (if required - `@nuxtjs/tailwindcss` should automatically configure `tailwindcss` correctly).
|
|
331
383
|
|
|
332
384
|
::tip
|
|
333
385
|
You can automate this migration by running `npx codemod@latest nuxt/4/file-structure`
|
|
334
386
|
::
|
|
335
387
|
|
|
336
|
-
However, migration is _not required_. If you wish to keep your current folder structure, Nuxt should auto-detect it. (If it does not, please raise an issue.) The one exception is that if you _already_ have a custom `srcDir`. In this case, you should be aware that your `modules/`, `public/` and `server/` folders will be resolved from your `rootDir` rather than from your custom `srcDir`. You can override this by configuring `dir.modules`, `dir.public` and `serverDir` if you need to.
|
|
388
|
+
However, migration is _not required_. If you wish to keep your current folder structure, Nuxt should auto-detect it. (If it does not, please raise an issue.) The one exception is that if you _already_ have a custom `srcDir`. In this case, you should be aware that your `modules/`, `public/`, `shared/` and `server/` folders will be resolved from your `rootDir` rather than from your custom `srcDir`. You can override this by configuring `dir.modules`, `dir.public` and `serverDir` if you need to.
|
|
337
389
|
|
|
338
390
|
You can also force a v3 folder structure with the following configuration:
|
|
339
391
|
|
|
@@ -846,6 +898,55 @@ If you provide a custom `default` value for `useAsyncData`, this will now be use
|
|
|
846
898
|
|
|
847
899
|
Often users set an appropriately empty value, such as an empty array, to avoid the need to check for `null`/`undefined` when iterating over it. This should be respected when resetting/clearing the data.
|
|
848
900
|
|
|
901
|
+
### Respect defaults when clearing `useState`
|
|
902
|
+
|
|
903
|
+
🚦 **Impact Level**: Minimal
|
|
904
|
+
|
|
905
|
+
#### What Changed
|
|
906
|
+
|
|
907
|
+
With `compatibilityVersion: 5`, `clearNuxtState` will reset state to its initial value (provided by the `init` function of `useState`) instead of setting it to `undefined`. This aligns `clearNuxtState` behavior with `clearNuxtData`, which already resets to defaults.
|
|
908
|
+
|
|
909
|
+
#### Reasons for Change
|
|
910
|
+
|
|
911
|
+
When `clearNuxtState` sets state to `undefined`, composables that depend on that state can crash because they expect the state to always have a valid shape (e.g., accessing properties on `undefined`). Resetting to the `init` value ensures state always has a usable default.
|
|
912
|
+
|
|
913
|
+
#### Migration Steps
|
|
914
|
+
|
|
915
|
+
If you rely on `clearNuxtState` setting state to `undefined`, you can explicitly pass `{ reset: false }`:
|
|
916
|
+
|
|
917
|
+
```diff
|
|
918
|
+
- clearNuxtState('myKey')
|
|
919
|
+
+ clearNuxtState('myKey', { reset: false })
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
Alternatively, you can revert to the previous behavior with:
|
|
923
|
+
|
|
924
|
+
```ts twoslash [nuxt.config.ts]
|
|
925
|
+
export default defineNuxtConfig({
|
|
926
|
+
experimental: {
|
|
927
|
+
defaults: {
|
|
928
|
+
useState: {
|
|
929
|
+
resetOnClear: false,
|
|
930
|
+
},
|
|
931
|
+
},
|
|
932
|
+
},
|
|
933
|
+
})
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
You can also opt in to this behavior today without setting `compatibilityVersion: 5`:
|
|
937
|
+
|
|
938
|
+
```ts twoslash [nuxt.config.ts]
|
|
939
|
+
export default defineNuxtConfig({
|
|
940
|
+
experimental: {
|
|
941
|
+
defaults: {
|
|
942
|
+
useState: {
|
|
943
|
+
resetOnClear: true,
|
|
944
|
+
},
|
|
945
|
+
},
|
|
946
|
+
},
|
|
947
|
+
})
|
|
948
|
+
```
|
|
949
|
+
|
|
849
950
|
### Alignment of `pending` value in `useAsyncData` and `useFetch`
|
|
850
951
|
|
|
851
952
|
🚦 **Impact Level**: Medium
|
|
@@ -1321,6 +1422,41 @@ export default defineNuxtConfig({
|
|
|
1321
1422
|
Read more about Nitro's prerender configuration options.
|
|
1322
1423
|
::
|
|
1323
1424
|
|
|
1425
|
+
### Normalized Page Component Names
|
|
1426
|
+
|
|
1427
|
+
🚦 **Impact Level**: Minimal
|
|
1428
|
+
|
|
1429
|
+
#### What Changed
|
|
1430
|
+
|
|
1431
|
+
When `future.compatibilityVersion` is set to `5` (or `experimental.normalizePageNames` is enabled), page component names match their route names instead of using the filename. For example, `pages/foo/index.vue` will have the component name `foo` instead of `index`.
|
|
1432
|
+
|
|
1433
|
+
#### Reasons for Change
|
|
1434
|
+
|
|
1435
|
+
Previously, Vue assigned component names based on the filename. This meant multiple pages like `pages/foo/index.vue` and `pages/bar/index.vue` would both have the component name `index`. This made `<KeepAlive>` with `include`/`exclude` filters unreliable and required manually adding `defineOptions({ name: '...' })` to each page.
|
|
1436
|
+
|
|
1437
|
+
#### Migration Steps
|
|
1438
|
+
|
|
1439
|
+
If you rely on the current component names (e.g. in `<KeepAlive>` `include`/`exclude` lists), update them to use route names instead of filenames.
|
|
1440
|
+
|
|
1441
|
+
```diff
|
|
1442
|
+
<template>
|
|
1443
|
+
<NuxtPage :keepalive="{
|
|
1444
|
+
- include: ['index']
|
|
1445
|
+
+ include: ['foo']
|
|
1446
|
+
}" />
|
|
1447
|
+
</template>
|
|
1448
|
+
```
|
|
1449
|
+
|
|
1450
|
+
To disable this behavior:
|
|
1451
|
+
|
|
1452
|
+
```ts twoslash [nuxt.config.ts]
|
|
1453
|
+
export default defineNuxtConfig({
|
|
1454
|
+
experimental: {
|
|
1455
|
+
normalizePageNames: false,
|
|
1456
|
+
},
|
|
1457
|
+
})
|
|
1458
|
+
```
|
|
1459
|
+
|
|
1324
1460
|
## Nuxt 2 vs. Nuxt 3+
|
|
1325
1461
|
|
|
1326
1462
|
In the table below, there is a quick comparison between 3 versions of Nuxt:
|
|
@@ -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 {
|
|
@@ -168,6 +168,65 @@ This is useful when you want to manage layouts centrally in your configuration r
|
|
|
168
168
|
|
|
169
169
|
:link-example{to="/docs/4.x/examples/features/layouts"}
|
|
170
170
|
|
|
171
|
+
## Passing Props to Layouts
|
|
172
|
+
|
|
173
|
+
You can pass props to layouts in several ways.
|
|
174
|
+
|
|
175
|
+
### Via `definePageMeta`
|
|
176
|
+
|
|
177
|
+
Use the object syntax for the `layout` property to pass props directly from your page:
|
|
178
|
+
|
|
179
|
+
::code-group
|
|
180
|
+
|
|
181
|
+
```vue [app/pages/dashboard.vue]
|
|
182
|
+
<script setup lang="ts">
|
|
183
|
+
definePageMeta({
|
|
184
|
+
layout: {
|
|
185
|
+
name: 'panel',
|
|
186
|
+
props: {
|
|
187
|
+
sidebar: true,
|
|
188
|
+
title: 'Dashboard',
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
})
|
|
192
|
+
</script>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
```vue [app/layouts/panel.vue]
|
|
196
|
+
<script setup lang="ts">
|
|
197
|
+
const props = defineProps<{
|
|
198
|
+
sidebar?: boolean
|
|
199
|
+
title?: string
|
|
200
|
+
}>()
|
|
201
|
+
</script>
|
|
202
|
+
|
|
203
|
+
<template>
|
|
204
|
+
<div>
|
|
205
|
+
<aside v-if="sidebar">
|
|
206
|
+
Sidebar
|
|
207
|
+
</aside>
|
|
208
|
+
<main>
|
|
209
|
+
<h1>{{ title }}</h1>
|
|
210
|
+
<slot />
|
|
211
|
+
</main>
|
|
212
|
+
</div>
|
|
213
|
+
</template>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
::
|
|
217
|
+
|
|
218
|
+
::tip
|
|
219
|
+
Props are fully typed based on your layout's `defineProps`. You'll get autocomplete and type-checking in your editor.
|
|
220
|
+
::
|
|
221
|
+
|
|
222
|
+
### Via `setPageLayout`
|
|
223
|
+
|
|
224
|
+
You can also pass props when changing the layout dynamically with [`setPageLayout`](/docs/4.x/api/utils/set-page-layout):
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
setPageLayout('panel', { sidebar: true, title: 'Dashboard' })
|
|
228
|
+
```
|
|
229
|
+
|
|
171
230
|
## Overriding a Layout on a Per-page Basis
|
|
172
231
|
|
|
173
232
|
If you are using pages, you can take full control by setting `layout: false` and then using the `<NuxtLayout>` component within the page.
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
---
|
|
2
|
-
navigation.title: 'Nuxt and
|
|
3
|
-
title: Nuxt and
|
|
2
|
+
navigation.title: 'Nuxt and Hydration'
|
|
3
|
+
title: Nuxt and Hydration
|
|
4
4
|
description: Why fixing hydration issues is important
|
|
5
5
|
---
|
|
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
|
|
|
@@ -142,9 +142,8 @@ Images in your website can usually be separated by importance; the ones that are
|
|
|
142
142
|
<NuxtImg
|
|
143
143
|
src="/hero-banner.jpg"
|
|
144
144
|
format="webp"
|
|
145
|
-
preload
|
|
145
|
+
:preload="{ fetchPriority: 'high' }"
|
|
146
146
|
loading="eager"
|
|
147
|
-
fetch-priority="high"
|
|
148
147
|
width="200"
|
|
149
148
|
height="100"
|
|
150
149
|
/>
|
|
@@ -154,7 +153,7 @@ Images in your website can usually be separated by importance; the ones that are
|
|
|
154
153
|
src="/facebook-logo.jpg"
|
|
155
154
|
format="webp"
|
|
156
155
|
loading="lazy"
|
|
157
|
-
|
|
156
|
+
fetchpriority="low"
|
|
158
157
|
width="200"
|
|
159
158
|
height="100"
|
|
160
159
|
/>
|
package/3.guide/3.ai/1.mcp.md
CHANGED
|
@@ -79,7 +79,7 @@ The Nuxt connector will appear in the composer's "Developer mode" tool later dur
|
|
|
79
79
|
### Claude Code
|
|
80
80
|
|
|
81
81
|
::note{icon="i-lucide-info"}
|
|
82
|
-
**Ensure Claude Code is installed** - Visit [Anthropic's documentation](https://
|
|
82
|
+
**Ensure Claude Code is installed** - Visit [Anthropic's documentation](https://code.claude.com/docs/en/quickstart) for installation instructions.
|
|
83
83
|
::
|
|
84
84
|
|
|
85
85
|
Add the server using the CLI command:
|
|
@@ -42,7 +42,7 @@ Nuxt provides specialized LLMs.txt files that you can reference in Cursor for be
|
|
|
42
42
|
1. **Direct reference**: Mention the LLMs.txt URLs when asking questions
|
|
43
43
|
2. Add these specific URLs to your project context using `@docs`
|
|
44
44
|
|
|
45
|
-
[Read more about Cursor Web and Docs Search](https://cursor.com/docs/context/
|
|
45
|
+
[Read more about Cursor Web and Docs Search](https://cursor.com/docs/context/mentions)
|
|
46
46
|
|
|
47
47
|
### Windsurf
|
|
48
48
|
|