Merge branch 'main' into fix/use-cookie

This commit is contained in:
Alexander Lichter 2023-07-12 18:59:32 +02:00 committed by GitHub
commit 63912b6075
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
121 changed files with 1101 additions and 866 deletions

View File

@ -1,4 +1,5 @@
{ {
"$schema": "https://json.schemastore.org/eslintrc",
"globals": { "globals": {
"NodeJS": true, "NodeJS": true,
"$fetch": true "$fetch": true

View File

@ -19,7 +19,7 @@ jobs:
steps: steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"
@ -30,4 +30,4 @@ jobs:
- name: Lint (docs) - name: Lint (docs)
run: pnpm lint:docs:fix run: pnpm lint:docs:fix
- uses: autofix-ci/action@8bc06253bec489732e5f9c52884c7cace15c0160 - uses: autofix-ci/action@8caa572fd27b0019a65e4c695447089c8d3138b9

View File

@ -15,7 +15,7 @@ jobs:
steps: steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"
@ -42,4 +42,4 @@ jobs:
- name: Update bundle size - name: Update bundle size
run: pnpm vitest run bundle -u run: pnpm vitest run bundle -u
- uses: autofix-ci/action@8bc06253bec489732e5f9c52884c7cace15c0160 - uses: autofix-ci/action@8caa572fd27b0019a65e4c695447089c8d3138b9

View File

@ -23,7 +23,7 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"

View File

@ -40,7 +40,7 @@ jobs:
steps: steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"
@ -77,7 +77,7 @@ jobs:
steps: steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"
@ -117,7 +117,7 @@ jobs:
steps: steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"
@ -146,7 +146,7 @@ jobs:
steps: steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"
@ -182,7 +182,7 @@ jobs:
steps: steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: ${{ matrix.node }} node-version: ${{ matrix.node }}
cache: "pnpm" cache: "pnpm"
@ -257,7 +257,7 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"
@ -296,7 +296,7 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"

View File

@ -23,7 +23,7 @@ jobs:
steps: steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
cache: "pnpm" cache: "pnpm"

View File

@ -22,7 +22,7 @@ jobs:
steps: steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"

View File

@ -27,7 +27,7 @@ jobs:
fetch-depth: 0 # All history fetch-depth: 0 # All history
- name: fetch tags - name: fetch tags
run: git fetch --depth=1 origin "+refs/tags/*:refs/tags/*" run: git fetch --depth=1 origin "+refs/tags/*:refs/tags/*"
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 16 node-version: 16
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'

View File

@ -35,7 +35,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 - uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"vue.volar"
]
}

View File

@ -34,7 +34,7 @@ Start with one of our starters and themes directly by opening [nuxt.new](https:/
- **Volar**: Either enable [**Take Over Mode**](https://vuejs.org/guide/typescript/overview.html#volar-takeover-mode) (recommended) or add the [TypeScript Vue Plugin](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) - **Volar**: Either enable [**Take Over Mode**](https://vuejs.org/guide/typescript/overview.html#volar-takeover-mode) (recommended) or add the [TypeScript Vue Plugin](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin)
If you have enabled **Take Over Mode** or installed the **TypeScript Vue Plugin (Volar)**, you can disable generating the shim for `*.vue` files in your `nuxt.config.ts` file: If you have enabled **Take Over Mode** or installed the **TypeScript Vue Plugin (Volar)**, you can disable generating the shim for `*.vue` files in your [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) file:
```ts [nuxt.config.ts] ```ts [nuxt.config.ts]
export default defineNuxtConfig({ export default defineNuxtConfig({

View File

@ -9,7 +9,7 @@ By default, Nuxt is configured to cover most use cases. The [`nuxt.config.ts`](/
## Nuxt Configuration ## Nuxt Configuration
The `nuxt.config.ts` file is located at the root of a Nuxt project and can override or extend the application's behavior. The [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) file is located at the root of a Nuxt project and can override or extend the application's behavior.
A minimal configuration file exports the `defineNuxtConfig` function containing an object with your configuration. The `defineNuxtConfig` helper is globally available without import. A minimal configuration file exports the `defineNuxtConfig` function containing an object with your configuration. The `defineNuxtConfig` helper is globally available without import.
@ -135,7 +135,7 @@ Non primitive JS types | ❌ No | ✅ Yes
## External Configuration Files ## External Configuration Files
Nuxt uses `nuxt.config.ts` file as the single source of trust for configurations and skips reading external configuration files. During the course of building your project, you may have a need to configure those. The following table highlights common configurations and, where applicable, how they can be configured with Nuxt. Nuxt uses [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) file as the single source of trust for configurations and skips reading external configuration files. During the course of building your project, you may have a need to configure those. The following table highlights common configurations and, where applicable, how they can be configured with Nuxt.
Name | Config File | How To Configure Name | Config File | How To Configure
|---------------------------------------------|---------------------------|------------------------- |---------------------------------------------|---------------------------|-------------------------

View File

@ -28,7 +28,7 @@ If you are familiar with Vue, you might wonder where `main.js` is (the file that
![Components are reusable pieces of UI](/assets/docs/getting-started/views/components.svg) ![Components are reusable pieces of UI](/assets/docs/getting-started/views/components.svg)
Most components are reusable pieces of the user interface, like buttons and menus. In Nuxt, you can create these components in the `components/` directory, and they will be automatically available across your application without having to explicitly import them. Most components are reusable pieces of the user interface, like buttons and menus. In Nuxt, you can create these components in the [`components/` directory](/docs/guide/directory-structure/components), and they will be automatically available across your application without having to explicitly import them.
::code-group ::code-group
@ -57,9 +57,9 @@ Most components are reusable pieces of the user interface, like buttons and menu
![Pages are views tied to a specific route](/assets/docs/getting-started/views/pages.svg) ![Pages are views tied to a specific route](/assets/docs/getting-started/views/pages.svg)
Pages represent views for each specific route pattern. Every file in the `pages/` directory represents a different route displaying its content. Pages represent views for each specific route pattern. Every file in the [`pages/` directory](/docs/guide/directory-structure/pages) represents a different route displaying its content.
To use pages, create `pages/index.vue` file and add `<NuxtPage />` component to the `app.vue` (or remove `app.vue` for default entry). You can now create more pages and their corresponding routes by adding new files in the `pages/` directory. To use pages, create `pages/index.vue` file and add `<NuxtPage />` component to the `app.vue` (or remove `app.vue` for default entry). You can now create more pages and their corresponding routes by adding new files in the [`pages/` directory](/docs/guide/directory-structure/pages).
::code-group ::code-group
@ -136,7 +136,7 @@ If you want to create more layouts and learn how to use them in your pages, find
## Advanced: Extending the HTML template ## Advanced: Extending the HTML template
::alert{type=info} ::alert{type=info}
If you only need to modify the head, you can refer to the [SEO and meta section](docs/getting-started/seo-meta). If you only need to modify the head, you can refer to the [SEO and meta section](/docs/getting-started/seo-meta).
:: ::
You can have full control over the HTML template by adding a Nitro plugin that registers a hook. You can have full control over the HTML template by adding a Nitro plugin that registers a hook.

View File

@ -13,7 +13,7 @@ Nuxt uses two directories to handle assets like stylesheets, fonts or images.
The [`public/` directory](/docs/guide/directory-structure/public) is used as a public server for static assets publicly available at a defined URL of your application. The [`public/` directory](/docs/guide/directory-structure/public) is used as a public server for static assets publicly available at a defined URL of your application.
You can get a file in the `public/` directory from your application's code or from a browser by the root URL `/`. You can get a file in the [`public/` directory](/docs/guide/directory-structure/public) from your application's code or from a browser by the root URL `/`.
### Example ### Example
@ -29,9 +29,9 @@ For example, referencing an image file in the `public/img/` directory, available
Nuxt uses [Vite](https://vitejs.dev/guide/assets.html) or [webpack](https://webpack.js.org/guides/asset-management/) to build and bundle your application. The main function of these build tools is to process JavaScript files, but they can be extended through [plugins](https://vitejs.dev/plugins/) (for Vite) or [loaders](https://webpack.js.org/loaders/) (for webpack) to process other kind of assets, like stylesheets, fonts or SVG. This step transforms the original file mainly for performance or caching purposes (such as stylesheets minification or browser cache invalidation). Nuxt uses [Vite](https://vitejs.dev/guide/assets.html) or [webpack](https://webpack.js.org/guides/asset-management/) to build and bundle your application. The main function of these build tools is to process JavaScript files, but they can be extended through [plugins](https://vitejs.dev/plugins/) (for Vite) or [loaders](https://webpack.js.org/loaders/) (for webpack) to process other kind of assets, like stylesheets, fonts or SVG. This step transforms the original file mainly for performance or caching purposes (such as stylesheets minification or browser cache invalidation).
By convention, Nuxt uses the `assets/` directory to store these files but there is no auto-scan functionality for this directory, and you can use any other name for it. By convention, Nuxt uses the [`assets/` directory](/docs/guide/directory-structure/assets) to store these files but there is no auto-scan functionality for this directory, and you can use any other name for it.
In your application's code, you can reference a file located in the `assets/` directory by using the `~/assets/` path. In your application's code, you can reference a file located in the [`assets/` directory](/docs/guide/directory-structure/assets) by using the `~/assets/` path.
### Example ### Example
@ -44,7 +44,7 @@ For example, referencing an image file that will be processed if a build tool is
``` ```
::alert{type=info icon=💡} ::alert{type=info icon=💡}
Nuxt won't serve files in the `assets/` directory at a static URL like `/assets/my-file.png`. If you need a static URL, use the [`public/` directory](#public-directory). Nuxt won't serve files in the [`assets/` directory](/docs/guide/directory-structure/assets) at a static URL like `/assets/my-file.png`. If you need a static URL, use the [`public/` directory](#public-directory).
:: ::
### Global Styles Imports ### Global Styles Imports

View File

@ -9,7 +9,7 @@ You can use CSS preprocessors, CSS frameworks, UI libraries and Nuxt modules to
## Local Stylesheets ## Local Stylesheets
If you're writing local stylesheets, the natural place to put them is the `assets/` directory. If you're writing local stylesheets, the natural place to put them is the [`assets/` directory](/docs/guide/directory-structure/assets).
### Importing Within Components ### Importing Within Components
@ -37,7 +37,7 @@ The stylesheets will be inlined in the HTML rendered by Nuxt.
### The CSS Property ### The CSS Property
You can also use the `css` property in the Nuxt configuration. You can also use the `css` property in the Nuxt configuration.
The natural place for your stylesheets is the `assets/` directory. You can then reference its path and Nuxt will include it to all the pages of your application. The natural place for your stylesheets is the [`assets/` directory](/docs/guide/directory-structure/assets). You can then reference its path and Nuxt will include it to all the pages of your application.
```ts [nuxt.config.ts] ```ts [nuxt.config.ts]
export default defineNuxtConfig({ export default defineNuxtConfig({
@ -105,7 +105,7 @@ export default defineNuxtConfig({
You can include external stylesheets in your application by adding a link element in the head section of your nuxt.config file. You can achieve this result using different methods. Note that local stylesheets can also be included like this. You can include external stylesheets in your application by adding a link element in the head section of your nuxt.config file. You can achieve this result using different methods. Note that local stylesheets can also be included like this.
You can manipulate the head with the `app.head` property of your Nuxt configuration: You can manipulate the head with the [`app.head`](/docs/api/configuration/nuxt-config#head) property of your Nuxt configuration:
```ts [nuxt.config.ts] ```ts [nuxt.config.ts]
export default defineNuxtConfig({ export default defineNuxtConfig({

View File

@ -4,11 +4,11 @@ description: Nuxt file-system routing creates a route for every file in the page
--- ---
# Routing # Routing
One core feature of Nuxt is the file system router. Every Vue file inside the `pages/` directory creates a corresponding URL (or route) that displays the contents of the file. By using dynamic imports for each page, Nuxt leverages code-splitting to ship the minimum amount of JavaScript for the requested route. One core feature of Nuxt is the file system router. Every Vue file inside the [`pages/` directory](/docs/guide/directory-structure/pages) creates a corresponding URL (or route) that displays the contents of the file. By using dynamic imports for each page, Nuxt leverages code-splitting to ship the minimum amount of JavaScript for the requested route.
## Pages ## Pages
Nuxt routing is based on [vue-router](https://router.vuejs.org/) and generates the routes from every component created in the [`pages/`](/docs/guide/directory-structure/pages) directory, based on their filename. Nuxt routing is based on [vue-router](https://router.vuejs.org/) and generates the routes from every component created in the [`pages/` directory](/docs/guide/directory-structure/pages), based on their filename.
This file system routing uses naming conventions to create dynamic and nested routes: This file system routing uses naming conventions to create dynamic and nested routes:
@ -93,8 +93,8 @@ Route middleware runs within the Vue part of your Nuxt app. Despite the similar
There are three kinds of route middleware: There are three kinds of route middleware:
1. Anonymous (or inline) route middleware, which are defined directly in the pages where they are used. 1. Anonymous (or inline) route middleware, which are defined directly in the pages where they are used.
2. Named route middleware, which are placed in the `middleware/` directory and will be automatically loaded via asynchronous import when used on a page. (**Note**: The route middleware name is normalized to kebab-case, so `someMiddleware` becomes `some-middleware`.) 2. Named route middleware, which are placed in the [`middleware/` directory](/docs/guide/directory-structure/middleware) and will be automatically loaded via asynchronous import when used on a page. (**Note**: The route middleware name is normalized to kebab-case, so `someMiddleware` becomes `some-middleware`.)
3. Global route middleware, which are placed in the `middleware/` directory (with a `.global` suffix) and will be automatically run on every route change. 3. Global route middleware, which are placed in the [`middleware/` directory](/docs/guide/directory-structure/middleware) (with a `.global` suffix) and will be automatically run on every route change.
Example of an `auth` middleware protecting the `/dashboard` page: Example of an `auth` middleware protecting the `/dashboard` page:

View File

@ -35,7 +35,7 @@ Shortcuts are available to make configuration easier: `charset` and `viewport`.
## `useHead` ## `useHead`
The `useHead` composable function allows you to manage your head tags in a programmatic and reactive way, The [`useHead`](/docs/api/composables/use-head) composable function allows you to manage your head tags in a programmatic and reactive way,
powered by [Unhead](https://unhead.harlanzw.com/). powered by [Unhead](https://unhead.harlanzw.com/).
As with all composables, it can only be used with a components `setup` and lifecycle hooks. As with all composables, it can only be used with a components `setup` and lifecycle hooks.
@ -59,7 +59,7 @@ We recommend to take a look at the [`useHead`](/docs/api/composables/use-head) a
## `useSeoMeta` and `useServerSeoMeta` ## `useSeoMeta` and `useServerSeoMeta`
The `useSeoMeta` and `useServerSeoMeta` composables let you define your site's SEO meta tags as a flat object with full TypeScript support. The `useSeoMeta` and [`useServerSeoMeta`](/docs/api/composables/use-server-seo-meta) composables let you define your site's SEO meta tags as a flat object with full TypeScript support.
This helps you avoid typos and common mistakes, such as using `name` instead of `property`. This helps you avoid typos and common mistakes, such as using `name` instead of `property`.
@ -108,7 +108,7 @@ const title = ref('Hello World')
## Types ## Types
The below is the non-reactive types used for `useHead`, `app.head` and components. Below are the non-reactive types used for [`useHead`](/docs/api/composables/use-head), [`app.head`](/docs/api/configuration/nuxt-config#head) and components.
```ts ```ts
interface MetaObject { interface MetaObject {
@ -196,7 +196,7 @@ If you want to use a function (for full control), then this cannot be set in you
:: ::
Now, if you set the title to `My Page` with `useHead` on another page of your site, the title would appear as 'My Page - Site Title' in the browser tab. You could also pass `null` to default to the site title. Now, if you set the title to `My Page` with [`useHead`](/docs/api/composables/use-head) on another page of your site, the title would appear as 'My Page - Site Title' in the browser tab. You could also pass `null` to default to the site title.
### Body Tags ### Body Tags
@ -222,7 +222,7 @@ useHead({
### With `definePageMeta` ### With `definePageMeta`
Within your `pages/` directory, you can use `definePageMeta` along with `useHead` to set metadata based on the current route. Within your [`pages/` directory](/docs/guide/directory-structure/pages), you can use `definePageMeta` along with [`useHead`](/docs/api/composables/use-head) to set metadata based on the current route.
For example, you can first set the current page title (this is extracted at build time via a macro, so it can't be set dynamically): For example, you can first set the current page title (this is extracted at build time via a macro, so it can't be set dynamically):
@ -274,7 +274,7 @@ useHead({
### External CSS ### External CSS
The example below shows how you might enable Google Fonts using either the `link` property of the `useHead` composable or using the `<Link>` component: The example below shows how you might enable Google Fonts using either the `link` property of the [`useHead`](/docs/api/composables/use-head) composable or using the `<Link>` component:
::code-group ::code-group

View File

@ -5,15 +5,15 @@ description: Nuxt provides composables to handle data fetching within your appli
# Data fetching # Data fetching
Nuxt comes with two composables and a built-in library to perform data-fetching in browser or server environments: `useFetch`, `useAsyncData` and `$fetch` . Nuxt comes with two composables and a built-in library to perform data-fetching in browser or server environments: `useFetch`, [`useAsyncData`](/docs/api/composables/use-async-data) and `$fetch` .
Used together, they ensure cross-environment compatibility and efficient caching and avoid duplicate network calls. Used together, they ensure cross-environment compatibility and efficient caching and avoid duplicate network calls.
`useFetch` is the most straightforward way to handle data fetching in a component setup function. [`useFetch`](/docs/api/composables/use-fetch) is the most straightforward way to handle data fetching in a component setup function.
On the other hand, when wanting to make a network request based on user interaction, `$fetch` is almost always the right handler to go for. On the other hand, when wanting to make a network request based on user interaction, `$fetch` is almost always the right handler to go for.
If you need more fine-grained control, you can use `useAsyncData` and `$fetch` independently. If you need more fine-grained control, you can use [`useAsyncData`](/docs/api/composables/use-async-data) and `$fetch` independently.
The two composables share a common set of options and patterns that we will detail in the last sections. The two composables share a common set of options and patterns that we will detail in the last sections.
@ -23,7 +23,7 @@ When using a framework like Nuxt that can perform calls and render pages on both
### Network calls duplication ### Network calls duplication
The `useFetch` and `useAsyncData` composables ensure that once an API call is made on the server, the data is properly forwarded to the client in the payload. This JavaScript object is accessible through [`useNuxtApp().payload`](/docs/api/composables/use-nuxt-app#payload) and is used on the client to avoid refetching the same data when the code is executed in the browser. The [`useFetch`](/docs/api/composables/use-fetch) and [`useAsyncData`](/docs/api/composables/use-async-data) composables ensure that once an API call is made on the server, the data is properly forwarded to the client in the payload. This JavaScript object is accessible through [`useNuxtApp().payload`](/docs/api/composables/use-nuxt-app#payload) and is used on the client to avoid refetching the same data when the code is executed in the browser.
::alert{icon=⚙️} ::alert{icon=⚙️}
Use the [Nuxt DevTools](https://devtools.nuxtjs.org) to inspect this data in the payload tab. Use the [Nuxt DevTools](https://devtools.nuxtjs.org) to inspect this data in the payload tab.
@ -31,7 +31,7 @@ Use the [Nuxt DevTools](https://devtools.nuxtjs.org) to inspect this data in the
### Effective caching ### Effective caching
`useFetch` and `useAsyncData` both use a key to cache API responses and further reduce API calls. We will detail later how to invalidate this cache. [`useFetch`](/docs/api/composables/use-fetch) and [`useAsyncData`](/docs/api/composables/use-async-data) both use a key to cache API responses and further reduce API calls. We will detail later how to invalidate this cache.
### Suspense ### Suspense
@ -43,7 +43,7 @@ These composables are auto-imported and can be used in `setup` functions or life
## `useFetch` ## `useFetch`
`useFetch` is the most straightforward way to perform data fetching. It is a wrapper around the `useAsyncData` composable and `$fetch` utility. [`useFetch`](/docs/api/composables/use-fetch) is the most straightforward way to perform data fetching. It is a wrapper around the [`useAsyncData`](/docs/api/composables/use-async-data) composable and `$fetch` utility.
```vue [app.vue] ```vue [app.vue]
<script setup> <script setup>
@ -75,7 +75,7 @@ The `ofetch` library is built on top of the `fetch` API and adds handy features
[Read the full documentation of ofetch](https://github.com/unjs/ofetch) [Read the full documentation of ofetch](https://github.com/unjs/ofetch)
:: ::
ofetch is auto-imported by Nuxt and used by the `useFetch` composable. ofetch is auto-imported by Nuxt and used by the [`useFetch`](/docs/api/composables/use-fetch) composable.
It can also be used in your whole application with the `$fetch` alias: It can also be used in your whole application with the `$fetch` alias:
@ -92,16 +92,16 @@ Beware that using only `$fetch` will not provide the benefits described in [the
## `useAsyncData` ## `useAsyncData`
`useFetch` receives a URL and gets that data, whereas `useAsyncData` might have more complex logic. `useFetch(url)` is nearly equivalent to `useAsyncData(url, () => $fetch(url))` - it's developer experience sugar for the most common use case. [`useFetch`](/docs/api/composables/use-fetch) receives a URL and gets that data, whereas [`useAsyncData`](/docs/api/composables/use-async-data) might have more complex logic. `useFetch(url)` is nearly equivalent to `useAsyncData(url, () => $fetch(url))` - it's developer experience sugar for the most common use case.
There are some cases when using the `useFetch` composable is not appropriate, for example when a CMS or a third-party provide their own query layer. In this case, you can use `useAsyncData` to wrap your calls and still keep the benefits provided by the composable: There are some cases when using the [`useFetch`](/docs/api/composables/use-fetch) composable is not appropriate, for example when a CMS or a third-party provide their own query layer. In this case, you can use [`useAsyncData`](/docs/api/composables/use-async-data) to wrap your calls and still keep the benefits provided by the composable:
```ts ```ts
const { data, error } = await useAsyncData('users', () => myGetFunction('users')) const { data, error } = await useAsyncData('users', () => myGetFunction('users'))
``` ```
::alert{icon=👉} ::alert{icon=👉}
The first argument of `useAsyncData` is the unique key used to cache the response of the second argument, the querying function. This argument can be ignored by directly passing the querying function. In that case, it will be auto-generated. The first argument of [`useAsyncData`](/docs/api/composables/use-async-data) is the unique key used to cache the response of the second argument, the querying function. This argument can be ignored by directly passing the querying function. In that case, it will be auto-generated.
:: ::
::ReadMore{link="/docs/api/composables/use-async-data"} ::ReadMore{link="/docs/api/composables/use-async-data"}
@ -109,7 +109,7 @@ The first argument of `useAsyncData` is the unique key used to cache the respons
## Options ## Options
`useAsyncData` and `useFetch` return the same object type and accept a common set of options as their last argument. They can help you control the composables behavior, such as navigation blocking, caching or execution. [`useAsyncData`](/docs/api/composables/use-async-data) and [`useFetch`](/docs/api/composables/use-fetch) return the same object type and accept a common set of options as their last argument. They can help you control the composables behavior, such as navigation blocking, caching or execution.
### Lazy ### Lazy
@ -134,7 +134,7 @@ const { pending, data: posts } = useFetch('/api/posts', {
</script> </script>
``` ```
You can alternatively use `useLazyFetch` and `useLazyAsyncData` as convenient methods to perform the same. You can alternatively use [`useLazyFetch`](/docs/api/composables/use-lazy-fetch) and `useLazyAsyncData` as convenient methods to perform the same.
```ts ```ts
const { pending, data: posts } = useLazyFetch('/api/posts') const { pending, data: posts } = useLazyFetch('/api/posts')
@ -188,10 +188,10 @@ const { data: mountains } = await useFetch('/api/mountains', {
#### Keys #### Keys
`useFetch` and `useAsyncData` use keys to prevent refetching the same data. [`useFetch`](/docs/api/composables/use-fetch) and [`useAsyncData`](/docs/api/composables/use-async-data) use keys to prevent refetching the same data.
- `useFetch` uses the provided URL as a key. Alternatively, a `key` value can be provided in the `options` object passed as a last argument. - [`useFetch`](/docs/api/composables/use-fetch) uses the provided URL as a key. Alternatively, a `key` value can be provided in the `options` object passed as a last argument.
- `useAsyncData` uses its first argument as a key if it is a string. If the first argument is the handler function that performs the query, then a key that is unique to the file name and line number of the instance of `useAsyncData` will be generated for you. - [`useAsyncData`](/docs/api/composables/use-async-data) uses its first argument as a key if it is a string. If the first argument is the handler function that performs the query, then a key that is unique to the file name and line number of the instance of `useAsyncData` will be generated for you.
::alert{icon=📘} ::alert{icon=📘}
To get the cached data by key, you can use [`useNuxtData`](/docs/api/composables/use-nuxt-data) To get the cached data by key, you can use [`useNuxtData`](/docs/api/composables/use-nuxt-data)
@ -310,7 +310,7 @@ Using `<script setup lang="ts">` is the recommended way of declaring Vue compone
## Serialization ## Serialization
When fetching data from the `server` directory, the response is serialized using `JSON.stringify`. However, since serialization is limited to only JavaScript primitive types, Nuxt does its best to convert the return type of `$fetch` and `useFetch` to match the actual value. When fetching data from the `server` directory, the response is serialized using `JSON.stringify`. However, since serialization is limited to only JavaScript primitive types, Nuxt does its best to convert the return type of `$fetch` and [`useFetch`](/docs/api/composables/use-fetch) to match the actual value.
::alert{icon=👉} ::alert{icon=👉}
You can learn more about `JSON.stringify` limitations [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description). You can learn more about `JSON.stringify` limitations [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description).

View File

@ -5,18 +5,18 @@ description: Nuxt provides powerful state management libraries and the useState
# State Management # State Management
Nuxt provides the `useState` composable to create a reactive and SSR-friendly shared state across components. Nuxt provides the [`useState`](/docs/api/composables/use-state) composable to create a reactive and SSR-friendly shared state across components.
`useState` is an SSR-friendly [`ref`](https://vuejs.org/api/reactivity-core.html#ref) replacement. Its value will be preserved after server-side rendering (during client-side hydration) and shared across all components using a unique key. [`useState`](/docs/api/composables/use-state) is an SSR-friendly [`ref`](https://vuejs.org/api/reactivity-core.html#ref) replacement. Its value will be preserved after server-side rendering (during client-side hydration) and shared across all components using a unique key.
::ReadMore{link="/docs/api/composables/use-state"} ::ReadMore{link="/docs/api/composables/use-state"}
:: ::
::alert{icon=👉} ::alert{icon=👉}
`useState` only works during `setup` or [`Lifecycle Hooks`](https://vuejs.org/api/composition-api-lifecycle.html#composition-api-lifecycle-hooks). [`useState`](/docs/api/composables/use-state) only works during `setup` or [`Lifecycle Hooks`](https://vuejs.org/api/composition-api-lifecycle.html#composition-api-lifecycle-hooks).
:: ::
::alert{type=warning} ::alert{type=warning}
Because the data inside `useState` will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols. Because the data inside [`useState`](/docs/api/composables/use-state) will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols.
:: ::
## Best Practices ## Best Practices

View File

@ -11,14 +11,14 @@ Some use cases:
::list{type="success"} ::list{type="success"}
- Share reusable configuration presets across projects using `nuxt.config` and `app.config` - Share reusable configuration presets across projects using `nuxt.config` and `app.config`
- Create a component library using `components/` directory - Create a component library using [`components/` directory](/docs/guide/directory-structure/components)
- Create utility and composable library using `composables/` and `utils/` directories - Create utility and composable library using [`composables/` directory](/docs/guide/directory-structure/composables) and [`utils/` directory](/docs/guide/directory-structure/utils)
- Create [Nuxt themes](https://github.com/nuxt-themes) - Create [Nuxt themes](https://github.com/nuxt-themes)
- Create Nuxt module presets - Create Nuxt module presets
- Share standard setup across projects - Share standard setup across projects
:: ::
You can extend a layer by adding the [extends](/docs/api/configuration/nuxt-config#extends) property to the `nuxt.config.ts` file. You can extend a layer by adding the [extends](/docs/api/configuration/nuxt-config#extends) property to the [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) file.
```ts [nuxt.config.ts] ```ts [nuxt.config.ts]
export default defineNuxtConfig({ export default defineNuxtConfig({

View File

@ -2,7 +2,9 @@
description: "Nuxt auto-imports helper functions, composables and Vue APIs." description: "Nuxt auto-imports helper functions, composables and Vue APIs."
--- ---
# Auto imports # Auto-imports
## Composables and Helper Functions
Nuxt auto-imports helper functions, composables and Vue APIs to use across your application without explicitly importing them. Based on the directory structure, every Nuxt application can also use auto-imports for its own components, composables and plugins. Components, composables or plugins can use these functions. Nuxt auto-imports helper functions, composables and Vue APIs to use across your application without explicitly importing them. Based on the directory structure, every Nuxt application can also use auto-imports for its own components, composables and plugins. Components, composables or plugins can use these functions.
@ -21,9 +23,9 @@ In the [server directory](/docs/guide/directory-structure/server), we auto impor
You can also auto-import functions exported from custom folders or third-party packages by configuring the [`imports` section](/docs/api/configuration/nuxt-config#imports) of your `nuxt.config` file. You can also auto-import functions exported from custom folders or third-party packages by configuring the [`imports` section](/docs/api/configuration/nuxt-config#imports) of your `nuxt.config` file.
:: ::
## Built-in Auto-imports ### Built-in Auto-imports
### Nuxt Auto-imports #### Nuxt Auto-imports
Nuxt auto-imports functions and composables to perform [data fetching](/docs/getting-started/data-fetching), get access to the [app context](/docs/api/composables/use-nuxt-app) and [runtime config](/docs/guide/going-further/runtime-config), manage [state](/docs/getting-started/state-management) or define components and plugins. Nuxt auto-imports functions and composables to perform [data fetching](/docs/getting-started/data-fetching), get access to the [app context](/docs/api/composables/use-nuxt-app) and [runtime config](/docs/guide/going-further/runtime-config), manage [state](/docs/getting-started/state-management) or define components and plugins.
@ -34,7 +36,7 @@ Nuxt auto-imports functions and composables to perform [data fetching](/docs/get
</script> </script>
``` ```
### Vue Auto-imports #### Vue Auto-imports
Vue 3 exposes Reactivity APIs like `ref` or `computed`, as well as lifecycle hooks and helpers that are auto-imported by Nuxt. Vue 3 exposes Reactivity APIs like `ref` or `computed`, as well as lifecycle hooks and helpers that are auto-imported by Nuxt.
@ -46,7 +48,7 @@ Vue 3 exposes Reactivity APIs like `ref` or `computed`, as well as lifecycle hoo
</script> </script>
``` ```
### Using Vue and Nuxt composables #### Using Vue and Nuxt composables
<!-- TODO: move to separate page with https://github.com/nuxt/nuxt/issues/14723 and add more information --> <!-- TODO: move to separate page with https://github.com/nuxt/nuxt/issues/14723 and add more information -->
@ -63,7 +65,7 @@ See the full explanation in this [comment](https://github.com/nuxt/nuxt/issues/1
::NeedContribution ::NeedContribution
:: ::
#### Example ##### Example
**Example:** Breaking code: **Example:** Breaking code:
@ -88,7 +90,7 @@ export const useMyComposable = () => {
} }
``` ```
## Directory-based Auto-imports ### Directory-based Auto-imports
Nuxt directly auto-imports files created in defined directories: Nuxt directly auto-imports files created in defined directories:
@ -96,7 +98,7 @@ Nuxt directly auto-imports files created in defined directories:
- `composables/` for [Vue composables](/docs/guide/directory-structure/composables). - `composables/` for [Vue composables](/docs/guide/directory-structure/composables).
- `utils/` for helper functions and other utilities. - `utils/` for helper functions and other utilities.
## Explicit Imports ### Explicit Imports
Nuxt exposes every auto-import with the `#imports` alias that can be used to make the import explicit if needed: Nuxt exposes every auto-import with the `#imports` alias that can be used to make the import explicit if needed:
@ -109,9 +111,9 @@ Nuxt exposes every auto-import with the `#imports` alias that can be used to mak
</script> </script>
``` ```
## Disable Auto-imports ### Disabling Auto-imports
In case you want to disable auto-imports, you can set `imports.autoImport` to `false` in your `nuxt.config.ts`. If you want to disable auto-importing composables and utilities, you can set `imports.autoImport` to `false` in the `nuxt.config` file.
```ts [nuxt.config.ts] ```ts [nuxt.config.ts]
export default defineNuxtConfig({ export default defineNuxtConfig({
@ -121,4 +123,20 @@ export default defineNuxtConfig({
}) })
``` ```
This will disable implicit auto imports completely but it's still possible to use [Explicit Imports](#explicit-imports). This will disable auto-imports completely but it's still possible to use [explicit imports](#explicit-imports) from `#imports`.
## Auto-imported Components
Nuxt also automatically imports components from your `~/components` directory, although this is configured separately from auto-importing composables and utility functions.
:ReadMore{link="/docs/guide/directory-structure/components"}
To disable auto-importing components from your own `~/components` directory, you can set `components.dirs` to an empty array (though note that this will not affect components added by modules).
```ts [nuxt.config.ts]
export default defineNuxtConfig({
components: {
dirs: []
}
})
```

View File

@ -36,7 +36,7 @@ Most applications need multiple pages and a way to navigate between them. This i
The `app.vue` file is the entry point, which represents the page displayed in the browser window. The `app.vue` file is the entry point, which represents the page displayed in the browser window.
Inside the `<template>` of the component, we use the `<Welcome>` component created in the `components/` directory without having to import it. Inside the `<template>` of the component, we use the `<Welcome>` component created in the [`components/` directory](/docs/guide/directory-structure/components) without having to import it.
Try to replace the `<template>`s content with a custom welcome message. The browser window on the right will automatically render the changes without reloading. Try to replace the `<template>`s content with a custom welcome message. The browser window on the right will automatically render the changes without reloading.
@ -103,7 +103,7 @@ Used with the `setup` keyword in the `<script>` definition, here is the above co
The goal of Nuxt 3 is to provide a great developer experience around the Composition API. The goal of Nuxt 3 is to provide a great developer experience around the Composition API.
- Use auto-imported [Reactivity functions](https://vuejs.org/api/reactivity-core.html) from Vue and Nuxt 3 [built-in composables](/docs/api/composables/use-async-data). - Use auto-imported [Reactivity functions](https://vuejs.org/api/reactivity-core.html) from Vue and Nuxt 3 [built-in composables](/docs/api/composables/use-async-data).
- Write your own auto-imported reusable functions in the `composables/` directory. - Write your own auto-imported reusable functions in the [`composables/` directory](/docs/guide/directory-structure/composables).
### TypeScript Support ### TypeScript Support

View File

@ -24,7 +24,7 @@ Key features include:
Check out [the h3 docs](https://github.com/unjs/h3) for more information. Check out [the h3 docs](https://github.com/unjs/h3) for more information.
::alert{type="info" icon=} ::alert{type="info" icon=}
Learn more about the API layer in the [`server/`](/docs/guide/directory-structure/server) directory. Learn more about the API layer in the [`server/` directory](/docs/guide/directory-structure/server).
:: ::
## Direct API Calls ## Direct API Calls

View File

@ -19,7 +19,7 @@ Best of all, Nuxt modules can be distributed in npm packages. This makes it poss
## The `modules` Property ## The `modules` Property
Once you have installed the modules you can then add them to your `nuxt.config.ts` file under the `modules` property. Module developers usually provide additional steps and details for usage. Once you have installed the modules you can then add them to your [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) file under the `modules` property. Module developers usually provide additional steps and details for usage.
```ts{}[nuxt.config.ts] ```ts{}[nuxt.config.ts]
export default defineNuxtConfig({ export default defineNuxtConfig({

View File

@ -7,7 +7,7 @@ head.title: ".nuxt/"
# .nuxt Directory # .nuxt Directory
Nuxt uses the `.nuxt/` directory in development to generate your Vue application. Nuxt uses the [`.nuxt/` directory](/docs/guide/directory-structure/nuxt) in development to generate your Vue application.
::alert{type=warning} ::alert{type=warning}
You should not touch any files inside since the whole directory will be re-created when running `nuxt dev`. You should not touch any files inside since the whole directory will be re-created when running `nuxt dev`.

View File

@ -7,7 +7,7 @@ head.title: ".output/"
# Output Directory # Output Directory
Nuxt creates the `.output/` directory when building your application for production. Nuxt creates the [`.output/` directory](/docs/guide/directory-structure/output) when building your application for production.
::alert{type=warning} ::alert{type=warning}
You should not touch any files inside since the whole directory will be re-created when running `nuxt build`. You should not touch any files inside since the whole directory will be re-created when running `nuxt build`.

View File

@ -7,7 +7,7 @@ head.title: "assets/"
# Assets Directory # Assets Directory
The `assets/` directory is used to add all the website's assets that the build tool (webpack or Vite) will process. The [`assets/` directory](/docs/guide/directory-structure/assets) is used to add all the website's assets that the build tool (webpack or Vite) will process.
The directory usually contains the following types of files: The directory usually contains the following types of files:

View File

@ -7,9 +7,9 @@ head.title: "components/"
# Components Directory # Components Directory
The `components/` directory is where you put all your Vue components which can then be imported inside your pages or other components ([learn more](https://vuejs.org/guide/essentials/component-basics.html#components-basics)). The [`components/` directory](/docs/guide/directory-structure/components) is where you put all your Vue components which can then be imported inside your pages or other components ([learn more](https://vuejs.org/guide/essentials/component-basics.html#components-basics)).
Nuxt automatically imports any components in your `components/` directory (along with components that are registered by any modules you may be using). Nuxt automatically imports any components in your [`components/` directory](/docs/guide/directory-structure/components) (along with components that are registered by any modules you may be using).
```bash ```bash
| components/ | components/

View File

@ -7,7 +7,7 @@ description: Use the composables/ directory to auto-import your Vue composables
# Composables Directory # Composables Directory
Nuxt 3 uses the `composables/` directory to automatically import your Vue composables into your application using [auto-imports](/docs/guide/concepts/auto-imports)! Nuxt 3 uses the [`composables/` directory](/docs/guide/directory-structure/composables) to automatically import your Vue composables into your application using [auto-imports](/docs/guide/concepts/auto-imports)!
Under the hood, Nuxt auto generates the file `.nuxt/imports.d.ts` to declare the types. Under the hood, Nuxt auto generates the file `.nuxt/imports.d.ts` to declare the types.
@ -75,7 +75,7 @@ export const useHello = () => {
## How Files Are Scanned ## How Files Are Scanned
Nuxt only scans files at the top level of the `composables/` directory, e.g.: Nuxt only scans files at the top level of the [`composables/` directory](/docs/guide/directory-structure/composables), e.g.:
```bash ```bash
composables composables

View File

@ -7,7 +7,7 @@ description: The Content module reads the content/ directory to create a file-ba
# Content Directory # Content Directory
The [Nuxt Content module](https://content.nuxtjs.org) reads the `content/` directory in your project and parses `.md`, `.yml`, `.csv` and `.json` files to create a file-based CMS for your application. The [Nuxt Content module](https://content.nuxtjs.org) reads the [`content/` directory](/docs/guide/directory-structure/content) in your project and parses `.md`, `.yml`, `.csv` and `.json` files to create a file-based CMS for your application.
::list{type=success} ::list{type=success}
@ -55,7 +55,7 @@ export default defineNuxtConfig({
### Create Content ### Create Content
Place your markdown files inside the `content/` directory in the root directory of your project: Place your markdown files inside the [`content/` directory](/docs/guide/directory-structure/content) in the root directory of your project:
```md [content/index.md] ```md [content/index.md]
# Hello Content # Hello Content

View File

@ -9,7 +9,7 @@ head.title: "layouts/"
Nuxt provides a customizable layouts framework you can use throughout your application, ideal for extracting common UI or code patterns into reusable layout components. Nuxt provides a customizable layouts framework you can use throughout your application, ideal for extracting common UI or code patterns into reusable layout components.
Layouts are placed in the `layouts/` directory and will be automatically loaded via asynchronous import when used. Layouts are used by adding `<NuxtLayout>` to your `app.vue`, and either setting a `layout` property as part of your page metadata (if you are using the `~/pages` integration), or by manually specifying it as a prop to `<NuxtLayout>`. (**Note**: The layout name is normalized to kebab-case, so `someLayout` becomes `some-layout`.) Layouts are placed in the [`layouts/` directory](/docs/guide/directory-structure/layouts) and will be automatically loaded via asynchronous import when used. Layouts are used by adding `<NuxtLayout>` to your `app.vue`, and either setting a `layout` property as part of your page metadata (if you are using the `~/pages` integration), or by manually specifying it as a prop to `<NuxtLayout>`. (**Note**: The layout name is normalized to kebab-case, so `someLayout` becomes `some-layout`.)
If you only have a single layout in your application, we recommend using [app.vue](/docs/guide/directory-structure/app) instead. If you only have a single layout in your application, we recommend using [app.vue](/docs/guide/directory-structure/app) instead.

View File

@ -16,8 +16,8 @@ Route middleware run within the Vue part of your Nuxt app. Despite the similar n
There are three kinds of route middleware: There are three kinds of route middleware:
1. Anonymous (or inline) route middleware, which are defined directly in the pages where they are used. 1. Anonymous (or inline) route middleware, which are defined directly in the pages where they are used.
2. Named route middleware, which are placed in the `middleware/` directory and will be automatically loaded via asynchronous import when used on a page. (**Note**: The route middleware name is normalized to kebab-case, so `someMiddleware` becomes `some-middleware`.) 2. Named route middleware, which are placed in the [`middleware/` directory](/docs/guide/directory-structure/middleware) and will be automatically loaded via asynchronous import when used on a page. (**Note**: The route middleware name is normalized to kebab-case, so `someMiddleware` becomes `some-middleware`.)
3. Global route middleware, which are placed in the `middleware/` directory (with a `.global` suffix) and will be automatically run on every route change. 3. Global route middleware, which are placed in the [`middleware/` directory](/docs/guide/directory-structure/middleware) (with a `.global` suffix) and will be automatically run on every route change.
The first two kinds of route middleware can be [defined in `definePageMeta`](/docs/guide/directory-structure/pages). The first two kinds of route middleware can be [defined in `definePageMeta`](/docs/guide/directory-structure/pages).

View File

@ -7,7 +7,7 @@ description: Use the modules/ directory to automatically register local modules
# Modules Directory # Modules Directory
Nuxt scans the `modules/` directory and loads them before starting. It is a good place to place any local modules you develop while building your application. Nuxt scans the [`modules/` directory](/docs/guide/directory-structure/modules) and loads them before starting. It is a good place to place any local modules you develop while building your application.
The auto-registered files patterns are: The auto-registered files patterns are:
- `modules/*/index.ts` - `modules/*/index.ts`

View File

@ -7,4 +7,4 @@ head.title: "node_modules/"
# Node modules Directory # Node modules Directory
The package manager ([`npm`](https://docs.npmjs.com/cli/v7/commands/npm) or [`yarn`](https://yarnpkg.com/) or [`pnpm`](https://pnpm.io/cli/install)) creates the `node_modules/` directory to store the dependencies of your project. The package manager ([`npm`](https://docs.npmjs.com/cli/v7/commands/npm) or [`yarn`](https://yarnpkg.com/) or [`pnpm`](https://pnpm.io/cli/install)) creates the [`node_modules/` directory](/docs/guide/directory-structure/node_modules) to store the dependencies of your project.

View File

@ -122,7 +122,7 @@ Navigating to `/users-admins/123` would render:
<p>admins - 123</p> <p>admins - 123</p>
``` ```
If you want to access the route using Composition API, there is a global `useRoute` function that will allow you to access the route just like `this.$route` in the Options API. If you want to access the route using Composition API, there is a global [`useRoute`](/docs/api/composables/use-route) function that will allow you to access the route just like `this.$route` in the Options API.
```vue ```vue
<script setup> <script setup>

View File

@ -10,12 +10,12 @@ head.title: "plugins/"
Nuxt automatically reads the files in your `plugins` directory and loads them at the creation of the Vue application. You can use `.server` or `.client` suffix in the file name to load a plugin only on the server or client side. Nuxt automatically reads the files in your `plugins` directory and loads them at the creation of the Vue application. You can use `.server` or `.client` suffix in the file name to load a plugin only on the server or client side.
::alert{type=warning} ::alert{type=warning}
All plugins in your `plugins/` directory are auto-registered, so you should not add them to your `nuxt.config` separately. All plugins in your [`plugins/` directory](/docs/guide/directory-structure/plugins) are auto-registered, so you should not add them to your `nuxt.config` separately.
:: ::
## Which Files Are Registered ## Which Files Are Registered
Only files at the top level of the `plugins/` directory (or index files within any subdirectories) will be registered as plugins. Only files at the top level of the [`plugins/` directory](/docs/guide/directory-structure/plugins) (or index files within any subdirectories) will be registered as plugins.
For example: For example:

View File

@ -7,8 +7,8 @@ head.title: "public/"
# Public Directory # Public Directory
The `public/` directory is directly served at the server root and contains public files that have to keep their names (e.g. `robots.txt`) _or_ likely won't change (e.g. `favicon.ico`). The [`public/` directory](/docs/guide/directory-structure/public) is directly served at the server root and contains public files that have to keep their names (e.g. `robots.txt`) _or_ likely won't change (e.g. `favicon.ico`).
::alert{icon=💡} ::alert{icon=💡}
This is known as the [`static/`](https://nuxtjs.org/docs/directory-structure/static) directory in Nuxt 2. This is known as the [`static/` directory](https://nuxtjs.org/docs/directory-structure/static) in Nuxt 2.
:: ::

View File

@ -7,10 +7,10 @@ description: Use the utils/ directory to auto-import your utility functions thro
# Utils Directory # Utils Directory
Nuxt 3 uses the `utils/` directory to automatically import helper functions and other utilities throughout your application using [auto-imports](/docs/guide/concepts/auto-imports)! Nuxt 3 uses the [`utils/` directory](/docs/guide/directory-structure/utils) to automatically import helper functions and other utilities throughout your application using [auto-imports](/docs/guide/concepts/auto-imports)!
::alert{type=info} ::alert{type=info}
The main purpose of the `utils/` directory is to allow a semantic distinction between your Vue composables and other auto-imported utility functions. The main purpose of the [`utils/` directory](/docs/guide/directory-structure/utils) is to allow a semantic distinction between your Vue composables and other auto-imported utility functions.
The way `utils/` auto-imports work and are scanned is identical to [the composables/ directory](/docs/guide/directory-structure/composables). You can see examples and more information about how they work in that section of the docs. The way `utils/` auto-imports work and are scanned is identical to [the composables/ directory](/docs/guide/directory-structure/composables). You can see examples and more information about how they work in that section of the docs.
:: ::

View File

@ -69,7 +69,7 @@ Allows Nuxt app state to be restored from `sessionStorage` when reloading the pa
::alert{type=warning icon=⚠️} ::alert{type=warning icon=⚠️}
Consider carefully before enabling this as it can cause unexpected behavior, Consider carefully before enabling this as it can cause unexpected behavior,
and consider providing explicit keys to `useState` as auto-generated keys may not match across builds. and consider providing explicit keys to [`useState`](/docs/api/composables/use-state) as auto-generated keys may not match across builds.
:: ::
```ts [nuxt.config.ts] ```ts [nuxt.config.ts]

View File

@ -6,7 +6,7 @@ description: Nuxt provides a powerful system that allows you to extend the defau
Nuxt layers are a powerful feature that you can use to share and reuse partial Nuxt applications within a monorepo, or from a git repository or npm package. The layers structure is almost identical to a standard Nuxt application, which makes them easy to author and maintain. ([Read More](/docs/getting-started/layers)) Nuxt layers are a powerful feature that you can use to share and reuse partial Nuxt applications within a monorepo, or from a git repository or npm package. The layers structure is almost identical to a standard Nuxt application, which makes them easy to author and maintain. ([Read More](/docs/getting-started/layers))
A minimal Nuxt layer directory should contain a `nuxt.config.ts` file to indicate it is a layer. A minimal Nuxt layer directory should contain a [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) file to indicate it is a layer.
```ts{}[base/nuxt.config.ts] ```ts{}[base/nuxt.config.ts]
export default defineNuxtConfig({}) export default defineNuxtConfig({})
@ -18,7 +18,7 @@ Additionally, certain other files in the layer directory will be auto-scanned an
- `composables/*` - Extend the default composables - `composables/*` - Extend the default composables
- `pages/*` - Extend the default pages - `pages/*` - Extend the default pages
- `server/*` - Extend the default server endpoints & middleware - `server/*` - Extend the default server endpoints & middleware
- `nuxt.config.ts` - Extend the default nuxt config - [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config)- Extend the default nuxt config
- `app.config.ts` - Extend the default app config - `app.config.ts` - Extend the default app config
## Basic Example ## Basic Example
@ -62,7 +62,7 @@ Additionally, certain other files in the layer directory will be auto-scanned an
:: ::
::alert{type="info"} ::alert{type="info"}
If you're interested in deepening your understanding about layers, consider examining [a fully fleshed out `nuxt.config.ts` file on the Docus platform](https://github.com/nuxt-themes/docus/blob/main/nuxt.config.ts). If you're interested in deepening your understanding about layers, consider examining [a fully fleshed out [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) file on the Docus platform](https://github.com/nuxt-themes/docus/blob/main/nuxt.config.ts).
:: ::
## Starter Template ## Starter Template

View File

@ -60,6 +60,32 @@ You may need to update the config below with a path to your web browser. For mor
} }
``` ```
### Example JetBrains IDEs Debug Configuration
You can also debug your Nuxt app in JetBrains IDEs such as IntelliJ IDEA, WebStorm, or PhpStorm.
1. Create a new file in your project root directory and name it `nuxt.run.xml`.
2. Open the `nuxt.run.xml` file and paste the following debug configuration:
```xml
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="client: chrome" type="JavascriptDebugType" uri="http://localhost:3000" useFirstLineBreakpoints="true">
<method v="2" />
</configuration>
<configuration default="false" name="server: nuxt" type="NodeJSConfigurationType" application-parameters="dev" path-to-js-file="$PROJECT_DIR$/node_modules/nuxi/bin/nuxi.mjs" working-dir="$PROJECT_DIR$">
<method v="2" />
</configuration>
<configuration default="false" name="fullstack: nuxt" type="CompoundRunConfigurationType">
<toRun name="client: chrome" type="JavascriptDebugType" />
<toRun name="server: nuxt" type="NodeJSConfigurationType" />
<method v="2" />
</configuration>
</component>
```
### Other IDEs ### Other IDEs
If you have another IDE and would like to contribute sample configuration, feel free to [open a PR](https://github.com/nuxt/nuxt/edit/main/docs/2.guide/3.going-further/9.debugging.md)! If you have another IDE and would like to contribute sample configuration, feel free to [open a PR](https://github.com/nuxt/nuxt/edit/main/docs/2.guide/3.going-further/9.debugging.md)!

View File

@ -1,12 +1,12 @@
--- ---
description: useAsyncData provides access to data that resolves asynchronously. description: useAsyncData provides access to data that resolves asynchronously.
--- ---
# `useAsyncData` # useAsyncData
Within your pages, components, and plugins you can use useAsyncData to get access to data that resolves asynchronously. Within your pages, components, and plugins you can use useAsyncData to get access to data that resolves asynchronously.
::alert{type=warning} ::alert{type=warning}
`useAsyncData` is a composable meant to be called directly in a setup function, plugin, or route middleware. It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client without re-fetching the data on client side when the page hydrates. [`useAsyncData`](/docs/api/composables/use-async-data) is a composable meant to be called directly in a setup function, plugin, or route middleware. It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client without re-fetching the data on client side when the page hydrates.
:: ::
## Type ## Type
@ -50,7 +50,7 @@ type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
## Params ## Params
* **key**: a unique key to ensure that data fetching can be properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file name and line number of the instance of `useAsyncData` will be generated for you. * **key**: a unique key to ensure that data fetching can be properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file name and line number of the instance of [`useAsyncData`](/docs/api/composables/use-async-data) will be generated for you.
* **handler**: an asynchronous function that returns a value * **handler**: an asynchronous function that returns a value
* **options**: * **options**:
* _lazy_: whether to resolve the async function after loading the route, instead of blocking client-side navigation (defaults to `false`) * _lazy_: whether to resolve the async function after loading the route, instead of blocking client-side navigation (defaults to `false`)
@ -74,7 +74,7 @@ Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the rout
By default, Nuxt waits until a `refresh` is finished before it can be executed again. By default, Nuxt waits until a `refresh` is finished before it can be executed again.
::alert{type=warning} ::alert{type=warning}
If you have not fetched data on the server (for example, with `server: false`), then the data _will not_ be fetched until hydration completes. This means even if you await `useAsyncData` on the client side, `data` will remain `null` within `<script setup>`. If you have not fetched data on the server (for example, with `server: false`), then the data _will not_ be fetched until hydration completes. This means even if you await [`useAsyncData`](/docs/api/composables/use-async-data) on the client side, `data` will remain `null` within `<script setup>`.
:: ::
## Example ## Example
@ -105,7 +105,7 @@ const { data: posts } = await useAsyncData(
``` ```
::alert{type=warning} ::alert{type=warning}
`useAsyncData` is a reserved function name transformed by the compiler, so you should not name your own function `useAsyncData`. [`useAsyncData`](/docs/api/composables/use-async-data) is a reserved function name transformed by the compiler, so you should not name your own function [`useAsyncData`](/docs/api/composables/use-async-data) .
:: ::
::ReadMore{link="/docs/getting-started/data-fetching"} ::ReadMore{link="/docs/getting-started/data-fetching"}

View File

@ -38,7 +38,7 @@ counter.value = counter.value || Math.round(Math.random() * 1000)
</script> </script>
``` ```
:button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/nuxt/tree/main/examples/composables/use-cookie?terminal=dev&file=app.vue" blank} :button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/examples/tree/main/advanced/use-cookie?terminal=dev&file=app.vue" blank}
## Options ## Options

View File

@ -4,7 +4,7 @@ This composable provides a convenient wrapper around [`useAsyncData`](/docs/api/
It automatically generates a key based on URL and fetch options, provides type hints for request url based on server routes, and infers API response type. It automatically generates a key based on URL and fetch options, provides type hints for request url based on server routes, and infers API response type.
::alert{type=warning} ::alert{type=warning}
`useFetch` is a composable meant to be called directly in a setup function, plugin, or route middleware. It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client without re-fetching the data on client side when the page hydrates. [`useFetch`](/docs/api/composables/use-fetch) is a composable meant to be called directly in a setup function, plugin, or route middleware. It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client without re-fetching the data on client side when the page hydrates.
:: ::
## Type ## Type
@ -60,8 +60,8 @@ interface AsyncDataExecuteOptions {
All fetch options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated. All fetch options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated.
:: ::
* **Options (from `useAsyncData`)**: * **Options (from [`useAsyncData`](/docs/api/composables/use-async-data) )**:
* `key`: a unique key to ensure that data fetching can be properly de-duplicated across requests, if not provided, it will be generated based on the static code location where `useAsyncData` is used. * `key`: a unique key to ensure that data fetching can be properly de-duplicated across requests, if not provided, it will be generated based on the static code location where [`useAsyncData`](/docs/api/composables/use-async-data) is used.
* `server`: Whether to fetch the data on the server (defaults to `true`). * `server`: Whether to fetch the data on the server (defaults to `true`).
* `default`: A factory function to set the default value of the data, before the async function resolves - particularly useful with the `lazy: true` option. * `default`: A factory function to set the default value of the data, before the async function resolves - particularly useful with the `lazy: true` option.
* `pick`: Only pick specified keys in this array from the `handler` function result. * `pick`: Only pick specified keys in this array from the `handler` function result.
@ -70,7 +70,7 @@ All fetch options can be given a `computed` or `ref` value. These will be watche
* `immediate`: When set to `false`, will prevent the request from firing immediately. (defaults to `true`) * `immediate`: When set to `false`, will prevent the request from firing immediately. (defaults to `true`)
::alert{type=warning} ::alert{type=warning}
If you provide a function or ref as the `url` parameter, or if you provide functions as arguments to the `options` parameter, then the `useFetch` call will not match other `useFetch` calls elsewhere in your codebase, even if the options seem to be identical. If you wish to force a match, you may provide your own key in `options`. If you provide a function or ref as the `url` parameter, or if you provide functions as arguments to the `options` parameter, then the [`useFetch`](/docs/api/composables/use-fetch) call will not match other [`useFetch`](/docs/api/composables/use-fetch) calls elsewhere in your codebase, even if the options seem to be identical. If you wish to force a match, you may provide your own key in `options`.
:: ::
## Return Values ## Return Values
@ -84,7 +84,7 @@ If you provide a function or ref as the `url` parameter, or if you provide funct
By default, Nuxt waits until a `refresh` is finished before it can be executed again. By default, Nuxt waits until a `refresh` is finished before it can be executed again.
::alert{type=warning} ::alert{type=warning}
If you have not fetched data on the server (for example, with `server: false`), then the data _will not_ be fetched until hydration completes. This means even if you await `useFetch` on client-side, `data` will remain null within `<script setup>`. If you have not fetched data on the server (for example, with `server: false`), then the data _will not_ be fetched until hydration completes. This means even if you await [`useFetch`](/docs/api/composables/use-fetch) on client-side, `data` will remain null within `<script setup>`.
:: ::
## Example ## Example
@ -131,7 +131,7 @@ const { data, pending, error, refresh } = await useFetch('/api/auth/login', {
``` ```
::alert{type=warning} ::alert{type=warning}
`useFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useFetch`. [`useFetch`](/docs/api/composables/use-fetch) is a reserved function name transformed by the compiler, so you should not name your own function `useFetch`.
:: ::
::LinkExample{link="/docs/examples/advanced/use-custom-fetch-composable"} ::LinkExample{link="/docs/examples/advanced/use-custom-fetch-composable"}

View File

@ -8,7 +8,7 @@ The `useHeadSafe` composable is a wrapper around the [`useHead`](/docs/api/compo
## Usage ## Usage
You can pass all the same values as `useHead` You can pass all the same values as [`useHead`](/docs/api/composables/use-head)
```ts ```ts
useHeadSafe({ useHeadSafe({

View File

@ -2,9 +2,9 @@
description: useHead customizes the head properties of individual pages of your Nuxt app. description: useHead customizes the head properties of individual pages of your Nuxt app.
--- ---
# `useHead` # useHead
The `useHead` composable function allows you to manage your head tags in a programmatic and reactive way, powered by [Unhead](https://unhead.harlanzw.com/). If the data comes from a user or other untrusted source, we recommend you check out [`useHeadSafe`](/docs/api/composables/use-head-safe) The [`useHead`](/docs/api/composables/use-head) composable function allows you to manage your head tags in a programmatic and reactive way, powered by [Unhead](https://unhead.harlanzw.com/). If the data comes from a user or other untrusted source, we recommend you check out [`useHeadSafe`](/docs/api/composables/use-head-safe)
:ReadMore{link="/docs/getting-started/seo-meta"} :ReadMore{link="/docs/getting-started/seo-meta"}
@ -14,7 +14,7 @@ The `useHead` composable function allows you to manage your head tags in a progr
useHead(meta: MaybeComputedRef<MetaObject>): void useHead(meta: MaybeComputedRef<MetaObject>): void
``` ```
Below are the non-reactive types for `useHead`. Below are the non-reactive types for [`useHead`](/docs/api/composables/use-head) .
```ts ```ts
interface MetaObject { interface MetaObject {
@ -34,7 +34,7 @@ interface MetaObject {
See [@unhead/schema](https://github.com/unjs/unhead/blob/main/packages/schema/src/schema.ts) for more detailed types. See [@unhead/schema](https://github.com/unjs/unhead/blob/main/packages/schema/src/schema.ts) for more detailed types.
::alert{type=info} ::alert{type=info}
The properties of `useHead` can be dynamic, accepting `ref`, `computed` and `reactive` properties. `meta` parameter can also accept a function returning an object to make the entire object reactive. The properties of [`useHead`](/docs/api/composables/use-head) can be dynamic, accepting `ref`, `computed` and `reactive` properties. `meta` parameter can also accept a function returning an object to make the entire object reactive.
:: ::
## Parameters ## Parameters

View File

@ -4,13 +4,13 @@ description: This wrapper around useAsyncData triggers navigation immediately.
# `useLazyAsyncData` # `useLazyAsyncData`
`useLazyAsyncData` provides a wrapper around `useAsyncData` that triggers navigation before the handler is resolved by setting the `lazy` option to `true`. `useLazyAsyncData` provides a wrapper around [`useAsyncData`](/docs/api/composables/use-async-data) that triggers navigation before the handler is resolved by setting the `lazy` option to `true`.
## Description ## Description
By default, [useAsyncData](/docs/api/composables/use-async-data) blocks navigation until its async handler is resolved. By default, [useAsyncData](/docs/api/composables/use-async-data) blocks navigation until its async handler is resolved.
> `useLazyAsyncData` has the same signature as `useAsyncData`. > `useLazyAsyncData` has the same signature as [`useAsyncData`](/docs/api/composables/use-async-data) .
:ReadMore{link="/docs/api/composables/use-async-data"} :ReadMore{link="/docs/api/composables/use-async-data"}

View File

@ -4,13 +4,13 @@ description: This wrapper around useFetch triggers navigation immediately.
# `useLazyFetch` # `useLazyFetch`
`useLazyFetch` provides a wrapper around `useFetch` that triggers navigation before the handler is resolved by setting the `lazy` option to `true`. `useLazyFetch` provides a wrapper around [`useFetch`](/docs/api/composables/use-fetch) that triggers navigation before the handler is resolved by setting the `lazy` option to `true`.
## Description ## Description
By default, [useFetch](/docs/api/composables/use-fetch) blocks navigation until its async handler is resolved. By default, [useFetch](/docs/api/composables/use-fetch) blocks navigation until its async handler is resolved.
> `useLazyFetch` has the same signature as `useFetch`. > [`useLazyFetch`](/docs/api/composables/use-lazy-fetch) has the same signature as `useFetch`.
:ReadMore{link="/docs/api/composables/use-fetch"} :ReadMore{link="/docs/api/composables/use-fetch"}

View File

@ -87,21 +87,19 @@ await nuxtApp.callHook('my-plugin:init')
`payload` exposes data and state variables from server side to client side. The following keys will be available on the client after they have been passed from the server side: `payload` exposes data and state variables from server side to client side. The following keys will be available on the client after they have been passed from the server side:
- **serverRendered** (boolean) - Indicates if response is server-side-rendered. - **serverRendered** (boolean) - Indicates if response is server-side-rendered.
- **data** (object) - When you fetch the data from an API endpoint using either `useFetch` or `useAsyncData`, resulting payload can be accessed from the `payload.data`. This data is cached and helps you prevent fetching the same data in case an identical request is made more than once. - **data** (object) - When you fetch the data from an API endpoint using either [`useFetch`](/docs/api/composables/use-fetch) or [`useAsyncData`](/docs/api/composables/use-async-data) , resulting payload can be accessed from the `payload.data`. This data is cached and helps you prevent fetching the same data in case an identical request is made more than once.
```vue [app.vue] ```vue [app.vue]
export default defineComponent({ <script setup>
async setup() { const { data } = await useAsyncData('count', () => $fetch('/api/count'))
const { data } = await useAsyncData('count', () => $fetch('/api/count')) </script>
}
})
``` ```
After fetching the value of `count` using `useAsyncData` in the example above, if you access `payload.data`, you will see `{ count: 1 }` recorded there. The value of `count` is updated whenever the page count increases. After fetching the value of `count` using [`useAsyncData`](/docs/api/composables/use-async-data) in the example above, if you access `payload.data`, you will see `{ count: 1 }` recorded there. The value of `count` is updated whenever the page count increases.
When accessing the same `payload.data` from [ssrcontext](#ssrcontext), you can access the same value on the server side as well. When accessing the same `payload.data` from [ssrcontext](#ssrcontext), you can access the same value on the server side as well.
- **state** (object) - When you use `useState` composable in Nuxt to set shared state, this state data is accessed through `payload.state.[name-of-your-state]`. - **state** (object) - When you use [`useState`](/docs/api/composables/use-state) composable in Nuxt to set shared state, this state data is accessed through `payload.state.[name-of-your-state]`.
```js [plugins/my-plugin.ts] ```js [plugins/my-plugin.ts]
export const useColor = () => useState<string>('color', () => 'pink') export const useColor = () => useState<string>('color', () => 'pink')

View File

@ -1,6 +1,6 @@
# `useNuxtData` # `useNuxtData`
`useNuxtData` gives you access to the current cached value of `useAsyncData`, `useLazyAsyncData`, `useFetch` and `useLazyFetch` with explicitly provided key. `useNuxtData` gives you access to the current cached value of [`useAsyncData`](/docs/api/composables/use-async-data) , `useLazyAsyncData`, [`useFetch`](/docs/api/composables/use-fetch) and [`useLazyFetch`](/docs/api/composables/use-lazy-fetch) with explicitly provided key.
## Type ## Type

View File

@ -5,7 +5,7 @@ description: "Use useRequestHeaders to access the incoming request headers."
# `useRequestHeaders` # `useRequestHeaders`
You can use built-in `useRequestHeaders` composable to access the incoming request headers within your pages, components, and plugins. You can use built-in [`useRequestHeaders`](/docs/api/composables/use-request-headers) composable to access the incoming request headers within your pages, components, and plugins.
```js ```js
// Get all request headers // Get all request headers
@ -16,12 +16,12 @@ const headers = useRequestHeaders(['cookie'])
``` ```
::alert{icon=👉} ::alert{icon=👉}
In the browser, `useRequestHeaders` will return an empty object. In the browser, [`useRequestHeaders`](/docs/api/composables/use-request-headers) will return an empty object.
:: ::
## Example ## Example
We can use `useRequestHeaders` to access and proxy the initial request's `authorization` header to any future internal requests during SSR. We can use [`useRequestHeaders`](/docs/api/composables/use-request-headers) to access and proxy the initial request's `authorization` header to any future internal requests during SSR.
The example below adds the `authorization` request header to an isomorphic `$fetch` call. The example below adds the `authorization` request header to an isomorphic `$fetch` call.

View File

@ -5,13 +5,13 @@ description: The useRoute composable returns the current route.
# `useRoute` # `useRoute`
The `useRoute` composable returns the current route and must be called in a `setup` function, plugin, or route middleware. The [`useRoute`](/docs/api/composables/use-route) composable returns the current route and must be called in a `setup` function, plugin, or route middleware.
Within the template of a Vue component, you can access the route using `$route`. Within the template of a Vue component, you can access the route using `$route`.
## Example ## Example
In the following example, we call an API via `useFetch` using a dynamic page parameter - `slug` - as part of the URL. In the following example, we call an API via [`useFetch`](/docs/api/composables/use-fetch) using a dynamic page parameter - `slug` - as part of the URL.
```html [~/pages/[slug].vue] ```html [~/pages/[slug].vue]
<script setup> <script setup>

View File

@ -5,11 +5,11 @@ description: "The useRouter composable returns the router instance."
# `useRouter` # `useRouter`
The `useRouter` composable returns the router instance and must be called in a setup function, plugin, or route middleware. The [`useRouter`](/docs/api/composables/use-router) composable returns the router instance and must be called in a setup function, plugin, or route middleware.
Within the template of a Vue component, you can access the router using `$router` instead. Within the template of a Vue component, you can access the router using `$router` instead.
If you have a `pages/` folder, `useRouter` is identical in behavior to the one provided by `vue-router`. Feel free to read the router documentation for more information on what each method does. If you have a `pages/` folder, [`useRouter`](/docs/api/composables/use-router) is identical in behavior to the one provided by `vue-router`. Feel free to read the router documentation for more information on what each method does.
::ReadMore{link="https://router.vuejs.org/api/interfaces/Router.html#Properties-currentRoute"} ::ReadMore{link="https://router.vuejs.org/api/interfaces/Router.html#Properties-currentRoute"}
:: ::
@ -63,4 +63,4 @@ However, Nuxt has a concept of **route middleware** that simplifies the implemen
## Universal Router Instance ## Universal Router Instance
If you do not have a `pages/` folder, then `useRouter` will return a universal router instance with similar helper methods, but be aware that not all features may be supported or behave in exactly the same way as with `vue-router`. If you do not have a `pages/` folder, then [`useRouter`](/docs/api/composables/use-router) will return a universal router instance with similar helper methods, but be aware that not all features may be supported or behave in exactly the same way as with `vue-router`.

View File

@ -1,6 +1,6 @@
# `useRuntimeConfig` # `useRuntimeConfig`
The `useRuntimeConfig` composable is used to expose config variables within your app. The [`useRuntimeConfig`](/docs/api/composables/use-runtime-config) composable is used to expose config variables within your app.
## Usage ## Usage

View File

@ -4,8 +4,8 @@ description: The useServerSeoMeta composable lets you define your site's SEO met
# `useServerSeoMeta` # `useServerSeoMeta`
Just like [`useSeoMeta`](/docs/api/composables/use-seo-meta), `useServerSeoMeta` composable lets you define your site's SEO meta tags as a flat object with full TypeScript support. Just like [`useSeoMeta`](/docs/api/composables/use-seo-meta), [`useServerSeoMeta`](/docs/api/composables/use-server-seo-meta) composable lets you define your site's SEO meta tags as a flat object with full TypeScript support.
:ReadMore{link="/docs/api/composables/use-seo-meta"} :ReadMore{link="/docs/api/composables/use-seo-meta"}
In most instances, the meta doesn't need to be reactive as robots will only scan the initial load. So we recommend using `useServerSeoMeta` as a performance-focused utility that will not do anything (or return a `head` object) on the client. In most instances, the meta doesn't need to be reactive as robots will only scan the initial load. So we recommend using [`useServerSeoMeta`](/docs/api/composables/use-server-seo-meta) as a performance-focused utility that will not do anything (or return a `head` object) on the client.
Parameters are exactly the same as with [`useSeoMeta`](/docs/api/composables/use-seo-meta) Parameters are exactly the same as with [`useSeoMeta`](/docs/api/composables/use-seo-meta)

View File

@ -10,16 +10,16 @@ useState<T>(init?: () => T | Ref<T>): Ref<T>
useState<T>(key: string, init?: () => T | Ref<T>): Ref<T> useState<T>(key: string, init?: () => T | Ref<T>): Ref<T>
``` ```
* **key**: A unique key ensuring that data fetching is properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file and line number of the instance of `useState` will be generated for you. * **key**: A unique key ensuring that data fetching is properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file and line number of the instance of [`useState`](/docs/api/composables/use-state) will be generated for you.
* **init**: A function that provides initial value for the state when not initiated. This function can also return a `Ref`. * **init**: A function that provides initial value for the state when not initiated. This function can also return a `Ref`.
* **T**: (typescript only) Specify the type of state * **T**: (typescript only) Specify the type of state
::alert{type=warning} ::alert{type=warning}
Because the data inside `useState` will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols. Because the data inside [`useState`](/docs/api/composables/use-state) will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols.
:: ::
::alert{type=warning} ::alert{type=warning}
`useState` is a reserved function name transformed by the compiler, so you should not name your own function `useState`. [`useState`](/docs/api/composables/use-state) is a reserved function name transformed by the compiler, so you should not name your own function `useState`.
:: ::
::ReadMore{link="/docs/getting-started/state-management"} ::ReadMore{link="/docs/getting-started/state-management"}

View File

@ -5,7 +5,7 @@ description: The NuxtPage component is required to display pages located in the
# `<NuxtPage>` # `<NuxtPage>`
`<NuxtPage>` is a built-in component that comes with Nuxt. `NuxtPage` is required to display top-level or nested pages located in the `pages/` directory. `<NuxtPage>` is a built-in component that comes with Nuxt. `NuxtPage` is required to display top-level or nested pages located in the [`pages/` directory](/docs/guide/directory-structure/pages).
`NuxtPage` is a wrapper around [`<RouterView>`](https://router.vuejs.org/api/interfaces/RouterViewProps.html#interface-routerviewprops) component from Vue Router. `NuxtPage` component accepts same `name` and `route` props. `NuxtPage` is a wrapper around [`<RouterView>`](https://router.vuejs.org/api/interfaces/RouterViewProps.html#interface-routerviewprops) component from Vue Router. `NuxtPage` component accepts same `name` and `route` props.
@ -44,7 +44,7 @@ definePageMeta({
</script> </script>
``` ```
:button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/nuxt/tree/main/examples/routing/pages?file=app.vue" blank} :button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/examples/tree/main/routing/pages?file=app.vue" blank}
## Accessing a page's component ref ## Accessing a page's component ref
@ -71,7 +71,7 @@ In addition, `NuxtPage` also accepts custom props that you may need to pass furt
<NuxtPage :foobar="123" /> <NuxtPage :foobar="123" />
``` ```
For example, in above example, value of `foobar` will be available using `attrs.foobar`. For example, in the above example, the value of `foobar` will be available using `$attrs.foobar` in the template or `useAttrs().foobar` in `<script setup>`.
::ReadMore{link="/docs/guide/directory-structure/app"} ::ReadMore{link="/docs/guide/directory-structure/app"}
:: ::

View File

@ -24,8 +24,6 @@ In this example, we use `<NuxtLink>` component to link to a website.
</template> </template>
``` ```
:button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/nuxt/tree/main/examples/routing/nuxt-link?terminal=dev&file=/pages/index.vue" blank}
### Internal Routing ### Internal Routing
In this example, we use `<NuxtLink>` component to link to another page of the application. In this example, we use `<NuxtLink>` component to link to another page of the application.
@ -39,8 +37,6 @@ In this example, we use `<NuxtLink>` component to link to another page of the ap
</template> </template>
``` ```
:button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/nuxt/tree/main/examples/routing/nuxt-link?terminal=dev&file=/pages/index.vue" blank}
### `target` and `rel` Attributes ### `target` and `rel` Attributes
In this example, we use `<NuxtLink>` with `target`, `rel`, and `noRel` props. In this example, we use `<NuxtLink>` with `target`, `rel`, and `noRel` props.
@ -69,8 +65,6 @@ In this example, we use `<NuxtLink>` with `target`, `rel`, and `noRel` props.
</template> </template>
``` ```
:button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/nuxt/tree/main/examples/routing/nuxt-link?terminal=dev&file=/pages/index.vue" blank}
## Props ## Props
- **to**: Any URL or a [route location object](https://router.vuejs.org/api/interfaces/RouteLocation.html) from Vue Router - **to**: Any URL or a [route location object](https://router.vuejs.org/api/interfaces/RouteLocation.html) from Vue Router
@ -104,8 +98,6 @@ export default defineNuxtLink({
You can then use `<MyNuxtLink />` component as usual with your new defaults. You can then use `<MyNuxtLink />` component as usual with your new defaults.
:button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/nuxt/tree/main/examples/routing/nuxt-link?terminal=dev&file=/components/MyNuxtLink.ts" blank}
### `defineNuxtLink` Signature ### `defineNuxtLink` Signature
```ts ```ts

View File

@ -11,13 +11,15 @@ Add `<NuxtLoadingIndicator/>` in your `app.vue` or layouts.
```vue [app.vue] ```vue [app.vue]
<template> <template>
<NuxtLayout> <NuxtLayout>
<NuxtLoadingIndicator /> <!-- here --> <div>
<NuxtPage /> <NuxtLoadingIndicator /> <!-- here -->
<NuxtPage />
</div>
</NuxtLayout> </NuxtLayout>
</template> </template>
``` ```
:button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/nuxt/tree/main/examples/routing/pages?terminal=dev&file=/app.vue" blank} :button-link[Open on StackBlitz]{href="https://stackblitz.com/github/nuxt/examples/tree/main/routing/pages?file=app.vue&terminal=dev" blank}
::alert{type=warning} ::alert{type=warning}
If you are changing layouts as well as page, the page transition you set here will not run. Instead, you should set a layout transition. If you are changing layouts as well as page, the page transition you set here will not run. Instead, you should set a layout transition.

View File

@ -9,7 +9,7 @@ Nuxt uses [ofetch](https://github.com/unjs/ofetch) to expose globally the `$fetc
During server-side rendering, calling `$fetch` to fetch your internal [API routes](/docs/guide/directory-structure/server) will directly call the relevant function (emulating the request), **saving an additional API call**. During server-side rendering, calling `$fetch` to fetch your internal [API routes](/docs/guide/directory-structure/server) will directly call the relevant function (emulating the request), **saving an additional API call**.
However, using `$fetch` in components without wrapping it with `useAsyncData` causes fetching the data twice: initially on the server, then again on the client-side during hydration, because `$fetch` does not transfer state from the server to the client. Thus, the fetch will be executed on both sides because the client has to get the data again. However, using `$fetch` in components without wrapping it with [`useAsyncData`](/docs/api/composables/use-async-data) causes fetching the data twice: initially on the server, then again on the client-side during hydration, because `$fetch` does not transfer state from the server to the client. Thus, the fetch will be executed on both sides because the client has to get the data again.
We recommend to use [`useFetch`](https://nuxt.com/docs/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/api/composables/use-async-data) + `$fetch` to prevent double data fetching when fetching the component data. We recommend to use [`useFetch`](https://nuxt.com/docs/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/api/composables/use-async-data) + `$fetch` to prevent double data fetching when fetching the component data.

View File

@ -1,6 +1,6 @@
# `clearNuxtData` # `clearNuxtData`
Delete cached data, error status and pending promises of `useAsyncData` and `useFetch`. Delete cached data, error status and pending promises of [`useAsyncData`](/docs/api/composables/use-async-data) and `useFetch`.
This method is useful if you want to invalidate the data fetching for another page. This method is useful if you want to invalidate the data fetching for another page.
@ -12,4 +12,4 @@ clearNuxtData (keys?: string | string[] | ((key: string) => boolean)): void
## Parameters ## Parameters
* `keys`: One or an array of keys that are used in `useAsyncData` to delete their cached data. If no keys are provided, **all data** will be invalidated. * `keys`: One or an array of keys that are used in [`useAsyncData`](/docs/api/composables/use-async-data) to delete their cached data. If no keys are provided, **all data** will be invalidated.

View File

@ -12,4 +12,4 @@ clearNuxtState (keys?: string | string[] | ((key: string) => boolean)): void
## Parameters ## Parameters
* `keys`: One or an array of keys that are used in `useState` to delete their cached state. If no keys are provided, **all state** will be invalidated. * `keys`: One or an array of keys that are used in [`useState`](/docs/api/composables/use-state) to delete their cached state. If no keys are provided, **all state** will be invalidated.

View File

@ -6,7 +6,7 @@ title: "defineNuxtRouteMiddleware"
Create named route middleware using `defineNuxtRouteMiddleware` helper function. Create named route middleware using `defineNuxtRouteMiddleware` helper function.
Route middleware are stored in the `middleware/` directory of your Nuxt application (unless [set otherwise](/docs/api/configuration/nuxt-config#middleware)). Route middleware are stored in the [`middleware/` directory](/docs/guide/directory-structure/middleware) of your Nuxt application (unless [set otherwise](/docs/api/configuration/nuxt-config#middleware)).
## Type ## Type
@ -46,7 +46,7 @@ The above route middleware will redirect a user to the custom error page defined
### Redirection ### Redirection
Use `useState` in combination with `navigateTo` helper function inside the route middleware to redirect users to different routes based on their authentication status: Use [`useState`](/docs/api/composables/use-state) in combination with `navigateTo` helper function inside the route middleware to redirect users to different routes based on their authentication status:
```ts [middleware/auth.ts] ```ts [middleware/auth.ts]
export default defineNuxtRouteMiddleware((to, from) => { export default defineNuxtRouteMiddleware((to, from) => {

View File

@ -4,7 +4,7 @@ title: "definePageMeta"
# `definePageMeta` # `definePageMeta`
`definePageMeta` is a compiler macro that you can use to set metadata for your **page** components located in the `pages/` directory (unless [set otherwise](/docs/api/configuration/nuxt-config#pages)). This way you can set custom metadata for each static or dynamic route of your Nuxt application. `definePageMeta` is a compiler macro that you can use to set metadata for your **page** components located in the [`pages/` directory](/docs/guide/directory-structure/pages) (unless [set otherwise](/docs/api/configuration/nuxt-config#pages)). This way you can set custom metadata for each static or dynamic route of your Nuxt application.
```vue [pages/some-page.vue] ```vue [pages/some-page.vue]
<script setup> <script setup>
@ -161,7 +161,7 @@ The example below shows how the middleware can be defined using a `function` dir
### Defining Layout ### Defining Layout
You can define the layout that matches the layout's file name located (by default) in the `layouts/` directory. You can also disable the layout by setting the `layout` to `false`: You can define the layout that matches the layout's file name located (by default) in the [`layouts/` directory](/docs/guide/directory-structure/layouts). You can also disable the layout by setting the `layout` to `false`:
```vue [pages/some-page.vue] ```vue [pages/some-page.vue]
<script setup> <script setup>

View File

@ -5,7 +5,7 @@ description: refreshNuxtData refetches all data from the server and updates the
# `refreshNuxtData` # `refreshNuxtData`
`refreshNuxtData` re-fetches all data from the server and updates the page as well as invalidates the cache of `useAsyncData`, `useLazyAsyncData`, `useFetch` and `useLazyFetch`. `refreshNuxtData` re-fetches all data from the server and updates the page as well as invalidates the cache of [`useAsyncData`](/docs/api/composables/use-async-data) , `useLazyAsyncData`, [`useFetch`](/docs/api/composables/use-fetch) and `useLazyFetch`.
## Type ## Type
@ -19,13 +19,13 @@ refreshNuxtData(keys?: string | string[])
**Type**: `String | String[]` **Type**: `String | String[]`
`refreshNuxtData` accepts a single or an array of strings as `keys` that are used to fetch the data. This parameter is **optional**. All `useAsyncData` and `useFetch` are re-fetched when no `keys` are specified. `refreshNuxtData` accepts a single or an array of strings as `keys` that are used to fetch the data. This parameter is **optional**. All [`useAsyncData`](/docs/api/composables/use-async-data) and [`useFetch`](/docs/api/composables/use-fetch) are re-fetched when no `keys` are specified.
## Examples ## Examples
### Refresh All data ### Refresh All data
This example below refreshes all data being fetched using `useAsyncData` and `useFetch` on the current page. This example below refreshes all data being fetched using [`useAsyncData`](/docs/api/composables/use-async-data) and [`useFetch`](/docs/api/composables/use-fetch) on the current page.
```vue [pages/some-page.vue] ```vue [pages/some-page.vue]
<template> <template>

View File

@ -7,7 +7,7 @@ If you're starting a fresh Nuxt 3 project, please skip this section and go to [N
:: ::
::alert{type=warning} ::alert{type=warning}
Nuxt Bridge provides identical features to Nuxt 3 ([docs](/docs/guide/concepts/auto-imports)) but there are some limitations, notably that `useAsyncData` and `useFetch` composables are not available. Please read the rest of this page for details. Nuxt Bridge provides identical features to Nuxt 3 ([docs](/docs/guide/concepts/auto-imports)) but there are some limitations, notably that [`useAsyncData`](/docs/api/composables/use-async-data) and [`useFetch`](/docs/api/composables/use-fetch) composables are not available. Please read the rest of this page for details.
:: ::
Bridge is a forward-compatibility layer that allows you to experience many of the new Nuxt 3 features by simply installing and enabling a Nuxt module. Bridge is a forward-compatibility layer that allows you to experience many of the new Nuxt 3 features by simply installing and enabling a Nuxt module.
@ -111,7 +111,7 @@ For all other situations, you can use the `nuxi build` command.
Please make sure to avoid any CommonJS syntax such as `module.exports`, `require` or `require.resolve` in your config file. It will soon be deprecated and unsupported. Please make sure to avoid any CommonJS syntax such as `module.exports`, `require` or `require.resolve` in your config file. It will soon be deprecated and unsupported.
You can use static `import`, dynamic `import()` and `export default` instead. Using TypeScript by renaming to `nuxt.config.ts` is also possible and recommended. You can use static `import`, dynamic `import()` and `export default` instead. Using TypeScript by renaming to [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt.config) is also possible and recommended.
```ts [nuxt.config.js|ts] ```ts [nuxt.config.js|ts]
import { defineNuxtConfig } from '@nuxt/bridge' import { defineNuxtConfig } from '@nuxt/bridge'
@ -226,7 +226,7 @@ export default defineNuxtPlugin(nuxtApp => {
``` ```
::alert ::alert
If you want to use the new Nuxt composables (such as `useNuxtApp` or `useRuntimeConfig`) within your plugins, you will need to use the `defineNuxtPlugin` helper for those plugins. If you want to use the new Nuxt composables (such as [`useNuxtApp`](/docs/api/composables/use-nuxt-app) or `useRuntimeConfig`) within your plugins, you will need to use the `defineNuxtPlugin` helper for those plugins.
:: ::
::alert{type=warning} ::alert{type=warning}
@ -257,7 +257,7 @@ Nuxt Bridge does not support `definePageMeta`.
## New `useHead` (Optional) ## New `useHead` (Optional)
Nuxt Bridge provides a new Nuxt 3 meta API that can be accessed with a new `useHead` composable. Nuxt Bridge provides a new Nuxt 3 meta API that can be accessed with a new [`useHead`](/docs/api/composables/use-head) composable.
```vue ```vue
<script setup> <script setup>
@ -279,11 +279,11 @@ export default defineNuxtConfig({
``` ```
::alert ::alert
This `useHead` composable uses `@vueuse/head` under the hood (rather than `vue-meta`) to manipulate your `<head>`. You need to add `@vueuse/head` to your package.json file for it to work properly. This [`useHead`](/docs/api/composables/use-head) composable uses `@vueuse/head` under the hood (rather than `vue-meta`) to manipulate your `<head>`. You need to add `@vueuse/head` to your package.json file for it to work properly.
:: ::
::alert{type=warning} ::alert{type=warning}
We recommend not using the native Nuxt 2 `head()` properties in addition to `useHead`, as they may conflict. We recommend not using the native Nuxt 2 `head()` properties in addition to [`useHead`](/docs/api/composables/use-head) , as they may conflict.
:: ::
For more information on how to use this composable, see [the docs](/docs/getting-started/seo-meta). For more information on how to use this composable, see [the docs](/docs/getting-started/seo-meta).

View File

@ -91,7 +91,7 @@ You may wish to [migrate your plugins to Nuxt 3-style plugins](/docs/bridge/over
### `onGlobalSetup` ### `onGlobalSetup`
This function has been removed, but its use cases can be met by using `useNuxtApp` or `useState` within `defineNuxtPlugin`. You can also run any custom code within the `setup()` function of a layout. This function has been removed, but its use cases can be met by using [`useNuxtApp`](/docs/api/composables/use-nuxt-app) or [`useState`](/docs/api/composables/use-state) within `defineNuxtPlugin`. You can also run any custom code within the `setup()` function of a layout.
```diff ```diff
- import { onGlobalSetup } from '@nuxtjs/composition-api' - import { onGlobalSetup } from '@nuxtjs/composition-api'
@ -110,7 +110,7 @@ This function has been removed, but its use cases can be met by using `useNuxtAp
These two functions have been replaced with a new composable that works very similarly under the hood: `useState`. These two functions have been replaced with a new composable that works very similarly under the hood: `useState`.
The key differences are that you must provide a _key_ for this state (which Nuxt generated automatically for `ssrRef` and `shallowSsrRef`), and that it can only be called within a Nuxt 3 plugin (which is defined by `defineNuxtPlugin`) or a component instance. (In other words, you cannot use `useState` with a global/ambient context, because of the danger of shared state across requests.) The key differences are that you must provide a _key_ for this state (which Nuxt generated automatically for `ssrRef` and `shallowSsrRef`), and that it can only be called within a Nuxt 3 plugin (which is defined by `defineNuxtPlugin`) or a component instance. (In other words, you cannot use [`useState`](/docs/api/composables/use-state) with a global/ambient context, because of the danger of shared state across requests.)
```diff ```diff
- import { ssrRef } from '@nuxtjs/composition-api' - import { ssrRef } from '@nuxtjs/composition-api'
@ -133,9 +133,9 @@ This function has been removed, and you will need to find an alternative impleme
### `useRouter` and `useRoute` ### `useRouter` and `useRoute`
Nuxt Bridge provides direct replacements for these composables via `useRouter` and `useRoute`. Nuxt Bridge provides direct replacements for these composables via [`useRouter`](/docs/api/composables/use-router) and `useRoute`.
The only key difference is that `useRoute` no longer returns a computed property. The only key difference is that [`useRoute`](/docs/api/composables/use-route) no longer returns a computed property.
```diff ```diff
- import { useRouter, useRoute } from '@nuxtjs/composition-api' - import { useRouter, useRoute } from '@nuxtjs/composition-api'
@ -246,7 +246,7 @@ title.value = 'new title'
Be careful not to use both `useNuxt2Meta()` and the Options API `head()` within the same component, as behavior may be unpredictable. Be careful not to use both `useNuxt2Meta()` and the Options API `head()` within the same component, as behavior may be unpredictable.
:: ::
Nuxt Bridge also provides a Nuxt 3-compatible meta implementation that can be accessed with the `useHead` composable. Nuxt Bridge also provides a Nuxt 3-compatible meta implementation that can be accessed with the [`useHead`](/docs/api/composables/use-head) composable.
```diff ```diff
<script setup> <script setup>
@ -268,6 +268,6 @@ export default defineNuxtConfig({
}) })
``` ```
This `useHead` composable uses `@vueuse/head` under the hood (rather than `vue-meta`) to manipulate your `<head>`. Accordingly, it is recommended not to use both the native Nuxt 2 `head()` properties as well as `useHead`, as they may conflict. This [`useHead`](/docs/api/composables/use-head) composable uses `@vueuse/head` under the hood (rather than `vue-meta`) to manipulate your `<head>`. Accordingly, it is recommended not to use both the native Nuxt 2 `head()` properties as well as [`useHead`](/docs/api/composables/use-head) , as they may conflict.
For more information on how to use this composable, see [the Nuxt 3 docs](/docs/getting-started/seo-meta). For more information on how to use this composable, see [the Nuxt 3 docs](/docs/getting-started/seo-meta).

View File

@ -94,7 +94,7 @@ If you are a module author, you can check out [more information about module com
## Directory Changes ## Directory Changes
The `static/` directory (for storing static assets) has been renamed to `public/`. You can either rename your `static` directory to `public`, or keep the name by setting `dir.public` in your `nuxt.config`. The [`static/` directory](/docs/guide/directory-structure/static) (for storing static assets) has been renamed to `public/`. You can either rename your `static` directory to `public`, or keep the name by setting `dir.public` in your `nuxt.config`.
::ReadMore{link="/docs/guide/directory-structure/public"} ::ReadMore{link="/docs/guide/directory-structure/public"}
:: ::

View File

@ -3,7 +3,7 @@
Nuxt 3 provides several different ways to manage your meta tags. Nuxt 3 provides several different ways to manage your meta tags.
1. Through your `nuxt.config`. 1. Through your `nuxt.config`.
2. Through the `useHead` [composable](/docs/getting-started/seo-meta) 2. Through the [`useHead`](/docs/api/composables/use-head) [composable](/docs/getting-started/seo-meta)
3. Through [global meta components](/docs/getting-started/seo-meta) 3. Through [global meta components](/docs/getting-started/seo-meta)
You can customize `title`, `titleTemplate`, `base`, `script`, `noscript`, `style`, `meta`, `link`, `htmlAttrs` and `bodyAttrs`. You can customize `title`, `titleTemplate`, `base`, `script`, `noscript`, `style`, `meta`, `link`, `htmlAttrs` and `bodyAttrs`.
@ -17,10 +17,10 @@ Nuxt currently uses [`vueuse/head`](https://github.com/vueuse/head) to manage yo
## Migration ## Migration
1. In your `nuxt.config`, rename `head` to `meta`. Consider moving this shared meta configuration into your `app.vue` instead. (Note that objects no longer have a `hid` key for deduplication.) 1. In your `nuxt.config`, rename `head` to `meta`. Consider moving this shared meta configuration into your `app.vue` instead. (Note that objects no longer have a `hid` key for deduplication.)
1. If you need to access the component state with `head`, you should migrate to using `useHead`. You might also consider using the built-in meta-components. 1. If you need to access the component state with `head`, you should migrate to using [`useHead`](/docs/api/composables/use-head) . You might also consider using the built-in meta-components.
1. If you need to use the Options API, there is a `head()` method you can use when you use `defineNuxtComponent`. 1. If you need to use the Options API, there is a `head()` method you can use when you use `defineNuxtComponent`.
### Example: `useHead` ### Example: useHead
::code-group ::code-group

View File

@ -64,7 +64,7 @@ You will also need to change how you define the layout used by a page using the
## Pages ## Pages
Nuxt 3 ships with an optional `vue-router` integration triggered by the existence of a `pages/` directory in your source directory. If you only have a single page, you may consider instead moving it to `app.vue` for a lighter build. Nuxt 3 ships with an optional `vue-router` integration triggered by the existence of a [`pages/` directory](/docs/guide/directory-structure/pages) in your source directory. If you only have a single page, you may consider instead moving it to `app.vue` for a lighter build.
### Dynamic Routes ### Dynamic Routes
@ -93,7 +93,7 @@ If you have been defining transitions for your page or layout directly in your c
1. Rename any pages with dynamic parameters to match the new format. 1. Rename any pages with dynamic parameters to match the new format.
1. Update `<Nuxt>` and `<NuxtChild>` to be `<NuxtPage>`. 1. Update `<Nuxt>` and `<NuxtChild>` to be `<NuxtPage>`.
1. If you're using the Composition API, you can also migrate `this.$route` and `this.$router` to use `useRoute` and `useRouter` composables. 1. If you're using the Composition API, you can also migrate `this.$route` and `this.$router` to use [`useRoute`](/docs/api/composables/use-route) and [`useRouter`](/docs/api/composables/use-router) composables.
#### Example: Dynamic Routes #### Example: Dynamic Routes

View File

@ -21,7 +21,7 @@ You can read more [about direct API calls](/docs/guide/concepts/server-engine#di
### Using Composables ### Using Composables
Nuxt 3 provides new composables for fetching data: `useAsyncData` and `useFetch`. They each have 'lazy' variants (`useLazyAsyncData` and `useLazyFetch`), which do not block client-side navigation. Nuxt 3 provides new composables for fetching data: [`useAsyncData`](/docs/api/composables/use-async-data) and `useFetch`. They each have 'lazy' variants (`useLazyAsyncData` and `useLazyFetch`), which do not block client-side navigation.
In Nuxt 2, you'd fetch your data in your component using a syntax similar to: In Nuxt 2, you'd fetch your data in your component using a syntax similar to:
@ -54,13 +54,13 @@ With Nuxt 3, you can perform this data fetching using composables in your `setup
You can now use `post` inside of your Nuxt 3 template, or call `refresh` to update the data. You can now use `post` inside of your Nuxt 3 template, or call `refresh` to update the data.
::alert{type=info} ::alert{type=info}
Despite the names, `useFetch` is not a direct replacement of the `fetch()` hook. Rather, `useAsyncData` replaces both hooks and is more customizable; it can do more than simply fetching data from an endpoint. `useFetch` is a convenience wrapper around `useAsyncData` for simply fetching data from an endpoint. Despite the names, [`useFetch`](/docs/api/composables/use-fetch) is not a direct replacement of the `fetch()` hook. Rather, [`useAsyncData`](/docs/api/composables/use-async-data) replaces both hooks and is more customizable; it can do more than simply fetching data from an endpoint. [`useFetch`](/docs/api/composables/use-fetch) is a convenience wrapper around [`useAsyncData`](/docs/api/composables/use-async-data) for simply fetching data from an endpoint.
:: ::
### Migration ### Migration
1. Replace the `asyncData` hook with `useAsyncData` or `useFetch` in your page/component. 1. Replace the `asyncData` hook with [`useAsyncData`](/docs/api/composables/use-async-data) or [`useFetch`](/docs/api/composables/use-fetch) in your page/component.
1. Replace the `fetch` hook with `useAsyncData` or `useFetch` in your component. 1. Replace the `fetch` hook with [`useAsyncData`](/docs/api/composables/use-async-data) or [`useFetch`](/docs/api/composables/use-fetch) in your component.
## `head` ## `head`

View File

@ -2,16 +2,16 @@
If you wish to reference environment variables within your Nuxt 3 app, you will need to use runtime config. If you wish to reference environment variables within your Nuxt 3 app, you will need to use runtime config.
When referencing these variables within your components, you will have to use the `useRuntimeConfig` composable in your setup method (or Nuxt plugin). When referencing these variables within your components, you will have to use the [`useRuntimeConfig`](/docs/api/composables/use-runtime-config) composable in your setup method (or Nuxt plugin).
In the `server/` portion of your app, you can use `useRuntimeConfig` without any import. In the `server/` portion of your app, you can use [`useRuntimeConfig`](/docs/api/composables/use-runtime-config) without any import.
[Read more about runtime config](/docs/guide/going-further/runtime-config). [Read more about runtime config](/docs/guide/going-further/runtime-config).
## Migration ## Migration
1. Add any environment variables that you use in your app to the `runtimeConfig` property of the `nuxt.config` file. 1. Add any environment variables that you use in your app to the `runtimeConfig` property of the `nuxt.config` file.
1. Migrate `process.env` to `useRuntimeConfig` throughout the Vue part of your app. 1. Migrate `process.env` to [`useRuntimeConfig`](/docs/api/composables/use-runtime-config) throughout the Vue part of your app.
## Example ## Example

View File

@ -37,20 +37,21 @@
"nuxt": "workspace:*", "nuxt": "workspace:*",
"vite": "4.3.9", "vite": "4.3.9",
"vue": "3.3.4", "vue": "3.3.4",
"magic-string": "^0.30.0" "magic-string": "^0.30.1"
}, },
"devDependencies": { "devDependencies": {
"@actions/core": "1.10.0", "@actions/core": "1.10.0",
"@nuxt/test-utils": "workspace:*", "@nuxt/test-utils": "workspace:*",
"@nuxt/webpack-builder": "workspace:*", "@nuxt/webpack-builder": "workspace:*",
"@nuxtjs/eslint-config-typescript": "12.0.0", "@nuxtjs/eslint-config-typescript": "12.0.0",
"@types/fs-extra": "11.0.1",
"@types/node": "18.16.19", "@types/node": "18.16.19",
"@types/semver": "7.5.0", "@types/semver": "7.5.0",
"case-police": "0.6.1", "case-police": "0.6.1",
"chalk": "5.3.0", "chalk": "5.3.0",
"changelogen": "0.5.3", "changelogen": "0.5.4",
"cheerio": "1.0.0-rc.12", "cheerio": "1.0.0-rc.12",
"consola": "3.2.2", "consola": "3.2.3",
"devalue": "4.3.2", "devalue": "4.3.2",
"eslint": "8.44.0", "eslint": "8.44.0",
"eslint-plugin-import": "2.27.5", "eslint-plugin-import": "2.27.5",
@ -58,10 +59,11 @@
"eslint-plugin-no-only-tests": "3.1.0", "eslint-plugin-no-only-tests": "3.1.0",
"execa": "7.1.1", "execa": "7.1.1",
"fs-extra": "11.1.1", "fs-extra": "11.1.1",
"globby": "13.2.1", "globby": "13.2.2",
"h3": "1.7.1", "h3": "1.7.1",
"jiti": "1.18.2", "jiti": "1.19.1",
"markdownlint-cli": "^0.33.0", "markdownlint-cli": "^0.33.0",
"nitropack": "2.5.2",
"nuxi": "workspace:*", "nuxi": "workspace:*",
"nuxt": "workspace:*", "nuxt": "workspace:*",
"nuxt-vitest": "0.8.7", "nuxt-vitest": "0.8.7",
@ -74,13 +76,14 @@
"typescript": "5.0.4", "typescript": "5.0.4",
"ufo": "1.1.2", "ufo": "1.1.2",
"vite": "4.3.9", "vite": "4.3.9",
"vitest": "0.32.4", "vitest": "0.33.0",
"vitest-environment-nuxt": "0.8.7", "vitest-environment-nuxt": "0.8.7",
"vue": "3.3.4", "vue": "3.3.4",
"vue-eslint-parser": "9.3.1", "vue-eslint-parser": "9.3.1",
"vue-tsc": "1.8.3" "vue-router": "4.2.4",
"vue-tsc": "1.8.4"
}, },
"packageManager": "pnpm@8.6.5", "packageManager": "pnpm@8.6.6",
"engines": { "engines": {
"node": "^14.18.0 || >=16.10.0" "node": "^14.18.0 || >=16.10.0"
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@nuxt/kit", "name": "@nuxt/kit",
"version": "3.6.1", "version": "3.6.2",
"repository": "nuxt/nuxt", "repository": "nuxt/nuxt",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
@ -22,12 +22,12 @@
"dependencies": { "dependencies": {
"@nuxt/schema": "workspace:../schema", "@nuxt/schema": "workspace:../schema",
"c12": "^1.4.2", "c12": "^1.4.2",
"consola": "^3.2.2", "consola": "^3.2.3",
"defu": "^6.1.2", "defu": "^6.1.2",
"globby": "^13.2.1", "globby": "^13.2.2",
"hash-sum": "^2.0.0", "hash-sum": "^2.0.0",
"ignore": "^5.2.4", "ignore": "^5.2.4",
"jiti": "^1.18.2", "jiti": "^1.19.1",
"knitwork": "^1.0.0", "knitwork": "^1.0.0",
"mlly": "^1.4.0", "mlly": "^1.4.0",
"pathe": "^1.1.1", "pathe": "^1.1.1",
@ -35,7 +35,7 @@
"scule": "^1.0.0", "scule": "^1.0.0",
"semver": "^7.5.3", "semver": "^7.5.3",
"unctx": "^2.3.1", "unctx": "^2.3.1",
"unimport": "^3.0.11", "unimport": "^3.0.14",
"untyped": "^1.3.2" "untyped": "^1.3.2"
}, },
"devDependencies": { "devDependencies": {
@ -46,7 +46,7 @@
"nitropack": "2.5.2", "nitropack": "2.5.2",
"unbuild": "latest", "unbuild": "latest",
"vite": "4.3.9", "vite": "4.3.9",
"vitest": "0.32.4", "vitest": "0.33.0",
"webpack": "5.88.1" "webpack": "5.88.1"
}, },
"engines": { "engines": {

View File

@ -46,7 +46,7 @@ export async function getNuxtModuleVersion (module: string | NuxtModule, nuxt: N
return version return version
} }
// it's possible that the module will be installed, it just hasn't been done yet, preemptively load the instance // it's possible that the module will be installed, it just hasn't been done yet, preemptively load the instance
if (typeof module !== 'string' && nuxt.options.modules.includes(moduleMeta.name)) { if (nuxt.options.modules.includes(moduleMeta.name)) {
const { buildTimeModuleMeta } = await loadNuxtModuleInstance(moduleMeta.name, nuxt) const { buildTimeModuleMeta } = await loadNuxtModuleInstance(moduleMeta.name, nuxt)
return buildTimeModuleMeta.version || false return buildTimeModuleMeta.version || false
} }

View File

@ -77,7 +77,7 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
const setupTime = perf ? Math.round((perf.duration * 100)) / 100 : 0 // TODO: remove when Node 14 reaches EOL const setupTime = perf ? Math.round((perf.duration * 100)) / 100 : 0 // TODO: remove when Node 14 reaches EOL
// Measure setup time // Measure setup time
if (setupTime > 5000) { if (setupTime > 5000 && uniqueKey !== '@nuxt/telemetry') {
logger.warn(`Slow module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`) logger.warn(`Slow module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`)
} else if (nuxt.options.debug) { } else if (nuxt.options.debug) {
logger.info(`Module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`) logger.info(`Module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`)

View File

@ -1,6 +1,6 @@
{ {
"name": "nuxi", "name": "nuxi",
"version": "3.6.1", "version": "3.6.2",
"repository": "nuxt/nuxt", "repository": "nuxt/nuxt",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
@ -29,7 +29,7 @@
"clear": "0.1.0", "clear": "0.1.0",
"clipboardy": "3.0.0", "clipboardy": "3.0.0",
"colorette": "2.0.20", "colorette": "2.0.20",
"consola": "3.2.2", "consola": "3.2.3",
"deep-object-diff": "1.1.9", "deep-object-diff": "1.1.9",
"defu": "6.1.2", "defu": "6.1.2",
"destr": "2.0.0", "destr": "2.0.0",
@ -37,7 +37,7 @@
"flat": "5.0.2", "flat": "5.0.2",
"giget": "1.1.2", "giget": "1.1.2",
"h3": "1.7.1", "h3": "1.7.1",
"jiti": "1.18.2", "jiti": "1.19.1",
"listhen": "1.0.4", "listhen": "1.0.4",
"mlly": "1.4.0", "mlly": "1.4.0",
"mri": "1.2.0", "mri": "1.2.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "nuxt", "name": "nuxt",
"version": "3.6.1", "version": "3.6.2",
"repository": "nuxt/nuxt", "repository": "nuxt/nuxt",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
@ -55,13 +55,13 @@
"@nuxt/devalue": "^2.0.2", "@nuxt/devalue": "^2.0.2",
"@nuxt/kit": "workspace:../kit", "@nuxt/kit": "workspace:../kit",
"@nuxt/schema": "workspace:../schema", "@nuxt/schema": "workspace:../schema",
"@nuxt/telemetry": "^2.2.0", "@nuxt/telemetry": "^2.3.0",
"@nuxt/ui-templates": "^1.2.0", "@nuxt/ui-templates": "^1.2.0",
"@nuxt/vite-builder": "workspace:../vite", "@nuxt/vite-builder": "workspace:../vite",
"@unhead/ssr": "^1.1.29", "@unhead/ssr": "^1.1.30",
"@unhead/vue": "^1.1.29", "@unhead/vue": "^1.1.30",
"@vue/shared": "^3.3.4", "@vue/shared": "^3.3.4",
"acorn": "8.9.0", "acorn": "8.10.0",
"c12": "^1.4.2", "c12": "^1.4.2",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"cookie-es": "^1.0.0", "cookie-es": "^1.0.0",
@ -72,14 +72,14 @@
"escape-string-regexp": "^5.0.0", "escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3", "estree-walker": "^3.0.3",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
"globby": "^13.2.1", "globby": "^13.2.2",
"h3": "^1.7.1", "h3": "^1.7.1",
"hookable": "^5.5.3", "hookable": "^5.5.3",
"jiti": "^1.18.2", "jiti": "^1.19.1",
"klona": "^2.0.6", "klona": "^2.0.6",
"knitwork": "^1.0.0", "knitwork": "^1.0.0",
"local-pkg": "^0.4.3", "local-pkg": "^0.4.3",
"magic-string": "^0.30.0", "magic-string": "^0.30.1",
"mlly": "^1.4.0", "mlly": "^1.4.0",
"nitropack": "^2.5.2", "nitropack": "^2.5.2",
"nuxi": "workspace:../nuxi", "nuxi": "workspace:../nuxi",
@ -96,14 +96,14 @@
"uncrypto": "^0.1.3", "uncrypto": "^0.1.3",
"unctx": "^2.3.1", "unctx": "^2.3.1",
"unenv": "^1.5.1", "unenv": "^1.5.1",
"unimport": "^3.0.11", "unimport": "^3.0.14",
"unplugin": "^1.3.2", "unplugin": "^1.3.2",
"unplugin-vue-router": "^0.6.4", "unplugin-vue-router": "^0.6.4",
"untyped": "^1.3.2", "untyped": "^1.3.2",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-bundle-renderer": "^1.0.3", "vue-bundle-renderer": "^1.0.3",
"vue-devtools-stub": "^0.1.0", "vue-devtools-stub": "^0.1.0",
"vue-router": "^4.2.2" "vue-router": "^4.2.4"
}, },
"devDependencies": { "devDependencies": {
"@parcel/watcher": "2.2.0", "@parcel/watcher": "2.2.0",
@ -113,7 +113,7 @@
"@vitejs/plugin-vue": "4.2.3", "@vitejs/plugin-vue": "4.2.3",
"unbuild": "latest", "unbuild": "latest",
"vite": "4.3.9", "vite": "4.3.9",
"vitest": "0.32.4" "vitest": "0.33.0"
}, },
"peerDependencies": { "peerDependencies": {
"@parcel/watcher": "^2.1.0", "@parcel/watcher": "^2.1.0",

View File

@ -0,0 +1,10 @@
import type { InjectionKey } from 'vue'
import type { RouteLocationNormalizedLoaded } from 'vue-router'
export interface LayoutMeta {
isCurrent: (route: RouteLocationNormalizedLoaded) => boolean
}
export const LayoutMetaSymbol: InjectionKey<LayoutMeta> = Symbol('layout-meta')
export const PageRouteSymbol: InjectionKey<RouteLocationNormalizedLoaded> = Symbol('route')

View File

@ -1,7 +1,9 @@
import type { InjectionKey, Ref, VNode } from 'vue' import type { Ref, VNode } from 'vue'
import { Suspense, Transition, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from 'vue' import { Suspense, Transition, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from 'vue'
import type { RouteLocationNormalizedLoaded } from 'vue-router' import type { RouteLocationNormalizedLoaded } from 'vue-router'
import { _wrapIf } from './utils' import { _wrapIf } from './utils'
import { LayoutMetaSymbol, PageRouteSymbol } from './injections'
import { useRoute } from '#app/composables/router' import { useRoute } from '#app/composables/router'
// @ts-expect-error virtual file // @ts-expect-error virtual file
import { useRoute as useVueRouterRoute } from '#build/pages' import { useRoute as useVueRouterRoute } from '#build/pages'
@ -11,12 +13,6 @@ import layouts from '#build/layouts'
import { appLayoutTransition as defaultLayoutTransition } from '#build/nuxt.config.mjs' import { appLayoutTransition as defaultLayoutTransition } from '#build/nuxt.config.mjs'
import { useNuxtApp } from '#app' import { useNuxtApp } from '#app'
export interface LayoutMeta {
isCurrent: (route: RouteLocationNormalizedLoaded) => boolean
}
export const LayoutMetaSymbol: InjectionKey<LayoutMeta> = Symbol('layout-meta')
export default defineComponent({ export default defineComponent({
name: 'NuxtLayout', name: 'NuxtLayout',
inheritAttrs: false, inheritAttrs: false,
@ -29,7 +25,7 @@ export default defineComponent({
setup (props, context) { setup (props, context) {
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
// Need to ensure (if we are not a child of `<NuxtPage>`) that we use synchronous route (not deferred) // Need to ensure (if we are not a child of `<NuxtPage>`) that we use synchronous route (not deferred)
const injectedRoute = inject('_route') as RouteLocationNormalizedLoaded const injectedRoute = inject(PageRouteSymbol)
const route = injectedRoute === useRoute() ? useVueRouterRoute() : injectedRoute const route = injectedRoute === useRoute() ? useVueRouterRoute() : injectedRoute
const layout = computed(() => unref(props.name) ?? route.meta.layout as string ?? 'default') const layout = computed(() => unref(props.name) ?? route.meta.layout as string ?? 'default')
@ -49,13 +45,14 @@ export default defineComponent({
// We avoid rendering layout transition if there is no layout to render // We avoid rendering layout transition if there is no layout to render
return _wrapIf(Transition, hasLayout && transitionProps, { return _wrapIf(Transition, hasLayout && transitionProps, {
default: () => h(Suspense, { suspensible: true, onResolve: () => { nextTick(done) } }, { default: () => h(Suspense, { suspensible: true, onResolve: () => { nextTick(done) } }, {
default: () => _wrapIf(LayoutProvider, hasLayout && { // @ts-expect-error seems to be an issue in vue types
default: () => h(LayoutProvider, {
layoutProps: mergeProps(context.attrs, { ref: layoutRef }), layoutProps: mergeProps(context.attrs, { ref: layoutRef }),
key: layout.value, key: layout.value,
name: layout.value, name: layout.value,
shouldProvide: !props.name, shouldProvide: !props.name,
hasTransition: !!transitionProps hasTransition: !!transitionProps
}, context.slots).default() }, context.slots)
}) })
}).default() }).default()
} }
@ -67,7 +64,7 @@ const LayoutProvider = defineComponent({
inheritAttrs: false, inheritAttrs: false,
props: { props: {
name: { name: {
type: String type: [String, Boolean]
}, },
layoutProps: { layoutProps: {
type: Object type: Object
@ -81,33 +78,45 @@ const LayoutProvider = defineComponent({
}, },
setup (props, context) { setup (props, context) {
// Prevent reactivity when the page will be rerendered in a different suspense fork // Prevent reactivity when the page will be rerendered in a different suspense fork
// eslint-disable-next-line vue/no-setup-props-destructure
const name = props.name
if (props.shouldProvide) { if (props.shouldProvide) {
// eslint-disable-next-line vue/no-setup-props-destructure
const name = props.name
provide(LayoutMetaSymbol, { provide(LayoutMetaSymbol, {
isCurrent: (route: RouteLocationNormalizedLoaded) => name === (route.meta.layout ?? 'default') isCurrent: (route: RouteLocationNormalizedLoaded) => name === (route.meta.layout ?? 'default')
}) })
} }
let vnode: VNode let vnode: VNode | undefined
if (process.dev && process.client) { if (process.dev && process.client) {
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
if (['#comment', '#text'].includes(vnode?.el?.nodeName)) { if (['#comment', '#text'].includes(vnode?.el?.nodeName)) {
console.warn(`[nuxt] \`${props.name}\` layout does not have a single root node and will cause errors when navigating between routes.`) if (name) {
console.warn(`[nuxt] \`${name}\` layout does not have a single root node and will cause errors when navigating between routes.`)
} else {
console.warn('[nuxt] `<NuxtLayout>` needs to be passed a single root node in its default slot.')
}
} }
}) })
}) })
} }
return () => { return () => {
if (!name || (typeof name === 'string' && !(name in layouts))) {
if (process.dev && process.client && props.hasTransition) {
vnode = context.slots.default?.() as VNode | undefined
return vnode
}
return context.slots.default?.()
}
if (process.dev && process.client && props.hasTransition) { if (process.dev && process.client && props.hasTransition) {
vnode = h(layouts[props.name], props.layoutProps, context.slots) vnode = h(layouts[name], props.layoutProps, context.slots)
return vnode return vnode
} }
return h(layouts[props.name], props.layoutProps, context.slots) return h(layouts[name], props.layoutProps, context.slots)
} }
} }
}) })

View File

@ -5,6 +5,7 @@ import { appendResponseHeader } from 'h3'
import { useHead } from '@unhead/vue' import { useHead } from '@unhead/vue'
import { randomUUID } from 'uncrypto' import { randomUUID } from 'uncrypto'
import { withQuery } from 'ufo' import { withQuery } from 'ufo'
import type { FetchResponse } from 'ofetch'
// eslint-disable-next-line import/no-restricted-paths // eslint-disable-next-line import/no-restricted-paths
import type { NuxtIslandResponse } from '../../core/runtime/nitro/renderer' import type { NuxtIslandResponse } from '../../core/runtime/nitro/renderer'
@ -42,11 +43,38 @@ export default defineComponent({
const hashId = computed(() => hash([props.name, props.props, props.context])) const hashId = computed(() => hash([props.name, props.props, props.context]))
const instance = getCurrentInstance()! const instance = getCurrentInstance()!
const event = useRequestEvent() const event = useRequestEvent()
const eventFetch = process.server ? event.fetch : globalThis.fetch // TODO: remove use of `$fetch.raw` when nitro 503 issues on windows dev server are resolved
const eventFetch = process.server ? event.fetch : process.dev ? $fetch.raw : globalThis.fetch
const mounted = ref(false) const mounted = ref(false)
onMounted(() => { mounted.value = true }) onMounted(() => { mounted.value = true })
const ssrHTML = ref<string>(process.client ? getFragmentHTML(instance.vnode?.el ?? null).join('') ?? '<div></div>' : '<div></div>') function setPayload (key: string, result: NuxtIslandResponse) {
nuxtApp.payload.data[key] = {
__nuxt_island: {
key,
...(process.server && process.env.prerender)
? {}
: { params: { ...props.context, props: props.props ? JSON.stringify(props.props) : undefined } }
},
...result
}
}
const ssrHTML = ref('<div></div>')
if (process.client) {
const renderedHTML = getFragmentHTML(instance.vnode?.el ?? null).join('')
if (renderedHTML && nuxtApp.isHydrating) {
setPayload(`${props.name}_${hashId.value}`, {
html: getFragmentHTML(instance.vnode?.el ?? null, true).join(''),
state: {},
head: {
link: [],
style: []
}
})
}
ssrHTML.value = renderedHTML ?? '<div></div>'
}
const slotProps = computed(() => getSlotProps(ssrHTML.value)) const slotProps = computed(() => getSlotProps(ssrHTML.value))
const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] ?? randomUUID()) const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] ?? randomUUID())
const availableSlots = computed(() => [...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1])) const availableSlots = computed(() => [...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1]))
@ -81,7 +109,7 @@ export default defineComponent({
...props.context, ...props.context,
props: props.props ? JSON.stringify(props.props) : undefined props: props.props ? JSON.stringify(props.props) : undefined
})) }))
const result = await r.json() as NuxtIslandResponse const result = process.server || !process.dev ? await r.json() : (r as FetchResponse<NuxtIslandResponse>)._data
// TODO: support passing on more headers // TODO: support passing on more headers
if (process.server && process.env.prerender) { if (process.server && process.env.prerender) {
const hints = r.headers.get('x-nitro-prerender') const hints = r.headers.get('x-nitro-prerender')
@ -89,20 +117,7 @@ export default defineComponent({
appendResponseHeader(event, 'x-nitro-prerender', hints) appendResponseHeader(event, 'x-nitro-prerender', hints)
} }
} }
nuxtApp.payload.data[key] = { setPayload(key, result)
__nuxt_island: {
key,
...(process.server && process.env.prerender)
? {}
: {
params: {
...props.context,
props: props.props ? JSON.stringify(props.props) : undefined
}
}
},
...result
}
return result return result
} }
const key = ref(0) const key = ref(0)

View File

@ -12,6 +12,7 @@ import { defineAsyncComponent, onErrorCaptured, onServerPrefetch, provide } from
import { useNuxtApp } from '#app/nuxt' import { useNuxtApp } from '#app/nuxt'
import { isNuxtError, showError, useError } from '#app/composables/error' import { isNuxtError, showError, useError } from '#app/composables/error'
import { useRoute } from '#app/composables/router' import { useRoute } from '#app/composables/router'
import { PageRouteSymbol } from '#app/components/injections'
import AppComponent from '#build/app-component.mjs' import AppComponent from '#build/app-component.mjs'
import ErrorComponent from '#build/error-component.mjs' import ErrorComponent from '#build/error-component.mjs'
@ -27,7 +28,7 @@ const SingleRenderer = process.test && process.dev && process.server && url.star
.then(r => r.default(process.server ? url : window.location.href))) .then(r => r.default(process.server ? url : window.location.href)))
// Inject default route (outside of pages) as active route // Inject default route (outside of pages) as active route
provide('_route', useRoute()) provide(PageRouteSymbol, useRoute())
// vue:setup hook // vue:setup hook
const results = nuxtApp.hooks.callHookWith(hooks => hooks.map(hook => hook()), 'vue:setup') const results = nuxtApp.hooks.callHookWith(hooks => hooks.map(hook => hook()), 'vue:setup')

View File

@ -0,0 +1,59 @@
import { defineComponent, h, nextTick, onMounted, provide, shallowReactive } from 'vue'
import type { Ref, VNode } from 'vue'
import type { RouteLocation, RouteLocationNormalizedLoaded } from '#vue-router'
import { PageRouteSymbol } from '#app/components/injections'
export const RouteProvider = defineComponent({
name: 'RouteProvider',
props: {
vnode: {
type: Object as () => VNode,
required: true
},
route: {
type: Object as () => RouteLocationNormalizedLoaded,
required: true
},
vnodeRef: Object as () => Ref<any>,
renderKey: String,
trackRootNodes: Boolean
},
setup (props) {
// Prevent reactivity when the page will be rerendered in a different suspense fork
// eslint-disable-next-line vue/no-setup-props-destructure
const previousKey = props.renderKey
// eslint-disable-next-line vue/no-setup-props-destructure
const previousRoute = props.route
// Provide a reactive route within the page
const route = {} as RouteLocation
for (const key in props.route) {
Object.defineProperty(route, key, {
get: () => previousKey === props.renderKey ? props.route[key as keyof RouteLocationNormalizedLoaded] : previousRoute[key as keyof RouteLocationNormalizedLoaded]
})
}
provide(PageRouteSymbol, shallowReactive(route))
let vnode: VNode
if (process.dev && process.client && props.trackRootNodes) {
onMounted(() => {
nextTick(() => {
if (['#comment', '#text'].includes(vnode?.el?.nodeName)) {
const filename = (vnode?.type as any).__file
console.warn(`[nuxt] \`${filename}\` does not have a single root node and will cause errors when navigating between routes.`)
}
})
})
}
return () => {
if (process.dev && process.client) {
vnode = h(props.vnode, { ref: props.vnodeRef })
return vnode
}
return h(props.vnode, { ref: props.vnodeRef })
}
}
})

View File

@ -99,25 +99,42 @@ export function vforToArray (source: any): any[] {
return [] return []
} }
export function getFragmentHTML (element: RendererNode | null) { /**
* Retrieve the HTML content from an element
* Handles `<!--[-->` Fragment elements
*
* @param element the element to retrieve the HTML
* @param withoutSlots purge all slots from the HTML string retrieved
* @returns {string[]} An array of string which represent the content of each element. Use `.join('')` to retrieve a component vnode.el HTML
*/
export function getFragmentHTML (element: RendererNode | null, withoutSlots = false) {
if (element) { if (element) {
if (element.nodeName === '#comment' && element.nodeValue === '[') { if (element.nodeName === '#comment' && element.nodeValue === '[') {
return getFragmentChildren(element) return getFragmentChildren(element, [], withoutSlots)
}
if (withoutSlots) {
const clone = element.cloneNode(true)
clone.querySelectorAll('[nuxt-ssr-slot-name]').forEach((n: Element) => { n.innerHTML = '' })
return [clone.outerHTML]
} }
return [element.outerHTML] return [element.outerHTML]
} }
return [] return []
} }
function getFragmentChildren (element: RendererNode | null, blocks: string[] = []) { function getFragmentChildren (element: RendererNode | null, blocks: string[] = [], withoutSlots = false) {
if (element && element.nodeName) { if (element && element.nodeName) {
if (isEndFragment(element)) { if (isEndFragment(element)) {
return blocks return blocks
} else if (!isStartFragment(element)) { } else if (!isStartFragment(element)) {
blocks.push(element.outerHTML) const clone = element.cloneNode(true) as Element
if (withoutSlots) {
clone.querySelectorAll('[nuxt-ssr-slot-name]').forEach((n) => { n.innerHTML = '' })
}
blocks.push(clone.outerHTML)
} }
getFragmentChildren(element.nextSibling, blocks) getFragmentChildren(element.nextSibling, blocks, withoutSlots)
} }
return blocks return blocks
} }

View File

@ -10,6 +10,7 @@ import { createError, showError } from './error'
import { useState } from './state' import { useState } from './state'
import type { PageMeta } from '#app' import type { PageMeta } from '#app'
import { PageRouteSymbol } from '#app/components/injections'
export const useRouter: typeof _useRouter = () => { export const useRouter: typeof _useRouter = () => {
return useNuxtApp()?.$router as Router return useNuxtApp()?.$router as Router
@ -20,7 +21,7 @@ export const useRoute: typeof _useRoute = () => {
console.warn('[nuxt] Calling `useRoute` within middleware may lead to misleading results. Instead, use the (to, from) arguments passed to the middleware to access the new and old routes.') console.warn('[nuxt] Calling `useRoute` within middleware may lead to misleading results. Instead, use the (to, from) arguments passed to the middleware to access the new and old routes.')
} }
if (hasInjectionContext()) { if (hasInjectionContext()) {
return inject('_route', useNuxtApp()._route) return inject(PageRouteSymbol, useNuxtApp()._route)
} }
return useNuxtApp()._route return useNuxtApp()._route
} }

View File

@ -126,7 +126,7 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
} }
}) })
nuxt.hook('builder:generateApp', async () => { nuxt.hook('app:templatesGenerated', async () => {
await regenerateImports() await regenerateImports()
}) })
} }

View File

@ -205,22 +205,20 @@ export default defineNuxtModule({
if (nuxt.options.dev || !nitro.options.static) { return } if (nuxt.options.dev || !nitro.options.static) { return }
// Prerender all non-dynamic page routes when generating app // Prerender all non-dynamic page routes when generating app
const prerenderRoutes = new Set<string>() const prerenderRoutes = new Set<string>()
nuxt.hook('modules:done', () => { nuxt.hook('pages:extend', (pages) => {
nuxt.hook('pages:extend', (pages) => { prerenderRoutes.clear()
prerenderRoutes.clear() const processPages = (pages: NuxtPage[], currentPath = '/') => {
const processPages = (pages: NuxtPage[], currentPath = '/') => { for (const page of pages) {
for (const page of pages) { // Add root of optional dynamic paths and catchalls
// Add root of optional dynamic paths and catchalls if (OPTIONAL_PARAM_RE.test(page.path) && !page.children?.length) { prerenderRoutes.add(currentPath) }
if (OPTIONAL_PARAM_RE.test(page.path) && !page.children?.length) { prerenderRoutes.add(currentPath) } // Skip dynamic paths
// Skip dynamic paths if (page.path.includes(':')) { continue }
if (page.path.includes(':')) { continue } const route = joinURL(currentPath, page.path)
const route = joinURL(currentPath, page.path) prerenderRoutes.add(route)
prerenderRoutes.add(route) if (page.children) { processPages(page.children, route) }
if (page.children) { processPages(page.children, route) }
}
} }
processPages(pages) }
}) processPages(pages)
}) })
nuxt.hook('nitro:build:before', (nitro) => { nuxt.hook('nitro:build:before', (nitro) => {
for (const route of nitro.options.prerender.routes || []) { for (const route of nitro.options.prerender.routes || []) {

View File

@ -1,14 +1,15 @@
import { Suspense, Transition, computed, defineComponent, h, inject, nextTick, onMounted, provide, reactive, ref } from 'vue' import { Suspense, Transition, defineComponent, h, inject, nextTick, ref } from 'vue'
import type { KeepAliveProps, TransitionProps, VNode } from 'vue' import type { KeepAliveProps, TransitionProps, VNode } from 'vue'
import { RouterView } from '#vue-router' import { RouterView } from '#vue-router'
import { defu } from 'defu' import { defu } from 'defu'
import type { RouteLocation, RouteLocationNormalized, RouteLocationNormalizedLoaded } from '#vue-router' import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from '#vue-router'
import type { RouterViewSlotProps } from './utils' import type { RouterViewSlotProps } from './utils'
import { generateRouteKey, wrapInKeepAlive } from './utils' import { generateRouteKey, wrapInKeepAlive } from './utils'
import { RouteProvider } from '#app/components/route-provider'
import { useNuxtApp } from '#app/nuxt' import { useNuxtApp } from '#app/nuxt'
import { _wrapIf } from '#app/components/utils' import { _wrapIf } from '#app/components/utils'
import { LayoutMetaSymbol } from '#app/components/layout' import { LayoutMetaSymbol, PageRouteSymbol } from '#app/components/injections'
// @ts-expect-error virtual file // @ts-expect-error virtual file
import { appKeepalive as defaultKeepaliveConfig, appPageTransition as defaultPageTransition } from '#build/nuxt.config.mjs' import { appKeepalive as defaultKeepaliveConfig, appPageTransition as defaultPageTransition } from '#build/nuxt.config.mjs'
@ -38,6 +39,7 @@ export default defineComponent({
setup (props, { attrs, expose }) { setup (props, { attrs, expose }) {
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
const pageRef = ref() const pageRef = ref()
const forkRoute = inject(PageRouteSymbol, null)
expose({ pageRef }) expose({ pageRef })
@ -47,13 +49,32 @@ export default defineComponent({
return () => { return () => {
return h(RouterView, { name: props.name, route: props.route, ...attrs }, { return h(RouterView, { name: props.name, route: props.route, ...attrs }, {
default: (routeProps: RouterViewSlotProps) => { default: (routeProps: RouterViewSlotProps) => {
if (!routeProps.Component) { return } const isRenderingNewRouteInOldFork = process.client && haveParentRoutesRendered(forkRoute, routeProps.route, routeProps.Component)
const hasSameChildren = process.client && forkRoute && forkRoute.matched.length === routeProps.route.matched.length
if (!routeProps.Component) {
// If we're rendering a `<NuxtPage>` child route on navigation to a route which lacks a child page
// we'll render the old vnode until the new route finishes resolving
if (process.client && vnode && !hasSameChildren) {
return vnode
}
return
}
// Return old vnode if we are rendering _new_ page suspense fork in _old_ layout suspense fork // Return old vnode if we are rendering _new_ page suspense fork in _old_ layout suspense fork
if (vnode && _layoutMeta && !_layoutMeta.isCurrent(routeProps.route)) { if (process.client && vnode && _layoutMeta && !_layoutMeta.isCurrent(routeProps.route)) {
return vnode return vnode
} }
if (process.client && isRenderingNewRouteInOldFork && forkRoute && (!_layoutMeta || _layoutMeta?.isCurrent(forkRoute))) {
// if leaving a route with an existing child route, render the old vnode
if (hasSameChildren) {
return vnode
}
// If _leaving_ null child route, return null vnode
return null
}
const key = generateRouteKey(routeProps, props.pageKey) const key = generateRouteKey(routeProps, props.pageKey)
const done = nuxtApp.deferHydration() const done = nuxtApp.deferHydration()
@ -70,7 +91,17 @@ export default defineComponent({
suspensible: true, suspensible: true,
onPending: () => nuxtApp.callHook('page:start', routeProps.Component), onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
onResolve: () => { nextTick(() => nuxtApp.callHook('page:finish', routeProps.Component).finally(done)) } onResolve: () => { nextTick(() => nuxtApp.callHook('page:finish', routeProps.Component).finally(done)) }
}, { default: () => h(RouteProvider, { key, routeProps, pageKey: key, hasTransition, pageRef } as {}) }) }, {
// @ts-expect-error seems to be an issue in vue types
default: () => h(RouteProvider, {
key,
vnode: routeProps.Component,
route: routeProps.route,
renderKey: key,
trackRootNodes: hasTransition,
vnodeRef: pageRef
})
})
)).default() )).default()
return vnode return vnode
@ -92,45 +123,15 @@ function _mergeTransitionProps (routeProps: TransitionProps[]): TransitionProps
return defu(..._props as [TransitionProps, TransitionProps]) return defu(..._props as [TransitionProps, TransitionProps])
} }
const RouteProvider = defineComponent({ function haveParentRoutesRendered (fork: RouteLocationNormalizedLoaded | null, newRoute: RouteLocationNormalizedLoaded, Component?: VNode) {
name: 'RouteProvider', if (!fork) { return false }
// TODO: Type props
// eslint-disable-next-line vue/require-prop-types
props: ['routeProps', 'pageKey', 'hasTransition', 'pageRef'],
setup (props) {
// Prevent reactivity when the page will be rerendered in a different suspense fork
// eslint-disable-next-line vue/no-setup-props-destructure
const previousKey = props.pageKey
// eslint-disable-next-line vue/no-setup-props-destructure
const previousRoute = props.routeProps.route
// Provide a reactive route within the page const index = newRoute.matched.findIndex(m => m.components?.default === Component?.type)
const route = {} as RouteLocation if (!index || index === -1) { return false }
for (const key in props.routeProps.route) {
(route as any)[key] = computed(() => previousKey === props.pageKey ? props.routeProps.route[key] : previousRoute[key])
}
provide('_route', reactive(route)) // we only care whether the parent route components have had to rerender
return newRoute.matched.slice(0, index)
let vnode: VNode .some(
if (process.dev && process.client && props.hasTransition) { (c, i) => c.components?.default !== fork.matched[i]?.components?.default) ||
onMounted(() => { (Component && generateRouteKey({ route: newRoute, Component }) !== generateRouteKey({ route: fork, Component }))
nextTick(() => { }
if (['#comment', '#text'].includes(vnode?.el?.nodeName)) {
const filename = (vnode?.type as any).__file
console.warn(`[nuxt] \`${filename}\` does not have a single root node and will cause errors when navigating between routes.`)
}
})
})
}
return () => {
if (process.dev && process.client) {
vnode = h(props.routeProps.Component, { ref: props.pageRef })
return vnode
}
return h(props.routeProps.Component, { ref: props.pageRef })
}
}
})

View File

@ -1,4 +1,4 @@
import { computed, isReadonly, reactive, shallowRef } from 'vue' import { isReadonly, reactive, shallowReactive, shallowRef } from 'vue'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import type { RouteLocation, Router, RouterScrollBehavior } from '#vue-router' import type { RouteLocation, Router, RouterScrollBehavior } from '#vue-router'
import { import {
@ -108,10 +108,12 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
// https://github.com/vuejs/router/blob/main/packages/router/src/router.ts#L1225-L1233 // https://github.com/vuejs/router/blob/main/packages/router/src/router.ts#L1225-L1233
const route = {} as RouteLocation const route = {} as RouteLocation
for (const key in _route.value) { for (const key in _route.value) {
(route as any)[key] = computed(() => _route.value[key as keyof RouteLocation]) Object.defineProperty(route, key, {
get: () => _route.value[key as keyof RouteLocation]
})
} }
nuxtApp._route = reactive(route) nuxtApp._route = shallowReactive(route)
nuxtApp._middleware = nuxtApp._middleware || { nuxtApp._middleware = nuxtApp._middleware || {
global: [], global: [],

View File

@ -1,6 +1,6 @@
{ {
"name": "@nuxt/schema", "name": "@nuxt/schema",
"version": "3.6.1", "version": "3.6.2",
"repository": "nuxt/nuxt", "repository": "nuxt/nuxt",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
@ -26,11 +26,11 @@
"prepack": "unbuild" "prepack": "unbuild"
}, },
"devDependencies": { "devDependencies": {
"@nuxt/telemetry": "2.2.0", "@nuxt/telemetry": "2.3.0",
"@types/file-loader": "5.0.1", "@types/file-loader": "5.0.1",
"@types/pug": "2.0.6", "@types/pug": "2.0.6",
"@types/sass-loader": "8.0.5", "@types/sass-loader": "8.0.5",
"@unhead/schema": "1.1.29", "@unhead/schema": "1.1.30",
"@vitejs/plugin-vue": "4.2.3", "@vitejs/plugin-vue": "4.2.3",
"@vitejs/plugin-vue-jsx": "3.0.1", "@vitejs/plugin-vue-jsx": "3.0.1",
"@vue/compiler-core": "3.3.4", "@vue/compiler-core": "3.3.4",
@ -44,7 +44,7 @@
"vue": "3.3.4", "vue": "3.3.4",
"vue-bundle-renderer": "1.0.3", "vue-bundle-renderer": "1.0.3",
"vue-loader": "17.2.2", "vue-loader": "17.2.2",
"vue-router": "4.2.2", "vue-router": "4.2.4",
"webpack": "5.88.1", "webpack": "5.88.1",
"webpack-dev-middleware": "6.1.1" "webpack-dev-middleware": "6.1.1"
}, },
@ -56,7 +56,7 @@
"postcss-import-resolver": "^2.0.0", "postcss-import-resolver": "^2.0.0",
"std-env": "^3.3.3", "std-env": "^3.3.3",
"ufo": "^1.1.2", "ufo": "^1.1.2",
"unimport": "^3.0.11", "unimport": "^3.0.14",
"untyped": "^1.3.2" "untyped": "^1.3.2"
}, },
"engines": { "engines": {

View File

@ -58,7 +58,7 @@ export default defineUntypedSchema({
* *
* @see [Nuxt Telemetry](https://github.com/nuxt/telemetry) for more information. * @see [Nuxt Telemetry](https://github.com/nuxt/telemetry) for more information.
* *
* @type {typeof import('@nuxt/telemetry').ModuleOptions} * @type {boolean | Record<string, any>}
*/ */
telemetry: undefined, telemetry: undefined,

View File

@ -193,7 +193,7 @@ export default defineUntypedSchema({
* Options passed directly to the transformer from `unctx` that preserves async context * Options passed directly to the transformer from `unctx` that preserves async context
* after `await`. * after `await`.
* *
* @type {typeof import('unctx').TransformerOptions} * @type {typeof import('unctx/transform').TransformerOptions}
*/ */
asyncTransforms: { asyncTransforms: {
asyncFunctions: ['defineNuxtPlugin', 'defineNuxtRouteMiddleware'], asyncFunctions: ['defineNuxtPlugin', 'defineNuxtRouteMiddleware'],

View File

@ -30,7 +30,12 @@ export default defineUntypedSchema({
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
}, },
publicDir: { publicDir: {
$resolve: async (val, get) => val ?? resolve((await get('srcDir')), (await get('dir')).public) $resolve: async (val, get) => {
if (val) {
console.warn('Directly configuring the `vite.publicDir` option is not supported. Instead, set `dir.public`. You can read more in `https://nuxt.com/docs/api/configuration/nuxt-config#public`.')
}
return val ?? resolve((await get('srcDir')), (await get('dir')).public)
}
}, },
vue: { vue: {
isProduction: { isProduction: {

View File

@ -96,7 +96,7 @@ export interface NuxtOptions extends Omit<ConfigSchema, 'builder'> {
$schema: SchemaDefinition $schema: SchemaDefinition
} }
export interface ViteConfig extends ViteUserConfig { export interface ViteConfig extends Omit<ViteUserConfig, 'publicDir'> {
/** The path to the entrypoint for the Vite build. */ /** The path to the entrypoint for the Vite build. */
entry?: string entry?: string
/** /**
@ -126,6 +126,14 @@ export interface ViteConfig extends ViteUserConfig {
* Use environment variables or top level `server` options to configure Nuxt server. * Use environment variables or top level `server` options to configure Nuxt server.
*/ */
server?: Omit<ViteServerOptions, 'port' | 'host'> server?: Omit<ViteServerOptions, 'port' | 'host'>
/**
* Directly configuring the `vite.publicDir` option is not supported. Instead, set `dir.public`.
*
* You can read more in <https://nuxt.com/docs/api/configuration/nuxt-config#public>.
*
* @deprecated
*/
publicDir?: never
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@nuxt/test-utils", "name": "@nuxt/test-utils",
"version": "3.6.1", "version": "3.6.2",
"repository": "nuxt/nuxt", "repository": "nuxt/nuxt",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
@ -24,7 +24,7 @@
"dependencies": { "dependencies": {
"@nuxt/kit": "workspace:../kit", "@nuxt/kit": "workspace:../kit",
"@nuxt/schema": "workspace:../schema", "@nuxt/schema": "workspace:../schema",
"consola": "^3.2.2", "consola": "^3.2.3",
"defu": "^6.1.2", "defu": "^6.1.2",
"execa": "^7.1.1", "execa": "^7.1.1",
"get-port-please": "^3.0.1", "get-port-please": "^3.0.1",
@ -33,15 +33,15 @@
"ufo": "^1.1.2" "ufo": "^1.1.2"
}, },
"devDependencies": { "devDependencies": {
"@jest/globals": "29.5.0", "@jest/globals": "29.6.0",
"playwright": "1.35.1", "playwright": "1.35.1",
"unbuild": "latest", "unbuild": "latest",
"vitest": "0.32.4" "vitest": "0.33.0"
}, },
"peerDependencies": { "peerDependencies": {
"@jest/globals": "^29.5.0", "@jest/globals": "^29.5.0",
"playwright": "^1.34.3", "playwright": "^1.34.3",
"vitest": "^0.30.0 || ^0.31.0 || ^0.32.0", "vitest": "^0.30.0 || ^0.31.0 || ^0.32.0 || ^0.33.0",
"vue": "^3.3.4" "vue": "^3.3.4"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@nuxt/vite-builder", "name": "@nuxt/vite-builder",
"version": "3.6.1", "version": "3.6.2",
"repository": "nuxt/nuxt", "repository": "nuxt/nuxt",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
@ -19,6 +19,7 @@
}, },
"devDependencies": { "devDependencies": {
"@nuxt/schema": "workspace:../schema", "@nuxt/schema": "workspace:../schema",
"@types/clear": "0.1.2",
"@types/estree": "1.0.1", "@types/estree": "1.0.1",
"@types/fs-extra": "11.0.1", "@types/fs-extra": "11.0.1",
"unbuild": "latest", "unbuild": "latest",
@ -31,7 +32,7 @@
"@vitejs/plugin-vue-jsx": "^3.0.1", "@vitejs/plugin-vue-jsx": "^3.0.1",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
"clear": "^0.1.0", "clear": "^0.1.0",
"consola": "^3.2.2", "consola": "^3.2.3",
"cssnano": "^6.0.1", "cssnano": "^6.0.1",
"defu": "^6.1.2", "defu": "^6.1.2",
"esbuild": "^0.18.11", "esbuild": "^0.18.11",
@ -42,7 +43,7 @@
"get-port-please": "^3.0.1", "get-port-please": "^3.0.1",
"h3": "^1.7.1", "h3": "^1.7.1",
"knitwork": "^1.0.0", "knitwork": "^1.0.0",
"magic-string": "^0.30.0", "magic-string": "^0.30.1",
"mlly": "^1.4.0", "mlly": "^1.4.0",
"ohash": "^1.1.2", "ohash": "^1.1.2",
"pathe": "^1.1.1", "pathe": "^1.1.1",
@ -57,7 +58,7 @@
"ufo": "^1.1.2", "ufo": "^1.1.2",
"unplugin": "^1.3.2", "unplugin": "^1.3.2",
"vite": "~4.3.9", "vite": "~4.3.9",
"vite-node": "^0.32.4", "vite-node": "^0.33.0",
"vite-plugin-checker": "^0.6.1", "vite-plugin-checker": "^0.6.1",
"vue-bundle-renderer": "^1.0.3" "vue-bundle-renderer": "^1.0.3"
}, },

View File

@ -229,7 +229,7 @@ export async function initViteDevBundler (ctx: ViteBuildContext, onBuild: () =>
const viteServer = ctx.ssrServer! const viteServer = ctx.ssrServer!
const options: TransformOptions = { const options: TransformOptions = {
viteServer, viteServer,
isExternal: createIsExternal(viteServer, ctx.nuxt.options.rootDir) isExternal: createIsExternal(viteServer, ctx.nuxt.options.rootDir, ctx.nuxt.options.modulesDir)
} }
// Build and watch // Build and watch

View File

@ -224,7 +224,7 @@ class ScopedVarsCollector {
const NUXT_IMPORT_RE = /nuxt|#app|#imports/ const NUXT_IMPORT_RE = /nuxt|#app|#imports/
function detectImportNames (code: string, composableMeta: Record<string, { source?: string | RegExp }>) { export function detectImportNames (code: string, composableMeta: Record<string, { source?: string | RegExp }>) {
const imports = findStaticImports(code) const imports = findStaticImports(code)
const names = new Set<string>() const names = new Set<string>()
for (const i of imports) { for (const i of imports) {
@ -235,7 +235,7 @@ function detectImportNames (code: string, composableMeta: Record<string, { sourc
if (source && matchWithStringOrRegex(i.specifier, source)) { if (source && matchWithStringOrRegex(i.specifier, source)) {
return return
} }
names.add(namedImports![name]) names.add(name)
} }
const { namedImports, defaultImport, namespacedImport } = parseStaticImport(i) const { namedImports, defaultImport, namespacedImport } = parseStaticImport(i)

View File

@ -2,7 +2,7 @@ import type { ExternalsOptions } from 'externality'
import { ExternalsDefaults, isExternal } from 'externality' import { ExternalsDefaults, isExternal } from 'externality'
import type { ViteDevServer } from 'vite' import type { ViteDevServer } from 'vite'
export function createIsExternal (viteServer: ViteDevServer, rootDir: string) { export function createIsExternal (viteServer: ViteDevServer, rootDir: string, modulesDirs?: string[]) {
const externalOpts: ExternalsOptions = { const externalOpts: ExternalsOptions = {
inline: [ inline: [
/virtual:/, /virtual:/,
@ -15,6 +15,7 @@ export function createIsExternal (viteServer: ViteDevServer, rootDir: string) {
/node_modules/ /node_modules/
], ],
resolve: { resolve: {
modules: modulesDirs,
type: 'module', type: 'module',
extensions: ['.ts', '.js', '.json', '.vue', '.mjs', '.jsx', '.tsx', '.wasm'] extensions: ['.ts', '.js', '.json', '.vue', '.mjs', '.jsx', '.tsx', '.wasm']
} }

View File

@ -128,7 +128,7 @@ function createViteNodeApp (ctx: ViteBuildContext, invalidates: Set<string> = ne
web: [] web: []
} }
}) })
const isExternal = createIsExternal(viteServer, ctx.nuxt.options.rootDir) const isExternal = createIsExternal(viteServer, ctx.nuxt.options.rootDir, ctx.nuxt.options.modulesDir)
node.shouldExternalize = async (id: string) => { node.shouldExternalize = async (id: string) => {
const result = await isExternal(id) const result = await isExternal(id)
if (result?.external) { if (result?.external) {

Some files were not shown because too many files have changed in this diff Show More