Merge branch 'main' into docs/scripts

This commit is contained in:
Daniel Roe 2024-04-19 13:33:32 +03:00 committed by GitHub
commit 3d3d6f4c36
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
595 changed files with 19956 additions and 10624 deletions

View File

@ -2,7 +2,7 @@
// https://containers.dev/implementors/json_reference/
{
"name": "nuxt-devcontainer",
"dockerFile": "Dockerfile",
"build": { "dockerfile": "Dockerfile" },
"features": {},
"customizations": {
"vscode": {

168
.eslintrc
View File

@ -1,168 +0,0 @@
{
"$schema": "https://json.schemastore.org/eslintrc",
"ignorePatterns": [
"dist",
"public",
"node_modules",
"packages/schema/schema"
],
"globals": {
"NodeJS": true,
"$fetch": true
},
"plugins": ["jsdoc", "import", "unicorn", "no-only-tests"],
"extends": [
"plugin:jsdoc/recommended",
"@nuxt/eslint-config",
"plugin:import/typescript"
],
"rules": {
"sort-imports": [
"error",
{
"ignoreDeclarationSort": true
}
],
"no-only-tests/no-only-tests": "error",
"unicorn/prefer-node-protocol": "error",
"no-console": "warn",
"vue/one-component-per-file": "off",
"vue/require-default-prop": "off",
// Vue stylistic rules from `@antfu/eslint-config`
"vue/array-bracket-spacing": ["error", "never"],
"vue/arrow-spacing": ["error", { "after": true, "before": true }],
"vue/block-spacing": ["error", "always"],
"vue/block-tag-newline": [
"error",
{
"multiline": "always",
"singleline": "always"
}
],
"vue/brace-style": ["error", "stroustrup", { "allowSingleLine": true }],
"vue/comma-dangle": ["error", "always-multiline"],
"vue/comma-spacing": ["error", { "after": true, "before": false }],
"vue/comma-style": ["error", "last"],
"vue/html-comment-content-spacing": [
"error",
"always",
{
"exceptions": ["-"]
}
],
"vue/key-spacing": ["error", { "afterColon": true, "beforeColon": false }],
"vue/keyword-spacing": ["error", { "after": true, "before": true }],
"vue/object-curly-newline": "off",
"vue/object-curly-spacing": ["error", "always"],
"vue/object-property-newline": [
"error",
{ "allowMultiplePropertiesPerLine": true }
],
"vue/operator-linebreak": ["error", "before"],
"vue/padding-line-between-blocks": ["error", "always"],
"vue/quote-props": ["error", "consistent-as-needed"],
"vue/space-in-parens": ["error", "never"],
"vue/template-curly-spacing": "error",
"jsdoc/require-jsdoc": "off",
"jsdoc/require-param": "off",
"jsdoc/require-returns": "off",
"jsdoc/require-param-type": "off",
"import/order": [
"error",
{
"pathGroups": [
{
"pattern": "#vue-router",
"group": "external"
}
]
}
],
"import/no-restricted-paths": [
"error",
{
"zones": [
{
"from": "packages/nuxt/src/!(core)/**/*",
"target": "packages/nuxt/src/core",
"message": "core should not directly import from modules."
},
{
"from": "packages/nuxt/src/!(app)/**/*",
"target": "packages/nuxt/src/app",
"message": "app should not directly import from modules."
},
{
"from": "packages/nuxt/src/app/**/index.ts",
"target": "packages/nuxt/src",
"message": "should not import from barrel/index files"
},
{
"from": "packages/nitro",
"target": "packages/!(nitro)/**/*",
"message": "nitro should not directly import other packages."
}
]
}
],
"@typescript-eslint/consistent-type-imports": [
"error",
{
"disallowTypeAnnotations": false
}
],
"@typescript-eslint/ban-ts-comment": [
"error",
{
"ts-expect-error": "allow-with-description",
"ts-ignore": true
}
],
"@typescript-eslint/prefer-ts-expect-error": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"ignoreRestSiblings": true
}
],
"jsdoc/check-tag-names": [
"error",
{
"definedTags": ["__NO_SIDE_EFFECTS__"]
}
]
},
"overrides": [
{
"files": ["packages/schema/**"],
"rules": {
"jsdoc/valid-types": "off",
"jsdoc/check-tag-names": [
"error",
{
"definedTags": ["experimental"]
}
]
}
},
{
"files": ["packages/nuxt/src/app/**", "test/**", "**/runtime/**"],
"rules": {
"no-console": "off"
}
}
],
"settings": {
"jsdoc": {
"ignoreInternal": true,
"tagNamePreference": {
"warning": "warning",
"note": "note"
}
}
}
}

View File

@ -1,10 +1,10 @@
blank_issues_enabled: true
contact_links:
- name: 📚 Nuxt 3 Documentation
url: https://nuxt.com/docs/
url: https://nuxt.com/docs
about: Check the documentation for usage of Nuxt 3
- name: 📚 Nuxt 2 Documentation
url: https://v2.nuxt.com/
url: https://v2.nuxt.com
about: Check the documentation for usage of Nuxt 2
- name: 💬 Discussions
url: https://github.com/nuxt/nuxt/discussions

View File

@ -1,37 +1,19 @@
<!---
☝️ PR title should follow conventional commits (https://conventionalcommits.org)
Please carefully read the contribution docs before creating a pull request
👉 https://nuxt.com/docs/community/contribution
-->
### 🔗 Linked issue
<!-- Please ensure there is an open issue and mention its number as #123 -->
### ❓ Type of change
<!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply. -->
- [ ] 📖 Documentation (updates to the documentation, readme or JSdoc annotations)
- [ ] 🐞 Bug fix (a non-breaking change that fixes an issue)
- [ ] 👌 Enhancement (improving an existing functionality like performance)
- [ ] ✨ New feature (a non-breaking change that adds functionality)
- [ ] 🧹 Chore (updates to the build process or auxiliary tools and libraries)
- [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to change)
<!-- Please ensure there is an open issue and mention its number. For example, "resolves #123" -->
### 📚 Description
<!-- Describe your changes in detail -->
<!-- Why is this change required? What problem does it solve? -->
<!-- If it resolves an open issue, please link to the issue here. For example "Resolves #1337" -->
<!-- Describe your changes in detail. Why is this change required? What problem does it solve? -->
### 📝 Checklist
<!----------------------------------------------------------------------
Before creating the pull request, please make sure you do the following:
<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- Check that there isn't already a PR that solves the problem the same way. If you find a duplicate, please help us reviewing it.
- Read the contribution docs at https://nuxt.com/docs/community/contribution
- Ensure that PR title follows conventional commits (https://conventionalcommits.org)
- Update the corresponding documentation if needed.
- Include relevant tests that fail without this PR but pass with it.
- [ ] I have linked an issue or discussion.
- [ ] I have added tests (if possible).
- [ ] I have updated the documentation accordingly.
Thank you for contributing to Nuxt!
----------------------------------------------------------------------->

View File

@ -27,6 +27,6 @@ Please ensure that the reproduction is as **minimal** as possible. See more deta
You might also find these other articles interesting and/or helpful:
- [The Importance of Reproductions](https://antfu.me/posts/why-reproductions-are-required)
- [How to Generate a Minimal, Complete, and Verifiable Example](https://stackoverflow.com/help/mcve)
- [How to Generate a Minimal, Complete, and Verifiable Example](https://stackoverflow.com/help/minimal-reproducible-example)
</details>

View File

@ -19,7 +19,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"

View File

@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -26,9 +26,6 @@ jobs:
- name: Build (stub)
run: pnpm dev:prepare
- name: Lint (code)
run: pnpm lint:fix
- name: Test (unit)
run: pnpm test:unit -u
@ -52,4 +49,7 @@ jobs:
if: ${{ !contains(github.head_ref, 'renovate') }}
run: pnpm vitest run bundle -u
- name: Lint (code)
run: pnpm lint:fix
- uses: autofix-ci/action@ea32e3a12414e6d3183163c3424a7d7a8631ad84

View File

@ -15,8 +15,6 @@ env:
# 7 GiB by default on GitHub, setting to 6 GiB
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
NODE_OPTIONS: --max-old-space-size=6144
# install playwright binary manually (because pnpm only runs install script once)
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
# Remove default permissions of GITHUB_TOKEN for security
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
@ -33,7 +31,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -48,7 +46,7 @@ jobs:
run: pnpm build
- name: Run benchmarks
uses: CodSpeedHQ/action@5ef3186765fa3fafd8b2729b064025d19626050c # v2.0.3
uses: CodSpeedHQ/action@1dbf41f0ae41cebfe61e084e535aebe533409b4d # v2.3.0
with:
run: pnpm vitest bench
token: ${{ secrets.CODSPEED_TOKEN }}

36
.github/workflows/cache-cleanup.yml vendored Normal file
View File

@ -0,0 +1,36 @@
# From https://github.com/actions/cache/blob/main/tips-and-workarounds.md#force-deletion-of-caches-overriding-default-cache-eviction-policy
name: cache
on:
pull_request:
types:
- closed
jobs:
cleanup:
runs-on: ubuntu-latest
permissions:
# `actions:write` permission is required to delete caches
# See also: https://docs.github.com/en/rest/actions/cache?apiVersion=2022-11-28#delete-a-github-actions-cache-for-a-repository-using-a-cache-id
actions: write
contents: read
steps:
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
echo "Fetching list of cache keys"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge

View File

@ -1,4 +1,4 @@
name: Release
name: changelog
on:
push:
@ -15,7 +15,7 @@ concurrency:
cancel-in-progress: ${{ github.event_name != 'push' }}
jobs:
update-changelog:
update:
if: github.repository_owner == 'nuxt' && !contains(github.event.head_commit.message, 'v3.')
runs-on: ubuntu-latest
@ -24,7 +24,7 @@ jobs:
with:
fetch-depth: 0
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"

View File

@ -18,7 +18,7 @@ jobs:
steps:
# Cache lychee results (e.g. to avoid hitting rate limits)
- name: Restore lychee cache
uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
with:
path: .lycheecache
key: cache-lychee-${{ github.sha }}
@ -28,7 +28,7 @@ jobs:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Lychee link checker
uses: lycheeverse/lychee-action@8c9a282bef269f1ba1f727d1f79c5b8139bf3a5a # for v1.8.0
uses: lycheeverse/lychee-action@1e92115388e88fdc331019d99c8ab8dfe97ddd13 # for v1.8.0
with:
# arguments with file types to check
args: >-

View File

@ -20,8 +20,6 @@ env:
# 7 GiB by default on GitHub, setting to 6 GiB
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
NODE_OPTIONS: --max-old-space-size=6144
# install playwright binary manually (because pnpm only runs install script once)
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
# Remove default permissions of GITHUB_TOKEN for security
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
@ -39,7 +37,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -57,7 +55,7 @@ jobs:
run: pnpm build
- name: Cache dist
uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2
with:
retention-days: 3
name: dist
@ -76,7 +74,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -85,19 +83,19 @@ jobs:
run: pnpm install
- name: Initialize CodeQL
uses: github/codeql-action/init@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
uses: github/codeql-action/init@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
with:
languages: javascript
queries: +security-and-quality
- name: Restore dist cache
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
uses: actions/download-artifact@8caf195ad4b1dee92908e23f56eeb0696f1dd42d # v4.1.5
with:
name: dist
path: packages
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
uses: github/codeql-action/analyze@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
with:
category: "/language:javascript"
@ -115,7 +113,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -124,7 +122,7 @@ jobs:
run: pnpm install
- name: Restore dist cache
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
uses: actions/download-artifact@8caf195ad4b1dee92908e23f56eeb0696f1dd42d # v4.1.5
with:
name: dist
path: packages
@ -134,6 +132,9 @@ jobs:
env:
MODULE_RESOLUTION: ${{ matrix.module }}
- name: Typecheck (docs)
run: pnpm typecheck:docs
lint:
# autofix workflow will be triggered instead for PRs
if: github.event_name == 'push'
@ -143,7 +144,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -167,7 +168,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -209,7 +210,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: ${{ matrix.node }}
cache: "pnpm"
@ -217,34 +218,11 @@ jobs:
- name: Install dependencies
run: pnpm install
# Install playwright's binary under custom directory to cache
- name: (non-windows) Set Playwright path and Get playwright version
if: runner.os != 'Windows'
run: |
echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV
PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright | jq --raw-output '.[0].unsavedDependencies["playwright"].version')"
echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
- name: (windows) Set Playwright path and Get playwright version
if: runner.os == 'Windows'
run: |
echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV
$env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright | jq --raw-output '.[0].unsavedDependencies[\"playwright\"].version')"
echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV
- name: Cache Playwright's binary
uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
with:
key: ${{ runner.os }}-playwright-bin-v1-${{ env.PLAYWRIGHT_VERSION }}
path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
restore-keys: |
${{ runner.os }}-playwright-bin-v1-
- name: Install Playwright
run: pnpm playwright-core install chromium
- name: Restore dist cache
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
uses: actions/download-artifact@8caf195ad4b1dee92908e23f56eeb0696f1dd42d # v4.1.5
with:
name: dist
path: packages
@ -258,7 +236,7 @@ jobs:
TEST_CONTEXT: ${{ matrix.context }}
SKIP_BUNDLE_SIZE: ${{ github.event_name != 'push' || matrix.env == 'dev' || matrix.builder == 'webpack' || matrix.context == 'default' || runner.os == 'Windows' }}
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
- uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # v4.3.0
if: github.event_name != 'push' && matrix.env == 'built' && matrix.builder == 'vite' && matrix.context == 'default' && matrix.os == 'ubuntu-latest' && matrix.manifest == 'manifest-on'
with:
token: ${{ secrets.CODECOV_TOKEN }}
@ -284,7 +262,7 @@ jobs:
with:
fetch-depth: 0
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -293,7 +271,7 @@ jobs:
run: pnpm install
- name: Restore dist cache
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
uses: actions/download-artifact@8caf195ad4b1dee92908e23f56eeb0696f1dd42d # v4.1.5
with:
name: dist
path: packages
@ -323,7 +301,7 @@ jobs:
with:
fetch-depth: 0
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -332,7 +310,7 @@ jobs:
run: pnpm install
- name: Restore dist cache
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
uses: actions/download-artifact@8caf195ad4b1dee92908e23f56eeb0696f1dd42d # v4.1.5
with:
name: dist
path: packages

View File

@ -19,4 +19,4 @@ jobs:
- name: 'Checkout Repository'
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: 'Dependency Review'
uses: actions/dependency-review-action@4901385134134e04cec5fbe5ddfe3b2c5bd5d976 # v4.0.0
uses: actions/dependency-review-action@5bbc3ba658137598168acb2ab73b21c432dd411b # v4.2.5

View File

@ -22,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"
@ -32,3 +32,9 @@ jobs:
- name: Lint (docs)
run: pnpm lint:docs
- name: Build Nuxt
run: pnpm build
- name: Typecheck (docs)
run: pnpm typecheck:docs

View File

@ -6,34 +6,68 @@ on:
- opened
branches:
- main
- 2.x
jobs:
add-pr-label:
name: Add PR label
add-pr-labels:
name: Add PR labels
runs-on: ubuntu-latest
permissions:
pull-requests: write
if: github.repository == 'nuxt/nuxt'
steps:
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
env:
PULL_REQUEST_TITLE: ${{ github.event.pull_request.title }}
with:
script: |
const baseName = "${{ github.event.pull_request.base.label }}"
const PRNumber = "${{ github.event.pull_request.number }}"
const labelsToAdd = []
if(baseName === "nuxt:2.x") {
const pullRequest = {
number: ${{ github.event.pull_request.number }},
title: process.env.PULL_REQUEST_TITLE,
labelsNames: ${{ toJson(github.event.pull_request.labels.*.name) }}
}
// Select label based on the name of the base branch
const baseBranchLabelName = '3.x'
if (!pullRequest.labelsNames.includes(baseBranchLabelName)) {
labelsToAdd.push(baseBranchLabelName)
}
// Select label based on the type in PR title
const pullRequestTypeToLabelName = {
chore: 'chore',
ci: 'chore',
docs: 'documentation',
feat: 'enhancement',
fix: 'bug',
perf: 'performance',
refactor: 'refactor',
test: 'test'
}
for (const [pullRequestType, labelName] of Object.entries(
pullRequestTypeToLabelName
)) {
if (
pullRequest.title.startsWith(pullRequestType) &&
!pullRequest.labelsNames.includes(
pullRequestTypeToLabelName[pullRequestType]
)
) {
labelsToAdd.push(labelName)
break
}
}
// Add selected labels
if (labelsToAdd.length > 0) {
github.rest.issues.addLabels({
issue_number: PRNumber,
issue_number: pullRequest.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ["2.x"]
})
} else if(baseName === "nuxt:main") {
github.rest.issues.addLabels({
issue_number: PRNumber,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ["3.x"]
labels: labelsToAdd
})
}

View File

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: repository dispatch
uses: peter-evans/repository-dispatch@bf47d102fdb849e755b0b0023ea3e81a44b6f570 #v2.1.2
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0
with:
token: ${{ secrets.BRIDGE_GITHUB_TOKEN }}
repository: ${{ matrix.repo }}

View File

@ -27,7 +27,7 @@ jobs:
fetch-depth: 0 # All history
- name: fetch tags
run: git fetch --depth=1 origin "+refs/tags/*:refs/tags/*"
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 18
registry-url: 'https://registry.npmjs.org'

View File

@ -1,4 +1,4 @@
name: release
name: release-pr
on:
issue_comment:
@ -22,7 +22,7 @@ jobs:
steps:
- name: Ensure action is by maintainer
uses: octokit/request-action@89697eb6635e52c6e1e5559f15b5c91ba5100cb0 # v2.1.9
uses: octokit/request-action@21d174fc38ff59af9cf4d7e07347d29df6dbaa99 # v2.3.0
id: check_role
with:
route: GET /repos/nuxt/nuxt/collaborators/${{ github.event.comment.user.login }}
@ -35,7 +35,7 @@ jobs:
fetch-depth: 0
- run: corepack enable
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: "pnpm"

40
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: release
on:
push:
tags:
- "v*"
# Remove default permissions of GITHUB_TOKEN for security
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions: {}
jobs:
release:
if: github.repository == 'nuxt/nuxt' && startsWith(github.event.head_commit.message, 'v3.')
permissions:
id-token: write
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 0
- run: corepack enable
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
registry-url: "https://registry.npmjs.org/"
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Build (stub)
run: pnpm dev:prepare
- name: Release
run: ./scripts/release.sh
env:
NODE_AUTH_TOKEN: ${{secrets.RELEASE_NODE_AUTH_TOKEN}}
NPM_CONFIG_PROVENANCE: true

View File

@ -58,7 +58,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2
with:
name: SARIF file
path: results.sarif
@ -66,6 +66,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1
with:
sarif_file: results.sarif

2
.gitignore vendored
View File

@ -73,3 +73,5 @@ Temporary Items
fixtures-temp
.pnpm-store
eslint-typegen.d.ts
.eslintcache

1
.npmrc
View File

@ -1,3 +1,2 @@
shamefully-hoist=true
strict-peer-dependencies=false
shell-emulator=true

View File

@ -13,16 +13,32 @@
Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.
It provides a number of features that make it easy to build fast, SEO-friendly, and scalable web applications, including:
- Server-side rendering, Static Site Generation or Hybrid Rendering
- Automatic routing with code-splitting
- State management
- SEO Optimization
- Auto imports
- Extensible with [180+ modules](https://nuxt.com/modules)
- Server-side rendering, Static Site Generation, Hybrid Rendering and Edge-Side Rendering
- Automatic routing with code-splitting and pre-fetching
- Data fetching and state management
- SEO Optimization and Meta tags definition
- Auto imports of components, composables and utils
- TypeScript with zero configuration
- Go fullstack with our server/ directory
- Extensible with [200+ modules](https://nuxt.com/modules)
- Deployment to a variety of [hosting platforms](https://nuxt.com/deploy)
- ...[and much more](https://nuxt.com) 🚀
## Getting Started
### Table of Contents
- 🚀 [Getting Started](#getting-started)
- 💻 [ Vue Development](#vue-development)
- 📖 [Documentation](#documentation)
- 🧩 [Modules](#modules)
- ❤️ [Contribute](#contribute)
- 🏠 [Local Development](#local-development)
- ⛰️ [Nuxt 2](#nuxt-2)
- 🔗 [Follow us](#follow-us)
- ⚖️ [License](#license)
---
## <a name="getting-started">🚀 Getting Started</a>
Use the following command to create a new starter project. This will create a starter project with all the necessary files and dependencies:
@ -30,16 +46,17 @@ Use the following command to create a new starter project. This will create a st
npx nuxi@latest init <my-project>
```
Discover also [nuxt.new](https://nuxt.new): Open a Nuxt starter on CodeSandbox, StackBlitz or locally to get up and running in a few seconds.
> [!TIP]
> Discover also [nuxt.new](https://nuxt.new): Open a Nuxt starter on CodeSandbox, StackBlitz or locally to get up and running in a few seconds.
## Vue Development
## <a name="vue-development">💻 Vue Development</a>
Simple, intuitive and powerful, Nuxt lets you write Vue components in a way that makes sense. Every repetitive task is automated, so you can focus on writing your full-stack Vue application with confidence.
Example of an `app.vue`:
```vue
<script setup>
<script setup lang="ts">
useSeoMeta({
title: 'Meet Nuxt',
description: 'The Intuitive Vue Framework.'
@ -54,7 +71,7 @@ useSeoMeta({
</div>
</template>
<style>
<style scoped>
#app {
background-color: #020420;
color: #00DC82;
@ -62,38 +79,37 @@ useSeoMeta({
</style>
```
## Documentation
## <a name="documentation">📖 Documentation</a>
We highly recommend you take a look at the [Nuxt documentation](https://nuxt.com/docs) to level up. Its a great resource for learning more about the framework. It covers everything from getting started to advanced topics.
## Modules
## <a name="modules">🧩 Modules</a>
Discover our [list of modules](https://nuxt.com/modules) to supercharge your Nuxt project, created by the Nuxt team and community.
## Contribute
## <a name="contribute">❤️ Contribute</a>
We invite you to contribute and help improve Nuxt 💚
Here are a few ways you can get involved:
- **Reporting Bugs:** If you come across any bugs or issues, please check out the [reporting bugs guide](https://nuxt.com/docs/community/reporting-bugs) to learn how to submit a bug report.
- **Suggestions:** Have ideas to enhance Nuxt? We'd love to hear them! Check out the [contribution guide](https://nuxt.com/docs/community/contribution#creating-an-issue) to share your suggestions.
- **Suggestions:** Have ideas to enhance Nuxt? We'd love to hear them! Check out the [contribution guide](https://nuxt.com/docs/community/contribution) to share your suggestions.
- **Questions:** If you have questions or need assistance, the [getting help guide](https://nuxt.com/docs/community/getting-help) provides resources to help you out.
## Local Development
## <a name="local-development">🏠 Local Development</a>
Follow the docs to [Set Up Your Local Development Environment](https://nuxt.com/docs/community/framework-contribution#setup) to contribute to the framework and documentation.
## Nuxt 2
## <a name="nuxt-2">⛰️ Nuxt 2</a>
You can find the code for Nuxt 2 on the [`2.x` branch](https://github.com/nuxt/nuxt/tree/2.x) and the documentation at [v2.nuxt.com](https://v2.nuxt.com).
## Follow us
## <a name="follow-us">🔗 Follow us</a>
<p valign="center">
<a href="https://chat.nuxt.dev"><img width="20px" src="./.github/assets/discord.svg" alt="Discord"></a>&nbsp;&nbsp;<a href="https://twitter.nuxt.dev"><img width="20px" src="./.github/assets/twitter.svg" alt="Twitter"></a>&nbsp;&nbsp;<a href="https://github.nuxt.dev"><img width="20px" src="./.github/assets/github.svg" alt="GitHub"></a>
</p>
## License
## <a name="license">⚖️ License</a>
[MIT](./LICENSE)

View File

@ -6,7 +6,7 @@ navigation.icon: i-ph-cloud-duotone
A Nuxt application can be deployed on a Node.js server, pre-rendered for static hosting, or deployed to serverless or edge (CDN) environments.
::callout
::tip
If you are looking for a list of cloud providers that support Nuxt 3, see the [Hosting providers](/deploy) section.
::
@ -38,9 +38,9 @@ It respects the following runtime environment variables:
[PM2](https://pm2.keymetrics.io/) (Process Manager 2) is a fast and easy solution for hosting your Nuxt application on your server or VM.
To use `pm2`, use an `ecosystem.config.js`:
To use `pm2`, use an `ecosystem.config.cjs`:
```ts [ecosystem.config.js]
```ts [ecosystem.config.cjs]
module.exports = {
apps: [
{
@ -98,8 +98,8 @@ Read more about the `nuxi generate` command.
You can manually specify routes that [Nitro](/docs/guide/concepts/server-engine) will fetch and pre-render during the build or ignore routes that you don't want to pre-render like `/dynamic` in the `nuxt.config` file:
```ts [nuxt.config.ts]
defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
nitro: {
prerender: {
routes: ['/user/1', '/user/2'],
@ -111,8 +111,8 @@ defineNuxtConfig({
You can combine this with the `crawlLinks` option to pre-render a set of routes that the crawler can't discover like your `/sitemap.xml` or `/robots.txt`:
```ts [nuxt.config.ts]
defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
nitro: {
prerender: {
crawlLinks: true,
@ -132,7 +132,7 @@ Read more about pre-rendering in the Nitro documentation.
If you don't want to pre-render your routes, another way of using static hosting is to set the `ssr` property to `false` in the `nuxt.config` file. The `nuxi generate` command will then output an `.output/public/index.html` entrypoint and JavaScript bundles like a classic client-side Vue.js application.
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
ssr: false
})
@ -150,7 +150,7 @@ In addition to Node.js servers and static hosting services, a Nuxt 3 project can
You can explicitly set the desired preset in the [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config) file:
```js [nuxt.config.ts]
```js twoslash [nuxt.config.ts]
export default defineNuxtConfig({
nitro: {
preset: 'node-server'

View File

@ -4,7 +4,7 @@ description: How to test your Nuxt application.
navigation.icon: i-ph-check-circle-duotone
---
::callout
::tip
If you are a module author, you can find more specific information in the [Module Author's guide](/docs/guide/going-further/modules#testing).
::
@ -15,8 +15,8 @@ Nuxt offers first-class support for end-to-end and unit testing of your Nuxt app
In order to allow you to manage your other testing dependencies, `@nuxt/test-utils` ships with various optional peer dependencies. For example:
- you can choose between `happy-dom` and `jsdom` for a runtime Nuxt environment
- you can choose between `vitest` and `jest` for end-to-end test runners
- `playwright-core` is only required if you wish to use the built-in browser testing utilities
- you can choose between `vitest`, `cucumber`, `jest` and `playwright` for end-to-end test runners
- `playwright-core` is only required if you wish to use the built-in browser testing utilities (and are not using `@playwright/test` as your test runner)
::code-group
```bash [yarn]
@ -41,7 +41,7 @@ We currently ship an environment for unit testing code that needs a [Nuxt](https
1. Add `@nuxt/test-utils/module` to your `nuxt.config` file (optional). It adds a Vitest integration to your Nuxt DevTools which supports running your unit tests in development.
```js
```ts twoslash
export default defineNuxtConfig({
modules: [
'@nuxt/test-utils/module'
@ -51,24 +51,29 @@ We currently ship an environment for unit testing code that needs a [Nuxt](https
2. Create a `vitest.config.ts` with the following content:
```ts
```ts twoslash
import { defineVitestConfig } from '@nuxt/test-utils/config'
export default defineVitestConfig({
// any custom Vitest config you require
})
```
::tip
When importing `@nuxt/test-utils` in your vitest config, It is necessary to have `type: "module"` specified in your `package.json` or rename your vitest config file appropriatly.
> ie. `vitest.config.m{ts,js}`.
::
### Using a Nuxt Runtime Environment
By default, `@nuxt/test-utils` will not change your default Vitest environment, so you can do fine-grained opt-in and run Nuxt tests together with other unit tests.
You can opt in to a Nuxt environment by adding `.nuxt.` to the test file's name (for example, `my-file.nuxt.test.ts` or `my-file.nuxt.spec.ts`) or by adding `@vitest-environment nuxt` as a comment directly in the test file.
```js
```ts twoslash
// @vitest-environment nuxt
import { test } from 'vitest'
test('my test', () => {
// ... test with Nuxt environment!
})
@ -76,7 +81,7 @@ You can opt in to a Nuxt environment by adding `.nuxt.` to the test file's name
You can alternatively set `environment: 'nuxt'` in your Vitest configuration to enable the Nuxt environment for **all tests**.
```js
```ts twoslash
// vitest.config.ts
import { fileURLToPath } from 'node:url'
import { defineVitestConfig } from '@nuxt/test-utils/config'
@ -88,6 +93,7 @@ export default defineVitestConfig({
// environmentOptions: {
// nuxt: {
// rootDir: fileURLToPath(new URL('./playground', import.meta.url)),
// domEnvironment: 'happy-dom', // 'happy-dom' (default) or 'jsdom'
// overrides: {
// // other Nuxt config you want to pass
// }
@ -99,7 +105,7 @@ export default defineVitestConfig({
If you have set `environment: 'nuxt'` by default, you can then opt _out_ of the [default environment](https://vitest.dev/guide/environment.html#test-environment) per test file as needed.
```js
```ts twoslash
// @vitest-environment node
import { test } from 'vitest'
@ -108,12 +114,10 @@ test('my test', () => {
})
```
::callout{icon="i-ph-warning-duotone" color="amber"}
::warning
When you run your tests within the Nuxt environment, they will be running in a [`happy-dom`](https://github.com/capricorn86/happy-dom) or [`jsdom`](https://github.com/jsdom/jsdom) environment. Before your tests run, a global Nuxt app will be initialized (including, for example, running any plugins or code you've defined in your `app.vue`).
This means you should take particular care not to mutate the global state in your tests (or, if you need to, to reset it afterwards).
::
### 🎭 Built-In Mocks
@ -130,7 +134,9 @@ Default `false`, uses [`fake-indexeddb`](https://github.com/dumbmatter/fakeIndex
These can be configured in the `environmentOptions` section of your `vitest.config.ts` file:
```js
```ts twoslash
import { defineVitestConfig } from '@nuxt/test-utils/config'
export default defineVitestConfig({
test: {
environmentOptions: {
@ -143,7 +149,7 @@ export default defineVitestConfig({
}
}
})
````
```
### 🛠️ Helpers
@ -153,8 +159,15 @@ export default defineVitestConfig({
`mountSuspended` allows you to mount any Vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins. For example:
```ts
```ts twoslash
import type { Component } from 'vue'
import { it, expect } from 'vitest'
declare const SomeComponent: Component
declare const App: Component
// ---cut---
// tests/components/SomeComponents.nuxt.spec.ts
import { mountSuspended } from '@nuxt/test-utils/runtime'
it('can mount some component', async () => {
const component = await mountSuspended(SomeComponent)
expect(component.text()).toMatchInlineSnapshot(
@ -185,28 +198,40 @@ The passed in component will be rendered inside a `<div id="test-wrapper"></div>
Examples:
```ts
```ts twoslash
import type { Component } from 'vue'
import { it, expect } from 'vitest'
declare const SomeComponent: Component
declare const App: Component
// ---cut---
// tests/components/SomeComponents.nuxt.spec.ts
import { renderSuspended } from '@nuxt/test-utils/runtime'
import { screen } from '@testing-library/vue'
it('can render some component', async () => {
await renderSuspended(SomeComponent)
expect(screen.getByText('This is an auto-imported component')).toBeDefined()
await renderSuspended(SomeComponent)
expect(screen.getByText('This is an auto-imported component')).toBeDefined()
})
```
```ts twoslash
import type { Component } from 'vue'
import { it, expect } from 'vitest'
declare const SomeComponent: Component
declare const App: Component
// ---cut---
// tests/App.nuxt.spec.ts
import { renderSuspended } from '@nuxt/test-utils/runtime'
it('can also render an app', async () => {
const html = await renderSuspended(App, { route: '/test' })
expect(html()).toMatchInlineSnapshot(`
"<div id="test-wrapper">
<div>This is an auto-imported component</div>
<div> I am a global component </div>
<div>Index page</div><a href="/test"> Test link </a>
</div>"
`)
const html = await renderSuspended(App, { route: '/test' })
expect(html).toMatchInlineSnapshot(`
"<div id="test-wrapper">
<div>This is an auto-imported component</div>
<div> I am a global component </div>
<div>Index page</div><a href="/test"> Test link </a>
</div>"
`)
})
```
@ -214,7 +239,7 @@ it('can also render an app', async () => {
`mockNuxtImport` allows you to mock Nuxt's auto import functionality. For example, to mock `useStorage`, you can do so like this:
```ts
```ts twoslash
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport('useStorage', () => {
@ -230,7 +255,7 @@ mockNuxtImport('useStorage', () => {
If you need to mock a Nuxt import and provide different implementations between tests, you can do it by creating and exposing your mocks using [`vi.hoisted`](https://vitest.dev/api/vi.html#vi-hoisted), and then use those mocks in `mockNuxtImport`. You then have access to the mocked imports, and can change the implementation between tests. Be careful to [restore mocks](https://vitest.dev/api/mock.html#mockrestore) before or after each test to undo mock state changes between runs.
```ts
```ts twoslash
import { vi } from 'vitest'
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
@ -249,7 +274,7 @@ mockNuxtImport('useStorage', () => {
// Then, inside a test
useStorageMock.mockImplementation(() => {
return { value: 'something else' }
})
})
```
#### `mockComponent`
@ -260,7 +285,7 @@ The second argument is a factory function that returns the mocked component.
For example, to mock `MyComponent`, you can:
```ts
```ts twoslash
import { mockComponent } from '@nuxt/test-utils/runtime'
mockComponent('MyComponent', {
@ -275,11 +300,11 @@ mockComponent('MyComponent', {
// relative path or alias also works
mockComponent('~/components/my-component.vue', async () => {
// or a factory function
return {
return defineComponent({
setup(props) {
// ...
}
}
})
})
// or you can use SFC for redirecting to a mock component
@ -290,16 +315,18 @@ mockComponent('MyComponent', () => import('./MockComponent.vue'))
> **Note**: You can't reference local variables in the factory function since they are hoisted. If you need to access Vue APIs or other variables, you need to import them in your factory function.
```ts
```ts twoslash
import { mockComponent } from '@nuxt/test-utils/runtime'
mockComponent('MyComponent', async () => {
const { ref, h } = await import('vue')
return {
return defineComponent({
setup(props) {
const counter = ref(0)
return () => h('div', null, counter.value)
}
}
})
})
```
@ -312,7 +339,7 @@ The second argument is a factory function that returns the mocked data.
For example, to mock `/test/` endpoint, you can do:
```ts
```ts twoslash
import { registerEndpoint } from '@nuxt/test-utils/runtime'
registerEndpoint("/test/", () => ({
@ -322,7 +349,7 @@ registerEndpoint("/test/", () => ({
By default, your request will be made using the `GET` method. You may use another method by setting an object as the second argument instead of a function.
```ts
```ts twoslash
import { registerEndpoint } from '@nuxt/test-utils/runtime'
registerEndpoint("/test/", {
@ -341,7 +368,7 @@ If you would like to use both the end-to-end and unit testing functionality of `
`app.nuxt.spec.ts`
```ts
```ts twoslash
import { mockNuxtImport } from "@nuxt/test-utils/runtime"
mockNuxtImport('useStorage', () => {
@ -354,7 +381,7 @@ mockNuxtImport('useStorage', () => {
`app.e2e.spec.ts`
```ts
```ts twoslash
import { setup, $fetch } from '@nuxt/test-utils/e2e'
await setup({
@ -366,13 +393,13 @@ await setup({
## End-To-End Testing
For end-to-end testing, we support [Vitest](https://github.com/vitest-dev/vitest) and [Jest](https://jestjs.io) as test runners.
For end-to-end testing, we support [Vitest](https://github.com/vitest-dev/vitest), [Jest](https://jestjs.io), [Cucumber](https://cucumber.io/) and [Playwright](https://playwright.dev/) as test runners.
### Setup
In each `describe` block where you are taking advantage of the `@nuxt/test-utils/e2e` helper methods, you will need to set up the test context before beginning.
```ts [test/my-test.spec.ts]
```ts twoslash [test/my-test.spec.ts]
import { describe, test } from 'vitest'
import { setup, $fetch } from '@nuxt/test-utils/e2e'
@ -432,7 +459,7 @@ Please use the options below for the `setup` method.
- `type`: The type of browser to launch - either `chromium`, `firefox` or `webkit`
- `launch`: `object` of options that will be passed to playwright when launching the browser. See [full API reference](https://playwright.dev/docs/api/class-browsertype#browser-type-launch).
- `runner`: Specify the runner for the test suite. Currently, [Vitest](https://vitest.dev) is recommended.
- Type: `'vitest' | 'jest'`
- Type: `'vitest' | 'jest' | 'cucumber'`
- Default: `'vitest'`
### APIs
@ -441,7 +468,7 @@ Please use the options below for the `setup` method.
Get the HTML of a server-rendered page.
```ts
```ts twoslash
import { $fetch } from '@nuxt/test-utils/e2e'
const html = await $fetch('/')
@ -451,7 +478,7 @@ const html = await $fetch('/')
Get the response of a server-rendered page.
```ts
```ts twoslash
import { fetch } from '@nuxt/test-utils/e2e'
const res = await fetch('/')
@ -462,7 +489,7 @@ const { body, headers } = res
Get the full URL for a given page (including the port the test server is running on.)
```ts
```ts twoslash
import { url } from '@nuxt/test-utils/e2e'
const pageUrl = url('/page')
@ -471,15 +498,82 @@ const pageUrl = url('/page')
### Testing in a Browser
We provide built-in support using Playwright within `@nuxt/test-utils`, but you can also use other test runners for end-to-end browser testing.
We provide built-in support using Playwright within `@nuxt/test-utils`, either programmatically or via the Playwright test runner.
#### `createPage(url)`
You can create a configured Playwright browser instance, and (optionally) point it at a path from the running server. You can find out more about the API methods available from [in the Playwright documentation](https://playwright.dev/docs/api/class-page).
Within `vitest`, `jest` or `cucumber`, you can create a configured Playwright browser instance with `createPage`, and (optionally) point it at a path from the running server. You can find out more about the API methods available from [in the Playwright documentation](https://playwright.dev/docs/api/class-page).
```ts
```ts twoslash
import { createPage } from '@nuxt/test-utils/e2e'
const page = await createPage('/page')
// you can access all the Playwright APIs from the `page` variable
```
#### Testing with Playwright Test Runner
We also provide first-class support for testing Nuxt within [the Playwright test runner](https://playwright.dev/docs/intro).
::code-group
```bash [yarn]
yarn add --dev @playwright/test @nuxt/test-utils
```
```bash [npm]
npm i --save-dev @playwright/test @nuxt/test-utils
```
```bash [pnpm]
pnpm add -D @playwright/test @nuxt/test-utils
```
```bash [bun]
bun add --dev @playwright/test @nuxt/test-utils
```
::
You can provide global Nuxt configuration, with the same configuration details as the `setup()` function mentioned earlier in this section.
```ts [playwright.config.ts]
import { fileURLToPath } from 'node:url'
import { defineConfig, devices } from '@playwright/test'
import type { ConfigOptions } from '@nuxt/test-utils/playwright'
export default defineConfig<ConfigOptions>({
use: {
nuxt: {
rootDir: fileURLToPath(new URL('.', import.meta.url))
}
},
// ...
})
```
::read-more{title="See full example config" to="https://github.com/nuxt/test-utils/blob/main/examples/app-playwright/playwright.config.ts" target="_blank"}
::
Your test file should then use `expect` and `test` directly from `@nuxt/test-utils/playwright`:
```ts [tests/example.test.ts]
import { expect, test } from '@nuxt/test-utils/playwright'
test('test', async ({ page, goto }) => {
await goto('/', { waitUntil: 'hydration' })
await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!')
})
```
You can alternatively configure your Nuxt server directly within your test file:
```ts [tests/example.test.ts]
import { expect, test } from '@nuxt/test-utils/playwright'
test.use({
nuxt: {
rootDir: fileURLToPath(new URL('..', import.meta.url))
}
})
test('test', async ({ page, goto }) => {
await goto('/', { waitUntil: 'hydration' })
await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!')
})
```

View File

@ -22,25 +22,14 @@ Start with one of our starters and themes directly by opening [nuxt.new](https:/
#### Prerequisites
- **Node.js** - [`v18.0.0`](https://nodejs.org/en) or newer
- **Text editor** - We recommend [Visual Studio Code](https://code.visualstudio.com/) with the [Volar Extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
- **Text editor** - We recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar)
- **Terminal** - In order to run Nuxt commands
::callout
::note
::details
:summary[Additional notes for an optimal setup:]
- **Node.js**: Make sure to use an even numbered version (18, 20, etc)
- **Nuxtr**: Install the community-developed [Nuxtr extension](https://marketplace.visualstudio.com/items?itemName=Nuxtr.nuxtr-vscode)
- **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`](/docs/guide/directory-structure/nuxt-config) file:
```ts [nuxt.config.ts]
export default defineNuxtConfig({
typescript: {
shim: false
}
})
```
::
::
@ -74,33 +63,6 @@ Or change directory into your new project from your terminal:
cd <project-name>
```
Install the dependencies:
::code-group
```bash [yarn]
yarn install
```
```bash [npm]
npm install
```
```bash [pnpm]
pnpm install
```
```bash [bun]
bun install
```
::
::callout
If you are using Yarn 2+ (Berry), add `nodeLinker: node-modules` to your `.yarnrc.yml` file.
[You can follow this issue status here](https://github.com/nuxt/nuxt/issues/22861)
::
## Development Server
Now you'll be able to start your Nuxt app in development mode:
@ -124,7 +86,7 @@ bun run dev -o
```
::
::callout{icon="i-ph-check-circle-duotone"}
::tip{icon="i-ph-check-circle-duotone"}
Well done! A browser window should automatically open for <http://localhost:3000>.
::

View File

@ -13,7 +13,7 @@ The [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config) file is loca
A minimal configuration file exports the `defineNuxtConfig` function containing an object with your configuration. The `defineNuxtConfig` helper is globally available without import.
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
// My Nuxt config
})
@ -25,7 +25,7 @@ This file will often be mentioned in the documentation, for example to add custo
Every option is described in the **Configuration Reference**.
::
::callout
::note
You don't have to use TypeScript to build an application with Nuxt. However, it is strongly recommended to use the `.ts` extension for the `nuxt.config` file. This way you can benefit from hints in your IDE to avoid typos and mistakes while editing your configuration.
::
@ -33,7 +33,7 @@ You don't have to use TypeScript to build an application with Nuxt. However, it
You can configure fully typed, per-environment overrides in your nuxt.config
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
$production: {
routeRules: {
@ -46,7 +46,7 @@ export default defineNuxtConfig({
})
```
::callout
::note
If you're authoring layers, you can also use the `$meta` key to provide metadata that you or the consumers of your layer might use.
::
@ -58,7 +58,7 @@ Those values should be defined in `nuxt.config` and can be overridden using envi
::code-group
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
runtimeConfig: {
// The private keys which are only available server-side
@ -137,23 +137,23 @@ Non primitive JS types | ❌ No | ✅ Yes
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
|----------------------------------------------|---------------------------|-------------------------
| [Nitro](https://nitro.unjs.io) | ~~`nitro.config.ts`~~ | Use [`nitro`](/docs/api/nuxt-config#nitro) key in `nuxt.config`
| [PostCSS](https://postcss.org) | ~~`postcss.config.js`~~ | Use [`postcss`](/docs/api/nuxt-config#postcss) key in `nuxt.config`
| [Vite](https://vitejs.dev) | ~~`vite.config.ts`~~ | Use [`vite`](/docs/api/nuxt-config#vite) key in `nuxt.config`
| [webpack](https://webpack.js.org) | ~~`webpack.config.ts`~~ | Use [`webpack`](/docs/api/nuxt-config#webpack-1) key in `nuxt.config`
Name | Config File | How To Configure
---------------------------------------------|---------------------------|-------------------------
[Nitro](https://nitro.unjs.io) | ~~`nitro.config.ts`~~ | Use [`nitro`](/docs/api/nuxt-config#nitro) key in `nuxt.config`
[PostCSS](https://postcss.org) | ~~`postcss.config.js`~~ | Use [`postcss`](/docs/api/nuxt-config#postcss) key in `nuxt.config`
[Vite](https://vitejs.dev) | ~~`vite.config.ts`~~ | Use [`vite`](/docs/api/nuxt-config#vite) key in `nuxt.config`
[webpack](https://webpack.js.org) | ~~`webpack.config.ts`~~ | Use [`webpack`](/docs/api/nuxt-config#webpack-1) key in `nuxt.config`
Here is a list of other common config files:
Name | Config File | How To Configure
|----------------------------------------------|-------------------------|--------------------------
| [TypeScript](https://www.typescriptlang.org) | `tsconfig.json` | [More Info](/docs/guide/concepts/typescript#nuxttsconfigjson)
| [ESLint](https://eslint.org) | `.eslintrc.js` | [More Info](https://eslint.org/docs/latest/use/configure/configuration-files)
| [Prettier](https://prettier.io) | `.prettierrc.json` | [More Info](https://prettier.io/docs/en/configuration.html)
| [Stylelint](https://stylelint.io) | `.stylelintrc.json` | [More Info](https://stylelint.io/user-guide/configure)
| [TailwindCSS](https://tailwindcss.com) | `tailwind.config.js` | [More Info](https://tailwindcss.nuxtjs.org/tailwind/config)
| [Vitest](https://vitest.dev) | `vitest.config.ts` | [More Info](https://vitest.dev/config)
Name | Config File | How To Configure
---------------------------------------------|-------------------------|--------------------------
[TypeScript](https://www.typescriptlang.org) | `tsconfig.json` | [More Info](/docs/guide/concepts/typescript#nuxttsconfigjson)
[ESLint](https://eslint.org) | `.eslintrc.js` | [More Info](https://eslint.org/docs/latest/use/configure/configuration-files)
[Prettier](https://prettier.io) | `.prettierrc.json` | [More Info](https://prettier.io/docs/en/configuration.html)
[Stylelint](https://stylelint.io) | `.stylelintrc.json` | [More Info](https://stylelint.io/user-guide/configure)
[TailwindCSS](https://tailwindcss.com) | `tailwind.config.js` | [More Info](https://tailwindcss.nuxtjs.org/tailwind/config)
[Vitest](https://vitest.dev) | `vitest.config.ts` | [More Info](https://vitest.dev/config)
## Vue Configuration
@ -164,7 +164,7 @@ If you need to pass options to `@vitejs/plugin-vue` or `@vitejs/plugin-vue-jsx`,
- `vite.vue` for `@vitejs/plugin-vue`. Check available options [here](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue).
- `vite.vueJsx` for `@vitejs/plugin-vue-jsx`. Check available options [here](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx).
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
vite: {
vue: {
@ -183,7 +183,7 @@ export default defineNuxtConfig({
If you use webpack and need to configure `vue-loader`, you can do this using `webpack.loaders.vue` key inside your `nuxt.config` file. The available options are [defined here](https://github.com/vuejs/vue-loader/blob/main/src/index.ts#L32-L62).
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
webpack: {
loaders: {
@ -201,7 +201,7 @@ export default defineNuxtConfig({
You may need to enable experimental features in Vue, such as `propsDestructure`. Nuxt provides an easy way to do that in `nuxt.config.ts`, no matter which builder you are using:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
vue: {
propsDestructure: true

View File

@ -18,7 +18,7 @@ By default, Nuxt will treat this file as the **entrypoint** and render its conte
</template>
```
::callout
::tip
If you are familiar with Vue, you might wonder where `main.js` is (the file that normally creates a Vue app). Nuxt does this behind the scene.
::
@ -90,12 +90,22 @@ To use pages, create `pages/index.vue` file and add `<NuxtPage />` component to
Layouts are wrappers around pages that contain a common User Interface for several pages, such as a header and footer display. Layouts are Vue files using `<slot />` components to display the **page** content. The `layouts/default.vue` file will be used by default. Custom layouts can be set as part of your page metadata.
::callout
::note
If you only have a single layout in your application, we recommend using [`app.vue`](/docs/guide/directory-structure/app) with [`<NuxtPage />`](/docs/api/components/nuxt-page) instead.
::
::code-group
```vue [app.vue]
<template>
<div>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</div>
</template>
```
```vue [layouts/default.vue]
<template>
<div>
@ -131,16 +141,16 @@ If you want to create more layouts and learn how to use them in your pages, find
## Advanced: Extending the HTML template
::callout
::note
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.
The callback function of the `render:html` hook allows you to mutate the HTML before it is sent to the client.
```ts [server/plugins/extend-html.ts]
```ts twoslash [server/plugins/extend-html.ts]
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('render:html', (html, { event }) => {
nitroApp.hooks.hook('render:html', (html, { event }) => {
// This will be an object representation of the html template.
console.log(html)
html.head.push(`<meta name="description" content="My custom description" />`)

View File

@ -43,7 +43,7 @@ For example, referencing an image file that will be processed if a build tool is
</template>
```
::callout
::note
Nuxt won't serve files in the [`assets/`](/docs/guide/directory-structure/assets) directory at a static URL like `/assets/my-file.png`. If you need a static URL, use the [`public/`](#public-directory) directory.
::
@ -73,7 +73,7 @@ In your `nuxt.config`
::code-group
```ts [SCSS]
```ts twoslash [SCSS]
export default defineNuxtConfig({
vite: {
css: {
@ -87,7 +87,7 @@ export default defineNuxtConfig({
})
```
```ts [SASS]
```ts twoslash [SASS]
export default defineNuxtConfig({
vite: {
css: {

View File

@ -30,7 +30,7 @@ import('~/assets/css/first.css')
</style>
```
::callout
::tip
The stylesheets will be inlined in the HTML rendered by Nuxt.
::
@ -45,7 +45,7 @@ export default defineNuxtConfig({
})
```
::callout
::tip
The stylesheets will be inlined in the HTML rendered by Nuxt, injected globally and present in all pages.
::
@ -107,7 +107,7 @@ You can include external stylesheets in your application by adding a link elemen
You can manipulate the head with the [`app.head`](/docs/api/nuxt-config#head) property of your Nuxt configuration:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
app: {
head: {
@ -122,7 +122,7 @@ You can use the useHead composable to dynamically set a value in your head in yo
:read-more{to="/docs/api/composables/use-head"}
```ts
```ts twoslash
useHead({
link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }]
})
@ -136,7 +136,7 @@ If you need more advanced control, you can intercept the rendered html with a ho
Create a plugin in `~/server/plugins/my-plugin.ts` like this:
```ts [server/plugins/my-plugin.ts]
```ts twoslash [server/plugins/my-plugin.ts]
export default defineNitroPlugin((nitro) => {
nitro.hooks.hook('render:html', (html) => {
html.head.push('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">')
@ -177,13 +177,13 @@ You can then import your source files in your `app.vue` (or layouts files) using
Alternatively, you can use the `css` property of your Nuxt configuration.
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
css: ['~/assets/scss/main.scss']
})
```
::callout
::tip
In both cases, the compiled stylesheets will be inlined in the HTML rendered by Nuxt.
::
@ -209,7 +209,7 @@ Then in your `nuxt.config` :
::code-group
```ts [SCSS]
```ts twoslash [SCSS]
export default defineNuxtConfig({
vite: {
css: {
@ -223,7 +223,7 @@ export default defineNuxtConfig({
})
```
```ts [SASS]
```ts twoslash [SASS]
export default defineNuxtConfig({
vite: {
css: {
@ -243,7 +243,7 @@ Nuxt uses Vite by default. If you wish to use webpack instead, refer to each pre
## Single File Components (SFC) Styling
One of the best things about Vue and SFC is how great it is at naturally dealing with styling. You can directly write CSS or preprocessor code in the style block of your components file, therefore you will have fantastic developer experience without having to use something like CSS-in-JS. However if you wish to use CSS-in-JS, you can find 3rd party libraries and modules that support it, such as [pinceau](https://pinceau.dev).
One of the best things about Vue and SFC is how great it is at naturally dealing with styling. You can directly write CSS or preprocessor code in the style block of your components file, therefore you will have fantastic developer experience without having to use something like CSS-in-JS. However if you wish to use CSS-in-JS, you can find 3rd party libraries and modules that support it, such as [pinceau](https://github.com/Tahul/pinceau).
You can refer to the [Vue docs](https://vuejs.org/api/sfc-css-features.html) for a comprehensive reference about styling components in SFC.
@ -286,7 +286,7 @@ const classObject = computed(() => ({
```
```vue [Array]
<script setup lang="ts">
<script setup lang="ts">
const isActive = ref(true)
const errorClass = ref('text-danger')
</script>
@ -421,7 +421,7 @@ For proper syntax highlighting in SFC, you can use the postcss lang attribute.
```vue
<style lang="postcss">
/* Write stylus here */
/* Write postcss here */
</style>
```
@ -430,7 +430,7 @@ By default, Nuxt comes with the following plugins already pre-configured:
- [postcss-import](https://github.com/postcss/postcss-import): Improves the `@import` rule
- [postcss-url](https://github.com/postcss/postcss-url): Transforms `url()` statements
- [autoprefixer](https://github.com/postcss/autoprefixer): Automatically adds vendor prefixes
- [cssnano](https://cssnano.co): Minification and purge
- [cssnano](https://cssnano.github.io/cssnano): Minification and purge
## Leveraging Layouts For Multiple Styles
@ -458,14 +458,14 @@ Use different styles for different layouts.
Nuxt isn't opinionated when it comes to styling and provides you with a wide variety of options. You can use any styling tool that you want, such as popular libraries like [UnoCSS](https://unocss.dev) or [Tailwind CSS](https://tailwindcss.com).
The community and the Nuxt team have developed plenty of Nuxt modules to makes the integration easier.
The community and the Nuxt team have developed plenty of Nuxt modules to make the integration easier.
You can discover them on the [modules section](/modules) of the website.
Here are a few modules to help you get started:
- [UnoCSS](/modules/unocss): Instant on-demand atomic CSS engine
- [Tailwind CSS](/modules/tailwindcss): Utility-first CSS framework
- [Fontaine](https://github.com/nuxt-modules/fontaine): Font metric fallback
- [Pinceau](https://pinceau.dev): Adaptable styling framework
- [Pinceau](https://github.com/Tahul/pinceau): Adaptable styling framework
- [Nuxt UI](https://ui.nuxt.com): A UI Library for Modern Web Apps
- [Panda CSS](https://panda-css.com/docs/installation/nuxt): CSS-in-JS engine that generates atomic CSS at build time
@ -489,7 +489,7 @@ Nuxt comes with the same `<Transition>` element that Vue has, and also has suppo
We would recommend using [Fontaine](https://github.com/nuxt-modules/fontaine) to reduce your [CLS](https://web.dev/cls). If you need something more advanced, consider creating a Nuxt module to extend the build process or the Nuxt runtime.
::callout
::tip
Always remember to take advantage of the various tools and techniques available in the Web ecosystem at large to make styling your application easier and more efficient. Whether you're using native CSS, a preprocessor, postcss, a UI library or a module, Nuxt has got you covered. Happy styling!
::

View File

@ -71,7 +71,7 @@ When a [`<NuxtLink>`](/docs/api/components/nuxt-link) enters the viewport on the
The [`useRoute()`](/docs/api/composables/use-route) composable can be used in a `<script setup>` block or a `setup()` method of a Vue component to access the current route details.
```vue [pages/posts/[id\\].vue]
```vue twoslash [pages/posts/[id\\].vue]
<script setup lang="ts">
const route = useRoute()
@ -86,7 +86,7 @@ console.log(route.params.id)
Nuxt provides a customizable route middleware framework you can use throughout your application, ideal for extracting code that you want to run before navigating to a particular route.
::callout
::note
Route middleware runs within the Vue part of your Nuxt app. Despite the similar name, they are completely different from server middleware, which are run in the Nitro server part of your app.
::
@ -100,7 +100,9 @@ Example of an `auth` middleware protecting the `/dashboard` page:
::code-group
```ts [middleware/auth.ts]
```ts twoslash [middleware/auth.ts]
function isAuthenticated(): boolean { return false }
// ---cut---
export default defineNuxtRouteMiddleware((to, from) => {
// isAuthenticated() is an example method verifying if a user is authenticated
if (isAuthenticated() === false) {
@ -109,7 +111,7 @@ export default defineNuxtRouteMiddleware((to, from) => {
})
```
```html [pages/dashboard.vue]
```vue twoslash [pages/dashboard.vue]
<script setup lang="ts">
definePageMeta({
middleware: 'auth'
@ -133,12 +135,12 @@ The `validate` property accepts the `route` as an argument. You can return a boo
If you have a more complex use case, then you can use anonymous route middleware instead.
```vue [pages/posts/[id\\].vue]
```vue twoslash [pages/posts/[id\\].vue]
<script setup lang="ts">
definePageMeta({
validate: async (route) => {
// Check if the id is made up of digits
return /^\d+$/.test(route.params.id)
return typeof route.params.id === 'string' && /^\d+$/.test(route.params.id)
}
})
</script>

View File

@ -6,9 +6,9 @@ navigation.icon: i-ph-file-search-duotone
## Defaults
Out-of-the-box, Nuxt provides sane defaults, which you can override if needed.
Out-of-the-box, Nuxt provides sensible defaults, which you can override if needed.
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
app: {
head: {
@ -21,7 +21,7 @@ export default defineNuxtConfig({
Providing an [`app.head`](/docs/api/nuxt-config#head) property in your [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config) allows you to customize the head for your entire app.
::callout
::important
This method does not allow you to provide reactive data. We recommend to use `useHead()` in `app.vue`.
::
@ -29,12 +29,12 @@ Shortcuts are available to make configuration easier: `charset` and `viewport`.
## `useHead`
The [`useHead`](/docs/api/composables/use-head) 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 programmatically and reactively,
powered by [Unhead](https://unhead.unjs.io).
As with all composables, it can only be used with a components `setup` and lifecycle hooks.
```vue [app.vue]
```vue twoslash [app.vue]
<script setup lang="ts">
useHead({
title: 'My App',
@ -57,7 +57,7 @@ The [`useSeoMeta`](/docs/api/composables/use-seo-meta) composable lets you defin
This helps you avoid typos and common mistakes, such as using `name` instead of `property`.
```vue [app.vue]
```vue twoslash [app.vue]
<script setup lang="ts">
useSeoMeta({
title: 'My Amazing Site',
@ -76,9 +76,9 @@ useSeoMeta({
Nuxt provides `<Title>`, `<Base>`, `<NoScript>`, `<Style>`, `<Meta>`, `<Link>`, `<Body>`, `<Html>` and `<Head>` components so that you can interact directly with your metadata within your component's template.
Because these component names match native HTML elements, it is very important that they are capitalized in the template.
Because these component names match native HTML elements, they must be capitalized in the template.
`<Head>` and `<Body>` can accept nested meta tags (for aesthetic reasons) but this has no effect on _where_ the nested meta tags are rendered in the final HTML.
`<Head>` and `<Body>` can accept nested meta tags (for aesthetic reasons) but this does not affect _where_ the nested meta tags are rendered in the final HTML.
<!-- @case-police-ignore html -->
@ -92,7 +92,7 @@ const title = ref('Hello World')
<Head>
<Title>{{ title }}</Title>
<Meta name="description" :content="title" />
<Style type="text/css" children="body { background-color: green; }" />
<Style type="text/css" children="body { background-color: green; }" ></Style>
</Head>
<h1>{{ title }}</h1>
@ -126,13 +126,13 @@ See [@unhead/schema](https://github.com/unjs/unhead/blob/main/packages/schema/sr
### Reactivity
Reactivity is supported on all properties, as computed, getters and reactive.
Reactivity is supported on all properties, by providing a computed value, a getter, or a reactive object.
It's recommended to use getters (`() => value`) over computed (`computed(() => value)`).
::code-group
```vue [useHead]
```vue twoslash [useHead]
<script setup lang="ts">
const description = ref('My amazing site.')
@ -143,8 +143,8 @@ It's recommended to use getters (`() => value`) over computed (`computed(() => v
})
</script>
```
```vue [useSeoMeta]
```vue twoslash [useSeoMeta]
<script setup lang="ts">
const description = ref('My amazing site.')
@ -158,7 +158,7 @@ It's recommended to use getters (`() => value`) over computed (`computed(() => v
<script setup lang="ts">
const description = ref('My amazing site.')
</script>
<template>
<div>
<Meta name="description" :content="description" />
@ -170,15 +170,15 @@ It's recommended to use getters (`() => value`) over computed (`computed(() => v
### Title Template
You can use the `titleTemplate` option to provide a dynamic template for customizing the title of your site. for example, by adding the name of your site to the title of every page.
You can use the `titleTemplate` option to provide a dynamic template for customizing the title of your site. For example, you could add the name of your site to the title of every page.
The `titleTemplate` can either be a string, where `%s` is replaced with the title, or a function.
If you want to use a function (for full control), then this cannot be set in your `nuxt.config`, and it is recommended instead to set it within your `app.vue` file, where it will apply to all pages on your site:
If you want to use a function (for full control), then this cannot be set in your `nuxt.config`. It is recommended instead to set it within your `app.vue` file where it will apply to all pages on your site:
::code-group
```vue [useHead]
```vue twoslash [useHead]
<script setup lang="ts">
useHead({
titleTemplate: (titleChunk) => {
@ -190,7 +190,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`](/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.
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 'Site Title'.
### Body Tags
@ -198,7 +198,7 @@ You can use the `tagPosition: 'bodyClose'` option on applicable tags to append t
For example:
```vue
```vue twoslash
<script setup lang="ts">
useHead({
script: [
@ -220,7 +220,7 @@ Within your [`pages/` directory](/docs/guide/directory-structure/pages), you can
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):
```vue [pages/some-page.vue]
```vue twoslash [pages/some-page.vue]
<script setup lang="ts">
definePageMeta({
title: 'Some Page'
@ -230,7 +230,7 @@ definePageMeta({
And then in your layout file, you might use the route's metadata you have previously set:
```vue [layouts/default.vue]
```vue twoslash [layouts/default.vue]
<script setup lang="ts">
const route = useRoute()
@ -248,13 +248,20 @@ useHead({
In the example below, `titleTemplate` is set either as a string with the `%s` placeholder or as a `function`, which allows greater flexibility in setting the page title dynamically for each route of your Nuxt app:
```vue [app.vue]
```vue twoslash [app.vue]
<script setup lang="ts">
useHead({
// as a string,
// where `%s` is replaced with the title
titleTemplate: '%s - Site Title',
// ... or as a function
})
</script>
```
```vue twoslash [app.vue]
<script setup lang="ts">
useHead({
// or as a function
titleTemplate: (productCategory) => {
return productCategory
? `${productCategory} - Site Title`
@ -272,7 +279,7 @@ The example below shows how you might enable Google Fonts using either the `link
::code-group
```vue [useHead]
```vue twoslash [useHead]
<script setup lang="ts">
useHead({
link: [

View File

@ -4,7 +4,7 @@ description: Apply transitions between pages and layouts with Vue or native brow
navigation.icon: i-ph-exclude-square-duotone
---
::callout
::note
Nuxt leverages Vue's [`<Transition>`](https://vuejs.org/guide/built-ins/transition.html#the-transition-component) component to apply transitions between pages and layouts.
::
@ -12,7 +12,7 @@ Nuxt leverages Vue's [`<Transition>`](https://vuejs.org/guide/built-ins/transiti
You can enable page transitions to apply an automatic transition for all your [pages](/docs/guide/directory-structure/pages).
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
app: {
pageTransition: { name: 'page', mode: 'out-in' }
@ -20,7 +20,7 @@ export default defineNuxtConfig({
})
```
::callout
::note
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](/docs/getting-started/transitions#layout-transitions).
::
@ -28,7 +28,7 @@ To start adding transition between your pages, add the following CSS to your [`a
::code-group
```html [app.vue]
```vue [app.vue]
<template>
<NuxtPage />
</template>
@ -46,7 +46,7 @@ To start adding transition between your pages, add the following CSS to your [`a
</style>
```
```html [pages/index.vue]
```vue [pages/index.vue]
<template>
<div>
<h1>Home page</h1>
@ -55,7 +55,7 @@ To start adding transition between your pages, add the following CSS to your [`a
</template>
```
```html [pages/about.vue]
```vue [pages/about.vue]
<template>
<div>
<h1>About page</h1>
@ -76,7 +76,7 @@ To set a different transition for a page, set the `pageTransition` key in [`defi
::code-group
```vue [pages/about.vue]
```vue twoslash [pages/about.vue]
<script setup lang="ts">
definePageMeta({
pageTransition: {
@ -86,7 +86,7 @@ definePageMeta({
</script>
```
```html [app.vue]
```vue [app.vue]
<template>
<NuxtPage />
</template>
@ -117,7 +117,7 @@ Moving to the about page will add the 3d rotation effect:
You can enable layout transitions to apply an automatic transition for all your [layouts](/docs/guide/directory-structure/layouts).
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
app: {
layoutTransition: { name: 'layout', mode: 'out-in' }
@ -129,7 +129,7 @@ To start adding transition between your pages and layouts, add the following CSS
::code-group
```html [app.vue]
```vue [app.vue]
<template>
<NuxtLayout>
<NuxtPage />
@ -148,7 +148,7 @@ To start adding transition between your pages and layouts, add the following CSS
</style>
```
```html [layouts/default.vue]
```vue [layouts/default.vue]
<template>
<div>
<pre>default layout</pre>
@ -163,7 +163,7 @@ div {
</style>
```
```html [layouts/orange.vue]
```vue [layouts/orange.vue]
<template>
<div>
<pre>orange layout</pre>
@ -180,7 +180,7 @@ div {
</style>
```
```html [pages/index.vue]
```vue [pages/index.vue]
<template>
<div>
<h1>Home page</h1>
@ -189,7 +189,7 @@ div {
</template>
```
```html [pages/about.vue]
```vue [pages/about.vue]
<script setup lang="ts">
definePageMeta({
layout: 'orange'
@ -214,7 +214,7 @@ This produces the following result when navigating between pages:
Similar to `pageTransition`, you can apply a custom `layoutTransition` to the page component using `definePageMeta`:
```vue [pages/about.vue]
```vue twoslash [pages/about.vue]
<script setup lang="ts">
definePageMeta({
layout: 'orange',
@ -231,7 +231,7 @@ You can customize these default transition names globally using `nuxt.config`.
Both `pageTransition` and `layoutTransition` keys accept [`TransitionProps`](https://vuejs.org/api/built-in-components.html#transition) as JSON serializable values where you can pass the `name`, `mode` and other valid transition-props of the custom CSS transition.
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
app: {
pageTransition: {
@ -246,13 +246,13 @@ export default defineNuxtConfig({
})
```
::callout
::warning
If you change the `name` property, you also have to rename the CSS classes accordingly.
::
To override the global transition property, use the `definePageMeta` to define page or layout transitions for a single Nuxt page and override any page or layout transitions that are defined globally in `nuxt.config` file.
```vue [pages/some-page.vue]
```vue twoslash [pages/some-page.vue]
<script setup lang="ts">
definePageMeta({
pageTransition: {
@ -267,7 +267,7 @@ definePageMeta({
`pageTransition` and `layoutTransition` can be disabled for a specific route:
```vue [pages/some-page.vue]
```vue twoslash [pages/some-page.vue]
<script setup lang="ts">
definePageMeta({
pageTransition: false,
@ -278,8 +278,8 @@ definePageMeta({
Or globally in the `nuxt.config`:
```ts [nuxt.config.ts]
defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
app: {
pageTransition: false,
layoutTransition: false
@ -293,7 +293,7 @@ For advanced use-cases, you can use JavaScript hooks to create highly dynamic an
This way presents perfect use-cases for JavaScript animation libraries such as [GSAP](https://gsap.com).
```vue [pages/some-page.vue]
```vue twoslash [pages/some-page.vue]
<script setup lang="ts">
definePageMeta({
pageTransition: {
@ -309,7 +309,7 @@ definePageMeta({
</script>
```
::callout
::tip
Learn more about additional [JavaScript hooks](https://vuejs.org/guide/built-ins/transition.html#javascript-hooks) available in the `Transition` component.
::
@ -319,7 +319,7 @@ To apply dynamic transitions using conditional logic, you can leverage inline [m
::code-group
```html [pages/[id\\].vue]
```vue twoslash [pages/[id\\].vue]
<script setup lang="ts">
definePageMeta({
pageTransition: {
@ -327,7 +327,8 @@ definePageMeta({
mode: 'out-in'
},
middleware (to, from) {
to.meta.pageTransition.name = +to.params.id > +from.params.id ? 'slide-left' : 'slide-right'
if (to.meta.pageTransition && typeof to.meta.pageTransition !== 'boolean')
to.meta.pageTransition.name = +to.params.id > +from.params.id ? 'slide-left' : 'slide-right'
}
})
</script>
@ -362,7 +363,7 @@ definePageMeta({
</style>
```
```html [layouts/default.vue]
```vue [layouts/default.vue]
<script setup lang="ts">
const route = useRoute()
const id = computed(() => Number(route.params.id || 1))
@ -406,7 +407,7 @@ When `<NuxtPage />` is used in `app.vue`, transition-props can be passed directl
</template>
```
::callout
::note
Remember, this page transition cannot be overridden with `definePageMeta` on individual pages.
::
@ -418,7 +419,7 @@ You can check a demo on https://nuxt-view-transitions.surge.sh and the [source o
The Nuxt integration is under active development, but can be enabled with the `experimental.viewTransition` option in your configuration file:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
viewTransition: true
@ -426,9 +427,38 @@ export default defineNuxtConfig({
})
```
The possible values are: `false`, `true`, or `'always'`.
If set to true, Nuxt will not apply transitions if the user's browser matches `prefers-reduced-motion: reduce` (recommended). If set to `always`, Nuxt will always apply the transition and it is up to you to respect the user's preference.
By default, view transitions are enabled for all [pages](/docs/guide/directory-structure/pages), but you can set a different global default.
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
app: {
// Disable view transitions globally, and opt-in on a per page basis
viewTransition: false
},
})
```
It is possible to override the default `viewTransition` value for a page by setting the `viewTransition` key in [`definePageMeta`](/docs/api/utils/define-page-meta) of the page:
```vue twoslash [pages/about.vue]
<script setup lang="ts">
definePageMeta({
viewTransition: false
})
</script>
```
::alert{type="warning"}
Overriding view transitions on a per-page basis will only have an effect if you have enabled the `experimental.viewTransition` option.
::
If you are also using Vue transitions like `pageTransition` and `layoutTransition` (see above) to achieve the same result as the new View Transitions API, then you may wish to _disable_ Vue transitions if the user's browser supports the newer, native web API. You can do this by creating `~/middleware/disable-vue-transitions.global.ts` with the following contents:
```js
```ts
export default defineNuxtRouteMiddleware(to => {
if (import.meta.server || !document.startViewTransition) { return }

View File

@ -26,7 +26,7 @@ The [`useFetch`](/docs/api/composables/use-fetch) and [`useAsyncData`](/docs/api
The payload is a JavaScript object accessible through [`useNuxtApp().payload`](/docs/api/composables/use-nuxt-app#payload). It is used on the client to avoid refetching the same data when the code is executed in the browser [during hydration](/docs/guide/concepts/rendering#universal-rendering).
::callout{color="blue" icon="i-ph-info-duotone"}
::tip
Use the [Nuxt DevTools](https://devtools.nuxt.com) to inspect this data in the **Payload tab**.
::
@ -34,7 +34,7 @@ Use the [Nuxt DevTools](https://devtools.nuxt.com) to inspect this data in the *
Nuxt uses Vues [`<Suspense>`](https://vuejs.org/guide/built-ins/suspense) component under the hood to prevent navigation before every async data is available to the view. The data fetching composables can help you leverage this feature and use what suits best on a per-calls basis.
::callout{color="blue" icon="i-ph-info-duotone"}
::note
You can add the [`<NuxtLoadingIndicator>`](/docs/api/components/nuxt-loading-indicator) to add a progress bar between page navigations.
::
@ -42,7 +42,7 @@ You can add the [`<NuxtLoadingIndicator>`](/docs/api/components/nuxt-loading-ind
The [`useFetch`](/docs/api/composables/use-fetch) composable is the most straightforward way to perform data fetching.
```vue [app.vue]
```vue twoslash [app.vue]
<script setup lang="ts">
const { data: count } = await useFetch('/api/count')
</script>
@ -60,10 +60,10 @@ This composable is a wrapper around the [`useAsyncData`](/docs/api/composables/u
## `$fetch`
Nuxt includes the `ofetch` library, and is auto-imported as the `$fetch` alias globally across your application. It's what `useFetch` uses behind the scenes.
Nuxt includes the [ofetch](https://github.com/unjs/ofetch) library, and is auto-imported as the `$fetch` alias globally across your application. It's what `useFetch` uses behind the scenes.
```vue [pages/todos.vue]
<script setup>
```vue twoslash [pages/todos.vue]
<script setup lang="ts">
async function addTodo() {
const todo = await $fetch('/api/todos', {
method: 'POST',
@ -75,7 +75,7 @@ async function addTodo() {
</script>
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Beware that using only `$fetch` will not provide [network calls de-duplication and navigation prevention](#why-using-specific-composables). :br
It is recommended to use `$fetch` for client-side interactions (event based) or combined with [`useAsyncData`](#useasyncdata) when fetching the initial component data.
::
@ -88,15 +88,15 @@ Read more about `$fetch`.
The `useAsyncData` composable is responsible for wrapping async logic and returning the result once it is resolved.
::callout
`useFetch(url)` is nearly equivalent to `useAsyncData(url, () => $fetch(url))` :br
Iit's developer experience sugar for the most common use case.
::tip
`useFetch(url)` is nearly equivalent to `useAsyncData(url, () => $fetch(url))`. :br
It's developer experience sugar for the most common use case.
::
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.
```vue [pages/users.vue]
<script setup>
<script setup lang="ts">
const { data, error } = await useAsyncData('users', () => myGetFunction('users'))
// This is also possible:
@ -104,7 +104,7 @@ const { data, error } = await useAsyncData(() => myGetFunction('users'))
</script>
```
::callout{color="blue" icon="i-ph-info-duotone"}
::note
The first argument of [`useAsyncData`](/docs/api/composables/use-async-data) is a unique key used to cache the response of the second argument, the querying function. This key can be ignored by directly passing the querying function, the key will be auto-generated.
:br :br
Since the autogenerated key only takes into account the file and line where `useAsyncData` is invoked, it is recommended to always create your own key to avoid unwanted behavior, like when you are creating your own custom composable wrapping `useAsyncData`.
@ -113,7 +113,7 @@ Setting a key can be useful to share the same data between components using [`us
::
```vue [pages/users/[id\\].vue]
<script setup>
<script setup lang="ts">
const { id } = useRoute().params
const { data, error } = await useAsyncData(`user:${id}`, () => {
@ -122,10 +122,10 @@ const { data, error } = await useAsyncData(`user:${id}`, () => {
</script>
```
The `useAsyncData` composable is a great way to wrap and wait for multiple `useFetch` to be done, and then retrieve the results of each.
The `useAsyncData` composable is a great way to wrap and wait for multiple `$fetch` requests to be completed, and then process the results.
```vue
<script setup>
<script setup lang="ts">
const { data: discounts, pending } = await useAsyncData('cart-discount', async () => {
const [coupons, offers] = await Promise.all([
$fetch('/cart/coupons'),
@ -150,16 +150,17 @@ Read more about `useAsyncData`.
- `data`: the result of the asynchronous function that is passed in.
- `pending`: a boolean indicating whether the data is still being fetched.
- `refresh`/`execute`: a function that can be used to refresh the data returned by the `handler` function.
- `clear`: a function that can be used to set `data` to undefined, set `error` to `null`, set `pending` to `false`, set `status` to `idle`, and mark any currently pending requests as cancelled.
- `error`: an error object if the data fetching failed.
- `status`: a string indicating the status of the data request (`"idle"`, `"pending"`, `"success"`, `"error"`).
::callout
::note
`data`, `pending`, `error` and `status` are Vue refs accessible with `.value` in `<script setup>`
::
By default, Nuxt waits until a `refresh` is finished before it can be executed again.
::callout
::note
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>`.
::
@ -171,7 +172,7 @@ If you have not fetched data on the server (for example, with `server: false`),
By default, data fetching composables will wait for the resolution of their asynchronous function before navigating to a new page by using Vues Suspense. This feature can be ignored on client-side navigation with the `lazy` option. In that case, you will have to manually handle loading state using the `pending` value.
```vue [app.vue]
```vue twoslash [app.vue]
<script setup lang="ts">
const { pending, data: posts } = useFetch('/api/posts', {
lazy: true
@ -193,7 +194,7 @@ const { pending, data: posts } = useFetch('/api/posts', {
You can alternatively use [`useLazyFetch`](/docs/api/composables/use-lazy-fetch) and `useLazyAsyncData` as convenient methods to perform the same.
```vue
```vue twoslash
<script setup lang="ts">
const { pending, data: posts } = useLazyFetch('/api/posts')
</script>
@ -213,9 +214,9 @@ By default, data fetching composables will perform their asynchronous function o
Combined with the `lazy` option, this can be useful for data that is not needed on the first render (for example, non-SEO sensitive data).
```ts
```ts twoslash
/* This call is performed before hydration */
const { article } = await useFetch('api/article')
const articles = await useFetch('/api/article')
/* This call will only be performed on the client */
const { pending, data: posts } = useFetch('/api/comments', {
@ -247,14 +248,14 @@ const { data: mountain } = await useFetch('/api/mountains/everest', {
If you need more control or map over several objects, you can use the `transform` function to alter the result of the query.
```ts
const { data: mountains } = await useFetch('/api/mountains', {
const { data: mountains } = await useFetch('/api/mountains', {
transform: (mountains) => {
return mountains.map(mountain => ({ title: mountain.title, description: mountain.description }))
}
})
```
::callout
::note
Both `pick` and `transform` don't prevent the unwanted data from being fetched initially. But they will prevent unwanted data from being added to the payload transferred from server to client.
::
@ -267,7 +268,7 @@ Both `pick` and `transform` don't prevent the unwanted data from being fetched i
- [`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`](/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.
::callout
::tip
To get the cached data by key, you can use [`useNuxtData`](/docs/api/composables/use-nuxt-data)
::
@ -275,7 +276,7 @@ To get the cached data by key, you can use [`useNuxtData`](/docs/api/composables
If you want to fetch or refresh data manually, use the `execute` or `refresh` function provided by the composables.
```vue
```vue twoslash
<script setup lang="ts">
const { data, error, execute, refresh } = await useFetch('/api/users')
</script>
@ -290,15 +291,30 @@ const { data, error, execute, refresh } = await useFetch('/api/users')
The `execute` function is an alias for `refresh` that works in exactly the same way but is more semantic for cases when the fetch is [not immediate](#not-immediate).
::callout{color="blue" icon="i-ph-info-duotone"}
::tip
To globally refetch or invalidate cached data, see [`clearNuxtData`](/docs/api/utils/clear-nuxt-data) and [`refreshNuxtData`](/docs/api/utils/refresh-nuxt-data).
::
#### Clear
If you want to clear the data provided, for whatever reason, without needing to know the specific key to pass to `clearNuxtData`, you can use the `clear` function provided by the composables.
```vue twoslash
<script setup lang="ts">
const { data, clear } = await useFetch('/api/users')
const route = useRoute()
watch(() => route.path, (path) => {
if (path === '/') clear()
})
</script>
```
#### Watch
To re-run your fetching function each time other reactive values in your application change, use the `watch` option. You can use it for one or multiple _watchable_ elements.
```vue
```vue twoslash
<script setup lang="ts">
const id = ref(1)
@ -360,7 +376,7 @@ const { data, pending, status } = useLazyFetch(() => `/api/users/${id.value}`, {
<div v-if="status === 'idle'">
Type an user ID
</div>
<div v-else-if="pending">
Loading ...
</div>
@ -427,7 +443,7 @@ const { data } = await useFetch('/api/me', { headers })
</script>
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::caution
Be very careful before proxying headers to an external API and just include headers that you need. Not all headers are safe to be bypassed and might introduce unwanted behavior. Here is a list of common headers that are NOT to be proxied:
- `host`, `accept`
@ -462,7 +478,7 @@ export const fetchWithCookie = async (event: H3Event, url: string) => {
// This composable will automatically pass cookies to the client
const event = useRequestEvent()
const { data: result } = await useAsyncData(() => fetchWithCookie(event, '/api/with-cookie'))
const { data: result } = await useAsyncData(() => fetchWithCookie(event!, '/api/with-cookie'))
onMounted(() => console.log(document.cookie))
</script>
@ -486,7 +502,7 @@ export default defineNuxtComponent({
</script>
```
::callout{color="blue" icon="i-ph-info-duotone"}
::note
Using `<script setup>` or `<script setup lang="ts">` are the recommended way of declaring Vue components in Nuxt 3.
::
@ -498,7 +514,7 @@ When using `useAsyncData` and `useLazyAsyncData` to transfer data fetched on ser
It is also possible to define your own serializer/deserializer for types that are not supported by Nuxt. You can read more in the [`useNuxtApp`](/docs/api/composables/use-nuxt-app#payload) docs.
::callout
::note
Note that this _does not apply_ to data passed from your server routes when fetched with `$fetch` or `useFetch` - see the next section for more information.
::

View File

@ -8,7 +8,7 @@ Nuxt provides the [`useState`](/docs/api/composables/use-state) composable to cr
[`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.
::callout
::important
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.
::
@ -18,12 +18,12 @@ Read more about `useState` composable.
## Best Practices
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Never define `const state = ref()` outside of `<script setup>` or `setup()` function.<br>
Such state will be shared across all users visiting your website and can lead to memory leaks!
::
::callout{color="green" icon="i-ph-check-circle-duotone"}
::tip{icon="i-ph-check-circle-duotone"}
Instead use `const useX = () => useState('x')`
::
@ -33,7 +33,7 @@ Instead use `const useX = () => useState('x')`
In this example, we use a component-local counter state. Any other component that uses `useState('counter')` shares the same reactive state.
```vue [app.vue]
```vue twoslash [app.vue]
<script setup lang="ts">
const counter = useState('counter', () => Math.round(Math.random() * 1000))
</script>
@ -53,7 +53,7 @@ const counter = useState('counter', () => Math.round(Math.random() * 1000))
:link-example{to="/docs/examples/features/state-management"}
::callout
::note
To globally invalidate cached state, see [`clearNuxtState`](/docs/api/utils/clear-nuxt-state) util.
::
@ -61,8 +61,8 @@ To globally invalidate cached state, see [`clearNuxtState`](/docs/api/utils/clea
Most of the time, you will want to initialize your state with data that resolves asynchronously. You can use the [`app.vue`](/docs/guide/directory-structure/app) component with the [`callOnce`](/docs/api/utils/call-once) util to do so.
```vue [app.vue]
<script setup>
```vue twoslash [app.vue]
<script setup lang="ts">
const websiteConfig = useState('config')
await callOnce(async () => {
@ -71,7 +71,7 @@ await callOnce(async () => {
</script>
```
::callout
::tip
This is similar to the [`nuxtServerInit` action](https://v2.nuxt.com/docs/directory-structure/store/#the-nuxtserverinit-action) in Nuxt 2, which allows filling the initial state of your store server-side before rendering the page.
::
@ -81,7 +81,7 @@ This is similar to the [`nuxtServerInit` action](https://v2.nuxt.com/docs/direct
In this example, we leverage the [Pinia module](/modules/pinia) to create a global store and use it across the app.
::callout
::important
Make sure to install the Pinia module with `npx nuxi@latest module add pinia` or follow the [module's installation steps](https://pinia.vuejs.org/ssr/nuxt.html#Installation).
::
@ -103,7 +103,7 @@ export const useWebsiteStore = defineStore('websiteStore', {
})
```
```vue [app.vue]
<script setup>
<script setup lang="ts">
const website = useWebsiteStore()
await callOnce(website.fetch)
@ -130,12 +130,12 @@ export const useLocale = () => {
export const useDefaultLocale = (fallback = 'en-US') => {
const locale = ref(fallback)
if (process.server) {
if (import.meta.server) {
const reqLocale = useRequestHeaders()['accept-language']?.split(',')[0]
if (reqLocale) {
locale.value = reqLocale
}
} else if (process.client) {
} else if (import.meta.client) {
const navLang = navigator.language
if (navLang) {
locale.value = navLang
@ -173,7 +173,7 @@ const date = useLocaleDate(new Date('2016-10-26'))
<template>
<div>
<h1>Nuxt birthday</h1>
<p>{{ date }}</p>
<p>{{ date }}</p>
<label for="locale-chooser">Preview a different locale</label>
<select id="locale-chooser" v-model="locale">
<option v-for="locale of locales" :key="locale" :value="locale">
@ -191,13 +191,15 @@ const date = useLocaleDate(new Date('2016-10-26'))
By using [auto-imported composables](/docs/guide/directory-structure/composables) we can define global type-safe states and import them across the app.
```ts [composables/states.ts]
export const useCounter = () => useState<number>('counter', () => 0)
```ts twoslash [composables/states.ts]
export const useColor = () => useState<string>('color', () => 'pink')
```
```vue [app.vue]
<script setup lang="ts">
// ---cut-start---
const useColor = () => useState<string>('color', () => 'pink')
// ---cut-end---
const color = useColor() // Same as useState('color')
</script>

View File

@ -7,15 +7,15 @@ navigation.icon: i-ph-bug-beetle-duotone
Nuxt 3 is a full-stack framework, which means there are several sources of unpreventable user runtime errors that can happen in different contexts:
- Errors during the Vue rendering lifecycle (SSR & CSR)
- Errors during Nitro server lifecycle ([`server/`](/docs/guide/directory-structure/server) directory)
- Server and client startup errors (SSR + CSR)
- Errors during Nitro server lifecycle ([`server/`](/docs/guide/directory-structure/server) directory)
- Errors downloading JS chunks
::callout
::tip
**SSR** stands for **Server-Side Rendering** and **CSR** for **Client-Side Rendering**.
::
## Vue Rendering Lifecycle
## Vue Errors
You can hook into Vue errors using [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle.html#onerrorcaptured).
@ -23,7 +23,7 @@ In addition, Nuxt provides a [`vue:error`](/docs/api/advanced/hooks#app-hooks-ru
If you are using an error reporting framework, you can provide a global handler through [`vueApp.config.errorHandler`](https://vuejs.org/api/application.html#app-config-errorhandler). It will receive all Vue errors, even if they are handled.
```ts [plugins/error-handler.ts]
```ts twoslash [plugins/error-handler.ts]
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
// handle error, e.g. report to a service
@ -36,7 +36,7 @@ export default defineNuxtPlugin((nuxtApp) => {
})
```
::callout
::note
Note that the `vue:error` hook is based on [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle.html#onerrorcaptured) lifecycle hook.
::
@ -51,7 +51,7 @@ This includes:
- mounting the app (on client-side), though you should handle this case with `onErrorCaptured` or with `vue:error`
- processing the `app:mounted` hook
## Nitro Server Lifecycle
## Nitro Server Errors
You cannot currently define a server-side handler for these errors, but can render an error page, see the [Render an Error Page](#error-page) section.
@ -63,7 +63,7 @@ You can change this behavior by setting `experimental.emitRouteChunkError` to `f
## Error Page
::callout
::note
When Nuxt encounters a fatal error (any unhandled error on the server, or an error created with `fatal: true` on the client) it will either render a JSON response (if requested with `Accept: application/json` header) or trigger a full-screen error page.
::
@ -84,10 +84,14 @@ Discover all the Nuxt lifecycle hooks.
Customize the default error page by adding `~/error.vue` in the source directory of your application, alongside `app.vue`.
<!-- TODO:twoslash: Twoslash does not support tsconfig paths yet -->
```vue [error.vue]
<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps({
error: Object
error: Object as () => NuxtError
})
const handleError = () => clearError({ redirect: '/' })
@ -101,39 +105,13 @@ const handleError = () => clearError({ redirect: '/' })
</template>
```
::callout
Although it is called an 'error page' it's not a route and shouldn't be placed in your `~/pages` directory. For the same reason, you shouldn't use `definePageMeta` within this page.
::read-more{to="/docs/guide/directory-structure/error"}
Read more about `error.vue` and its uses.
::
The error page has a single prop - `error` which contains an error for you to handle.
The `error` object provides the fields:
```ts
{
url: string
statusCode: number
statusMessage: string
message: string
description: string
data: any
}
```
If you have an error with custom fields they will be lost; you should assign them to `data` instead:
```ts
throw createError({
statusCode: 404,
statusMessage: 'Page Not Found',
data: {
myCustomField: true
}
})
```
For custom errors we highly recommend to use `onErrorCaptured` composable that can be called in a page/component setup function or `vue:error` runtime nuxt hook that can be configured in a nuxt plugin.
```ts [plugins/error-handler.ts]
```ts twoslash [plugins/error-handler.ts]
export default defineNuxtPlugin(nuxtApp => {
nuxtApp.hook('vue:error', (err) => {
//
@ -143,11 +121,11 @@ export default defineNuxtPlugin(nuxtApp => {
When you are ready to remove the error page, you can call the [`clearError`](/docs/api/utils/clear-error) helper function, which takes an optional path to redirect to (for example, if you want to navigate to a 'safe' page).
::callout
::important
Make sure to check before using anything dependent on Nuxt plugins, such as `$route` or `useRouter`, as if a plugin threw an error, then it won't be re-run until you clear the error.
::
::callout
::note
If you are running on Node 16 and you set any cookies when rendering your error page, they will [overwrite cookies previously set](https://github.com/nuxt/nuxt/pull/20585). We recommend using a newer version of Node as Node 16 reached end-of-life in September 2023.
::
@ -177,7 +155,7 @@ If you throw an error created with `createError`:
- on server-side, it will trigger a full-screen error page which you can clear with [`clearError`](#clearerror).
- on client-side, it will throw a non-fatal error for you to handle. If you need to trigger a full-screen error page, then you can do this by setting `fatal: true`.
```vue [pages/movies/[slug\\].vue]
```vue twoslash [pages/movies/[slug\\].vue]
<script setup lang="ts">
const route = useRoute()
const { data } = await useFetch(`/api/movies/${route.params.slug}`)
@ -229,7 +207,7 @@ This component is responsible for handling errors that occur within its default
The `#error` slot will receive `error` as a prop. (If you set `error = null` it will trigger re-rendering the default slot; you'll need to ensure that the error is fully resolved first or the error slot will just be rendered a second time.)
::callout
::tip
If you navigate to another route, the error will be cleared automatically.
::

View File

@ -26,7 +26,7 @@ You can easily manage the server-only part of your Nuxt app, from API endpoints
Both endpoints and middleware can be defined like this:
```ts [server/api/test.ts]
```ts twoslash [server/api/test.ts]
export default defineEventHandler(async (event) => {
// ... Do whatever you want here
})
@ -48,7 +48,7 @@ There are more than 15 presets to build your Nuxt app for different cloud provid
- [Cloudflare Workers](https://workers.cloudflare.com)
- [Netlify Functions](https://www.netlify.com/products/functions)
- [Vercel Edge Network](https://vercel.com/docs/edge-network/introduction)
- [Vercel Edge Network](https://vercel.com/docs/edge-network/overview)
Or for other runtimes:
@ -63,7 +63,7 @@ Or for other runtimes:
Nitro has a powerful feature called `routeRules` which allows you to define a set of rules to customize how each route of your Nuxt app is rendered (and more).
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
routeRules: {
// Generated at build time for SEO purpose
@ -83,9 +83,9 @@ export default defineNuxtConfig({
Learn about all available route rules are available to customize the rendering mode of your routes.
::
In addition, there are some route rules (for example, `ssr` and `experimentalNoScripts`) that are Nuxt specific to change the behavior when rendering your pages to HTML.
In addition, there are some route rules (for example, `ssr`, `appMiddleware`, and `experimentalNoScripts`) that are Nuxt specific to change the behavior when rendering your pages to HTML.
Some route rules (`redirect` and `prerender`) also affect client-side behavior.
Some route rules (`appMiddleware`, `redirect` and `prerender`) also affect client-side behavior.
Nitro is used to build the app for server side rendering, as well as pre-rendering.

View File

@ -14,6 +14,7 @@ One of the core features of Nuxt 3 is the layers and extending support. You can
- Create Nuxt module presets
- Share standard setup across projects
- Create Nuxt themes
- Enhance code organization by implementing a modular architecture and support Domain-Driven Design (DDD) pattern in large scale projects.
## Usage
@ -29,11 +30,24 @@ export default defineNuxtConfig({
})
```
You can also pass an authentication token if you are extending from a private GitHub repository:
```ts [nuxt.config.ts]
export default defineNuxtConfig({
extends: [
// per layer configuration
['github:my-themes/private-awesome', { auth: process.env.GITHUB_TOKEN }]
]
})
```
Nuxt uses [unjs/c12](https://c12.unjs.io) and [unjs/giget](https://giget.unjs.io) for extending remote layers. Check the documentation for more information and all available options.
::read-more{to="/docs/guide/going-further/layers"}
Read more about layers in the **Layer Author Guide**.
::
::callout{color="blue" icon="i-ph-video-duotone" to="https://www.youtube.com/watch?v=lnFCM7c9f7I" target="_blank"}
::tip{icon="i-ph-video-duotone" to="https://www.youtube.com/watch?v=lnFCM7c9f7I" target="_blank"}
Watch Learn Vue video about Nuxt Layers.
::

View File

@ -5,7 +5,7 @@ description: "Nuxt auto-imports components, composables, helper functions and Vu
Nuxt auto-imports components, composables and [Vue.js APIs](https://vuejs.org/api) to use across your application without explicitly importing them.
```vue [app.vue]
```vue twoslash [app.vue]
<script setup lang="ts">
const count = ref(1) // ref is auto-imported
</script>
@ -15,15 +15,15 @@ Thanks to its opinionated directory structure, Nuxt can auto-import your [`compo
Contrary to a classic global declaration, Nuxt preserves typings, IDEs completions and hints, and **only includes what is used in your production code**.
::callout{color="blue" icon="i-ph-lightbulb-duotone"}
::note
In the docs, every function that is not explicitly imported is auto-imported by Nuxt and can be used as-is in your code. You can find a reference for auto-imported components, composables and utilities in the [API section](/docs/api).
::
::callout
::note
In the [`server`](/docs/guide/directory-structure/server) directory, Nuxt auto-imports exported functions and variables from `server/utils/`.
::
::callout
::note
You can also auto-import functions exported from custom folders or third-party packages by configuring the [`imports`](/docs/api/nuxt-config#imports) section of your `nuxt.config` file.
::
@ -31,7 +31,7 @@ You can also auto-import functions exported from custom folders or third-party p
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.
```vue
```vue twoslash
<script setup lang="ts">
/* useAsyncData() and $fetch() are auto-imported */
const { data, refresh, pending } = await useFetch('/api/hello')
@ -40,7 +40,7 @@ const { data, refresh, pending } = await useFetch('/api/hello')
Vue 3 exposes Reactivity APIs like `ref` or `computed`, as well as lifecycle hooks and helpers that are auto-imported by Nuxt.
```vue
```vue twoslash
<script setup lang="ts">
/* ref() and computed() are auto-imported */
const count = ref(1)
@ -70,7 +70,7 @@ See the full explanation in this GitHub comment.
**Example of breaking code:**
```ts [composables/example.ts]
```ts twoslash [composables/example.ts]
// trying to access runtime config outside a composable
const config = useRuntimeConfig()
@ -81,10 +81,10 @@ export const useMyComposable = () => {
**Example of working code:**
```ts [composables/example.ts]
```ts twoslash [composables/example.ts]
export const useMyComposable = () => {
// Because your composable is called in the right place in the lifecycle,
// useRuntimeConfig will also work
// useRuntimeConfig will work here
const config = useRuntimeConfig()
// ...
@ -105,6 +105,8 @@ Nuxt directly auto-imports files created in defined directories:
Nuxt exposes every auto-import with the `#imports` alias that can be used to make the import explicit if needed:
<!-- TODO:twoslash: Twoslash does not support tsconfig paths yet -->
```vue
<script setup lang="ts">
import { ref, computed } from '#imports'
@ -118,7 +120,7 @@ const double = computed(() => count.value * 2)
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 twoslash [nuxt.config.ts]
export default defineNuxtConfig({
imports: {
autoImport: false
@ -136,7 +138,7 @@ Nuxt also automatically imports components from your `~/components` directory, a
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]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
components: {
dirs: []
@ -148,13 +150,13 @@ export default defineNuxtConfig({
Nuxt also allows auto-importing from third-party packages.
::callout
::tip
If you are using the Nuxt module for that package, it is likely that the module has already configured auto-imports for that package.
::
For example, you could enable the auto-import of the `useI18n` composable from the `vue-i18n` package like this:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
imports: {
presets: [

View File

@ -5,7 +5,7 @@ description: "Nuxt uses Vue.js and adds features such as component auto-imports,
Nuxt integrates Vue 3, the new major release of Vue that enables new patterns for Nuxt users.
::callout
::note
While an in-depth knowledge of Vue is not required to use Nuxt, we recommend that you read the documentation and go through some of the examples on [vuejs.org](https://vuejs.org).
::
@ -61,7 +61,7 @@ This way, a minimal Vue 3 application can be reduced to 12 kb gzipped.
The only way to provide data and logic to components in Vue 2 was through the Options API, which allows you to return data and methods to a template with pre-defined properties like `data` and `methods`:
```vue
```vue twoslash
<script>
export default {
data() {
@ -82,7 +82,7 @@ The [Composition API](https://vuejs.org/guide/extras/composition-api-faq.html) i
Used with the `setup` keyword in the `<script>` definition, here is the above component rewritten with Composition API and Nuxt 3s auto-imported Reactivity APIs:
```vue [components/Counter.vue]
```vue twoslash [components/Counter.vue]
<script setup lang="ts">
const count = ref(0)
const increment = () => count.value++

View File

@ -31,11 +31,11 @@ Universal rendering allows a Nuxt application to provide quick page load times w
Universal rendering is very versatile and can fit almost any use case, and is especially appropriate for any content-oriented websites: **blogs, marketing websites, portfolios, e-commerce sites, and marketplaces.**
::callout
::tip
For more examples about writing Vue code without hydration mismatch, see [the Vue docs](https://vuejs.org/guide/scaling-up/ssr.html#hydration-mismatch).
::
::callout{icon="i-ph-warning-duotone" color="amber"}
::important
When importing a library that relies on browser APIs and has side effects, make sure the component importing it is only called client-side. Bundlers do not treeshake imports of modules containing side effects.
::
@ -64,7 +64,7 @@ export default defineNuxtConfig({
})
```
::callout
::note
If you do use `ssr: false`, you should also place an HTML file in `~/app/spa-loading-template.html` with some HTML you would like to use to render a loading screen that will be rendered until your app is hydrated.
:read-more{title="SPA Loading Template" to="/docs/api/configuration/nuxt-config#spaloadingtemplate"}
::
@ -79,14 +79,18 @@ Nuxt 3 includes route rules and hybrid rendering support. Using route rules you
Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using [Nitro caching layer](https://nitro.unjs.io/guide/cache).
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
routeRules: {
// Homepage pre-rendered at build time
'/': { prerender: true },
// Product page generated on-demand, revalidates in background
// Products page generated on demand, revalidates in background, cached until API response changes
'/products': { swr: true },
// Product page generated on demand, revalidates in background, cached for 1 hour (3600 seconds)
'/products/**': { swr: 3600 },
// Blog post generated on-demand once until next deploy
// Blog posts page generated on demand, revalidates in background, cached on CDN for 1 hour (3600 seconds)
'/blog': { isr: 3600 },
// Blog post page generated on demand once until next deployment, cached on CDN
'/blog/**': { isr: true },
// Admin dashboard renders only on client-side
'/admin/**': { ssr: false },
@ -105,14 +109,15 @@ The different properties you can use are the following:
- `ssr: boolean`{lang=ts} - Disables server-side rendering for sections of your app and make them SPA-only with `ssr: false`
- `cors: boolean`{lang=ts} - Automatically adds cors headers with `cors: true` - you can customize the output by overriding with `headers`
- `headers: object`{lang=ts} - Add specific headers to sections of your site - for example, your assets
- `swr: number|boolean`{lang=ts} - Add cache headers to the server response and cache it on the server or reverse proxy for a configurable TTL (time to live). The `node-server` preset of Nitro is able to cache the full response. When the TTL expired, the cached response will be sent while the page will be regenerated in the background. If true is used, a `stale-while-revalidate` header is added without a MaxAge.
- `isr: number|boolean`{lang=ts} - The behavior is the same as `swr` except that we are able to add the response to the CDN cache on platforms that support this (currently Netlify or Vercel). If `true` is used, the content persists until the next deploy inside the CDN.
- `prerender:boolean`{lang=ts} - Prerenders routes at build time and includes them in your build as static assets
- `swr: number | boolean`{lang=ts} - Add cache headers to the server response and cache it on the server or reverse proxy for a configurable TTL (time to live). The `node-server` preset of Nitro is able to cache the full response. When the TTL expired, the cached response will be sent while the page will be regenerated in the background. If true is used, a `stale-while-revalidate` header is added without a MaxAge.
- `isr: number | boolean`{lang=ts} - The behavior is the same as `swr` except that we are able to add the response to the CDN cache on platforms that support this (currently Netlify or Vercel). If `true` is used, the content persists until the next deploy inside the CDN.
- `prerender: boolean`{lang=ts} - Prerenders routes at build time and includes them in your build as static assets
- `experimentalNoScripts: boolean`{lang=ts} - Disables rendering of Nuxt scripts and JS resource hints for sections of your site.
- `appMiddleware: string | string[] | Record<string, boolean>`{lang=ts} - Allows you to define middleware that should or should not run for page paths within the Vue app part of your application (that is, not your Nitro routes)
Whenever possible, route rules will be automatically applied to the deployment platform's native rules for optimal performances (Netlify and Vercel are currently supported).
::callout{icon="i-ph-warning-duotone" color="amber"}
::important
Note that Hybrid Rendering is not available when using [`nuxt generate`](/docs/api/commands/generate).
::

View File

@ -19,7 +19,7 @@ Explore Nuxt Modules
Once you have installed the modules you can 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 twoslash [nuxt.config.ts]
export default defineNuxtConfig({
modules: [
// Using package name (recommended usage)
@ -29,7 +29,7 @@ export default defineNuxtConfig({
'./modules/example',
// Add module with inline-options
['./modules/example', { token: '123' }]
['./modules/example', { token: '123' }],
// Inline module definition
async (inlineOptions, nuxt) => { }
@ -37,7 +37,7 @@ export default defineNuxtConfig({
})
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Nuxt modules are now build-time-only, and the `buildModules` property used in Nuxt 2 is deprecated in favor of `modules`.
::

View File

@ -117,7 +117,7 @@ If you encounter these errors, the issue is almost certainly with the upstream l
In the meantime, you can tell Nuxt not to try to import these libraries by adding them to `build.transpile`:
```js
```ts twoslash
export default defineNuxtConfig({
build: {
transpile: ['sample-library']
@ -131,7 +131,7 @@ You may find that you _also_ need to add other packages that are being imported
In some cases, you may also need to manually alias the library to the CJS version, for example:
```js
```ts twoslash
export default defineNuxtConfig({
alias: {
'sample-library': 'sample-library/dist/sample-library.cjs.js'

View File

@ -9,22 +9,26 @@ By default, Nuxt doesn't check types when you run [`nuxi dev`](/docs/api/command
To enable type-checking at build or development time, install `vue-tsc` and `typescript` as development dependency:
::alert{type="warning"}
You may experience issues with the latest `vue-tsc` and `vite-plugin-checker`, used internally when type checking. For now, you may need to stay on v1 of `vue-tsc`, and follow these upstream issues for updates: [fi3ework/vite-plugin-checker#306](https://github.com/fi3ework/vite-plugin-checker/issues/306) and [vuejs/language-tools#3969](https://github.com/vuejs/language-tools/issues/3969).
::
::code-group
```bash [yarn]
yarn add --dev vue-tsc typescript
yarn add --dev vue-tsc@^1 typescript
```
```bash [npm]
npm install --save-dev vue-tsc typescript
npm install --save-dev vue-tsc@^1 typescript
```
```bash [pnpm]
pnpm add -D vue-tsc typescript
pnpm add -D vue-tsc@^1 typescript
```
```bash [bun]
bun add -D vue-tsc typescript
bun add -D vue-tsc@^1 typescript
```
::
@ -37,7 +41,7 @@ npx nuxi typecheck
To enable type-checking at build time, you can also use the [`typescript.typeCheck`](/docs/api/nuxt-config#typecheck) option in your `nuxt.config` file:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
typescript: {
typeCheck: true
@ -61,11 +65,11 @@ This file contains the recommended basic TypeScript configuration for your proje
[Read more about how to extend this configuration](/docs/guide/directory-structure/tsconfig).
::callout
::note
Nitro also [auto-generates types](/docs/guide/concepts/server-engine#typed-api-routes) for API routes. Plus, Nuxt also generates types for globally available components and [auto-imports from your composables](/docs/guide/directory-structure/composables), plus other core functionality.
::
::callout
::note
Keep in mind that all options extended from `./.nuxt/tsconfig.json` will be overwritten by the options defined in your `tsconfig.json`.
Overwriting options such as `"compilerOptions.paths"` with your own configuration will lead TypeScript to not factor in the module resolutions from `./.nuxt/tsconfig.json`. This can lead to module resolutions such as `#imports` not being recognized.
:br :br
@ -80,7 +84,7 @@ Once youve converted your codebase to TypeScript and felt familiar with it, y
In order to enable strict type checking, you have to update `nuxt.config`:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
typescript: {
strict: true

View File

@ -5,76 +5,20 @@ description: "Nuxt supports ESLint out of the box"
## ESLint
The recommended approach for Nuxt is to enable ESLint support using [`@nuxt/eslint-config`](https://github.com/nuxt/eslint-config).
The recommended approach for Nuxt is to enable ESLint support using the [`@nuxt/eslint`](https://eslint.nuxt.com/packages/module) module, that will setup project-aware ESLint configuration for you.
At the moment, this configuration will not format your files; you can set up Prettier or another tool to do so.
:::callout{icon="i-ph-lightbulb-duotone"}
The module is designed for the [new ESLint flat config format](https://eslint.org/docs/latest/use/configure/configuration-files-new) with is the [default format since ESLint v9](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/).
::alert{type=info}
We're currently working to refactor the Nuxt ESLint configuration. Subscribe to the [Nuxt ESLint roadmap](https://github.com/nuxt/eslint-config/issues/303) to follow updates.
::
If you are using the legacy `.eslintrc` config, you will need to [configure manually with `@nuxt/eslint-config`](https://eslint.nuxt.com/packages/config#legacy-config-format). We highly recommand you to migrate over the flat config to be future-proof.
:::
### Install Dependencies
## Quick Setup
Install both ESLint and the Nuxt configuration as development dependencies.
::code-group
```bash [yarn]
yarn add --dev eslint @nuxt/eslint-config
```bash
npx nuxi module add eslint
```
```bash [npm]
npm install --save-dev eslint @nuxt/eslint-config
```
Start your Nuxt app, a `eslint.config.mjs` file will be generated under your project root. You can customize it as needed.
```bash [pnpm]
pnpm add -D eslint @nuxt/eslint-config
```
```bash [bun]
bun add -D eslint @nuxt/eslint-config
```
::
### Configuration
Add `.eslintrc.cjs` to the root folder of your Nuxt app.
```js
module.exports = {
root: true,
extends: ['@nuxt/eslint-config'],
}
```
### Modify package.json
Add the below to lint commands to your `package.json` script section:
```json
"scripts": {
...
"lint": "eslint .",
"lint:fix": "eslint . --fix",
...
},
```
Run the `lint` command to check if the code style is correct or run `lint:fix` to automatically fix issues.
### Configuring VS Code
Install the [VS Code ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint).
In VS Code press `ctrl+shift+p` (`cmd+shift+p` on Mac) to open the command prompt, find `Open Workspace Settings (JSON)`, add the below lines to the JSON and save:
```json
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
```
You're good to go! On save, your files will be linted and auto-fixed.
You can learn more about the module and customizations in [Nuxt ESLint's documentation](https://eslint.nuxt.com/packages/module).

View File

@ -5,7 +5,7 @@ head.title: ".nuxt/"
navigation.icon: i-ph-folder-duotone
---
::callout{icon="i-ph-warning-duotone" color="amber"}
::important
This directory should be added to your [`.gitignore`](/docs/guide/directory-structure/gitignore) file to avoid pushing the dev build output to your repository.
::
@ -15,6 +15,6 @@ Nuxt also provides a Virtual File System (VFS) for modules to add templates to t
You can explore the generated files by opening the [Nuxt DevTools](https://devtools.nuxt.com) in development mode and navigating to the **Virtual Files** tab.
::callout{icon="i-ph-warning-duotone" color="amber"}
::warning
You should not touch any files inside since the whole directory will be re-created when running [`nuxt dev`](/docs/api/commands/dev).
::

View File

@ -5,7 +5,7 @@ head.title: ".output/"
navigation.icon: i-ph-folder-duotone
---
::callout{icon="i-ph-warning-duotone" color="amber"}
::important
This directory should be added to your [`.gitignore`](/docs/guide/directory-structure/gitignore) file to avoid pushing the build output to your repository.
::
@ -13,6 +13,6 @@ Use this directory to deploy your Nuxt application to production.
:read-more{to="/docs/getting-started/deployment"}
::callout{icon="i-ph-warning-duotone" color="amber"}
::warning
You should not touch any files inside since the whole directory will be re-created when running [`nuxt build`](/docs/api/commands/build).
::

View File

@ -40,18 +40,18 @@ If you have a component in nested directories such as:
<BaseFooButton />
```
::callout
::note
For clarity, we recommend that the component's filename matches its name. So, in the example above, you could rename `Button.vue` to be `BaseFooButton.vue`.
::
If you want to auto-import components based only on its name, not path, then you need to set `pathPrefix` option to `false` using extended form of the configuration object:
```diff [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
components: [
{
path: '~/components',
+ pathPrefix: false,
pathPrefix: false, // [!code ++]
},
],
});
@ -78,7 +78,7 @@ const MyButton = resolveComponent('MyButton')
</template>
```
::callout
::important
If you are using `resolveComponent` to handle dynamic components, make sure not to insert anything but the name of the component, which must be a string and not a variable.
::
@ -95,7 +95,7 @@ Alternatively, though not recommended, you can register all your components glob
You can also selectively register some components globally by placing them in a `~/components/global` directory, or by using a `.global.vue` suffix in the filename. As noted above, each global component is rendered in a separate chunk, so be careful not to overuse this feature.
::callout
::note
The `global` option can also be set per component directory.
::
@ -105,8 +105,8 @@ To dynamically import a component (also known as lazy-loading a component) all y
By using the `Lazy` prefix you can delay loading the component code until the right moment, which can be helpful for optimizing your JavaScript bundle size.
```html [pages/index.vue]
<script setup>
```vue [pages/index.vue]
<script setup lang="ts">
const show = ref(false)
</script>
@ -123,7 +123,7 @@ const show = ref(false)
You can also explicitly import components from `#components` if you want or need to bypass Nuxt's auto-importing functionality.
```html [pages/index.vue]
```vue [pages/index.vue]
<script setup lang="ts">
import { NuxtLink, LazyMountainsList } from '#components'
@ -144,7 +144,7 @@ const show = ref(false)
By default, only the `~/components` directory is scanned. If you want to add other directories, or change how the components are scanned within a subfolder of this directory, you can add additional directories to the configuration:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
components: [
// ~/calendar-module/components/event/Update.vue => <EventUpdate />
@ -172,7 +172,7 @@ If you want to auto-import components from an npm package, you can use [`addComp
::code-group
```ts [~/modules/register-component.ts]
```ts twoslash [~/modules/register-component.ts]
import { addComponent, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
@ -198,7 +198,7 @@ export default defineNuxtModule({
::
::callout
::note
Any nested directories need to be added first as they are scanned in order.
::
@ -207,12 +207,12 @@ Any nested directories need to be added first as they are scanned in order.
By default, any file with an extension specified in the [extensions key of `nuxt.config.ts`](/docs/api/nuxt-config#extensions) is treated as a component.
If you need to restrict the file extensions that should be registered as components, you can use the extended form of the components directory declaration and its `extensions` key:
```diff
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
components: [
{
path: '~/components',
+ extensions: ['.vue'],
extensions: ['.vue'], // [!code ++]
}
]
})
@ -227,7 +227,7 @@ If a component is meant to be rendered only client-side, you can add the `.clien
--| Comments.client.vue
```
```html [pages/example.vue]
```vue [pages/example.vue]
<template>
<div>
<!-- this component will only be rendered on client side -->
@ -236,25 +236,29 @@ If a component is meant to be rendered only client-side, you can add the `.clien
</template>
```
::callout
::note
This feature only works with Nuxt auto-imports and `#components` imports. Explicitly importing these components from their real paths does not convert them into client-only components.
::
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
`.client` components are rendered only after being mounted. To access the rendered template using `onMounted()`, add `await nextTick()` in the callback of the `onMounted()` hook.
::
::read-more{to="/docs/api/components/client-only"}
You can also achieve a similar result with the `<ClientOnly>` component.
::
## Server Components
Server components allow server-rendering individual components within your client-side apps. It's possible to use server components within Nuxt, even if you are generating a static site. That makes it possible to build complex sites that mix dynamic components, server-rendered HTML and even static chunks of markup.
Server components can either be used on their own or paired with a [client component](#paired-with-a-client-component).
::callout{color="blue" icon="i-ph-video-duotone" to="https://www.youtube.com/watch?v=u1yyXe86xJM" target="_blank"}
::tip{icon="i-ph-video-duotone" to="https://www.youtube.com/watch?v=u1yyXe86xJM" target="_blank"}
Watch Learn Vue video about Nuxt Server Components.
::
::callout{color="blue" icon="i-ph-article-duotone" to="https://roe.dev/blog/nuxt-server-components" target="_blank"}
::tip{icon="i-ph-article-duotone" to="https://roe.dev/blog/nuxt-server-components" target="_blank"}
Read Daniel Roe's guide to Nuxt server components
::
@ -266,7 +270,7 @@ When their props update, this will result in a network request that will update
Server components are currently experimental and in order to use them, you need to enable the 'component islands' feature in your nuxt.config:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
componentIslands: true
@ -281,7 +285,7 @@ Now you can register server-only components with the `.server` suffix and use th
--| HighlightedMarkdown.server.vue
```
```html [pages/example.vue]
```vue [pages/example.vue]
<template>
<div>
<!--
@ -295,6 +299,14 @@ Now you can register server-only components with the `.server` suffix and use th
Server-only components use [`<NuxtIsland>`](/docs/api/components/nuxt-island) under the hood, meaning that `lazy` prop and `#fallback` slot are both passed down to it.
::alert{type=warning}
Server components (and islands) must have a single root element. (HTML comments are considered elements as well.)
::
::alert{type=warning}
Most features for server-only components and island components, such as slots and client components, are only available for single file components.
::
#### Client components within server components
::alert{type=info}
@ -303,7 +315,7 @@ This feature needs `experimental.componentIslands.selectiveClient` within your c
You can partially hydrate a component by setting a `nuxt-client` attribute on the component you wish to be loaded client-side.
```html [components/ServerWithClient.vue]
```vue [components/ServerWithClient.vue]
<template>
<div>
<HighlightedMarkdown markdown="# Headline" />
@ -314,7 +326,7 @@ You can partially hydrate a component by setting a `nuxt-client` attribute on th
```
::alert{type=info}
This only works within a server component.
This only works within a server component. Slots for client components are working only with `experimental.componentIsland.selectiveClient` set to `'deep'` and since they are rendered server-side, they are not interactive once client-side.
::
#### Server Component Context
@ -330,7 +342,7 @@ This means:
Within an island component, you can access its island context through `nuxtApp.ssrContext.islandContext`. Note that while island components are still marked as experimental, the format of this context may change.
::callout
::note
Slots can be interactive and are wrapped within a `<div>` with `display: contents;`
::
@ -344,7 +356,7 @@ In this case, the `.server` + `.client` components are two 'halves' of a compone
--| Comments.server.vue
```
```html [pages/example.vue]
```vue [pages/example.vue]
<template>
<div>
<!-- this component will render Comments.server on the server then Comments.client once mounted in the browser -->
@ -353,87 +365,12 @@ In this case, the `.server` + `.client` components are two 'halves' of a compone
</template>
```
## `<ClientOnly>` Component
## Built-In Nuxt Components
Nuxt provides the [`<ClientOnly>`](/docs/api/components/client-only) component for purposely rendering a component only on client side.
There are a number of components that Nuxt provides, including `<ClientOnly>` and `<DevOnly>`. You can read more about them in the API documentation.
```html [pages/example.vue]
<template>
<div>
<Sidebar />
<ClientOnly>
<!-- this component will only be rendered on client-side -->
<Comments />
</ClientOnly>
</div>
</template>
```
Use a slot as fallback until `<ClientOnly>` is mounted on client side.
```html [pages/example.vue]
<template>
<div>
<Sidebar />
<!-- This renders the "span" element on the server side -->
<ClientOnly fallbackTag="span">
<!-- this component will only be rendered on client side -->
<Comments />
<template #fallback>
<!-- this will be rendered on server side -->
<p>Loading comments...</p>
</template>
</ClientOnly>
</div>
</template>
```
<!-- TODO: Add back after passing treeshakeClientOnly experiment -->
<!-- ::callout
Make sure not to _nest_ `<ClientOnly>` components or other client-only components. Nuxt performs an optimization to remove the contents of these components from the server-side render, which can break in this case.
:: -->
## `<DevOnly>` Component
Nuxt provides the `<DevOnly>` component to render a component only during development.
The content will not be included in production builds and tree-shaken.
```html [pages/example.vue]
<template>
<div>
<Sidebar />
<DevOnly>
<!-- this component will only be rendered during development -->
<LazyDebugBar />
<!-- if you ever require to have a replacement during production -->
<!-- be sure to test these using `nuxt preview` -->
<template #fallback>
<div><!-- empty div for flex.justify-between --></div>
</template>
</DevOnly>
</div>
</template>
```
## `<NuxtClientFallback>` Component
Nuxt provides the `<NuxtClientFallback>` component to render its content on the client if any of its children trigger an error in SSR.
You can specify a `fallbackTag` to make it render a specific tag if it fails to render on the server.
```html [pages/example.vue]
<template>
<div>
<Sidebar />
<!-- this component will be rendered on client-side -->
<NuxtClientFallback fallback-tag="span">
<Comments />
<BrokeInSSR />
</NuxtClientFallback>
</div>
</template>
```
::read-more{to="/docs/api"}
::
## Library Authors
@ -457,7 +394,7 @@ Imagine a directory structure like this:
Then in `awesome-ui/nuxt.js` you can use the `components:dirs` hook:
```ts
```ts twoslash
import { defineNuxtModule, createResolver } from '@nuxt/kit'
export default defineNuxtModule({
@ -476,7 +413,7 @@ export default defineNuxtModule({
That's it! Now in your project, you can import your UI library as a Nuxt module in your `nuxt.config` file:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
modules: ['awesome-ui/nuxt']
})

View File

@ -52,7 +52,7 @@ Under the hood, Nuxt auto generates the file `.nuxt/imports.d.ts` to declare the
Be aware that you have to run [`nuxi prepare`](/docs/api/commands/prepare), [`nuxi dev`](/docs/api/commands/dev) or [`nuxi build`](/docs/api/commands/build) in order to let Nuxt generate the types.
::callout
::note
If you create a composable without having the dev server running, TypeScript will throw an error, such as `Cannot find name 'useBar'.`
::
@ -105,7 +105,7 @@ export { utils } from './nested/utils.ts'
**Example:** Scan nested directories inside the `composables/` folder:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
imports: {
dirs: [

View File

@ -49,6 +49,6 @@ To render content pages, add a [catch-all route](/docs/guide/directory-structure
## Documentation
::callout
::tip{ icon="i-ph-book" }
Head over to <https://content.nuxt.com> to learn more about the Content module features, such as how to build queries and use Vue components in your Markdown files with the MDC syntax.
::

View File

@ -5,7 +5,7 @@ description: "Nuxt provides a layouts framework to extract common UI patterns in
navigation.icon: i-ph-folder-duotone
---
::callout{icon="i-ph-rocket-launch-duotone"}
::tip{icon="i-ph-rocket-launch-duotone" color="gray" }
For best performance, components placed in this directory will be automatically loaded via asynchronous import when used.
::
@ -25,19 +25,19 @@ To use a layout:
- Set a `layout` property in your page with [definePageMeta](/docs/api/utils/define-page-meta).
- Set the `name` prop of `<NuxtLayout>`.
::callout{color="blue" icon="i-ph-info-duotone"}
::note
The layout name is normalized to kebab-case, so `someLayout` becomes `some-layout`.
::
::callout{color="blue" icon="i-ph-info-duotone"}
If not layout is specified, `layouts/default.vue` will be used.
::note
If no layout is specified, `layouts/default.vue` will be used.
::
::callout{icon="i-ph-lightbulb-duotone"}
::important
If you only have a single layout in your application, we recommend using [`app.vue`](/docs/guide/directory-structure/app) instead.
::
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
Unlike other components, your layouts must have a single root element to allow Nuxt to apply transitions between layout changes - and this root element cannot be a `<slot />`.
::
@ -66,7 +66,7 @@ In a layout file, the content of the page will be displayed in the `<slot />` co
Then you can use the `custom` layout in your page:
```vue [pages/about.vue]
```vue twoslash [pages/about.vue]
<script setup lang="ts">
definePageMeta({
layout: 'custom'
@ -115,7 +115,7 @@ File | Layout Name
You can also use the [`setPageLayout`](/docs/api/utils/set-page-layout) helper to change the layout dynamically:
```vue
```vue twoslash
<script setup lang="ts">
function enableCustomLayout () {
setPageLayout('custom')
@ -175,6 +175,6 @@ definePageMeta({
::
::callout
::important
If you use `<NuxtLayout>` within your pages, make sure it is not the root element (or [disable layout/page transitions](/docs/getting-started/transitions#disable-transitions)).
::

View File

@ -15,11 +15,11 @@ There are three kinds of route middleware:
The first two kinds of route middleware can be defined in [`definePageMeta`](/docs/api/utils/define-page-meta).
::callout
::note
Name of middleware are normalized to kebab-case: `myMiddleware` becomes `my-middleware`.
::
::callout
::note
Route middleware run within the Vue part of your Nuxt app. Despite the similar name, they are completely different from [server middleware](/docs/guide/directory-structure/server#server-middleware), which are run in the Nitro server part of your app.
::
@ -27,7 +27,7 @@ Route middleware run within the Vue part of your Nuxt app. Despite the similar n
Route middleware are navigation guards that receive the current route and the next route as arguments.
```ts [middleware/my-middleware.ts]
```ts twoslash [middleware/my-middleware.ts]
export default defineNuxtRouteMiddleware((to, from) => {
if (to.params.id === '1') {
return abortNavigation()
@ -59,7 +59,7 @@ Possible return values are:
:read-more{to="/docs/api/utils/navigate-to"}
:read-more{to="/docs/api/utils/abort-navigation"}
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
We recommend using the helper functions above for performing redirects or stopping navigation. Other possible return values described in [the vue-router docs](https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards) may work but there may be breaking changes in future.
::
@ -79,7 +79,7 @@ middleware/
--| auth.ts
```
```vue [pages/profile.vue]
```vue twoslash [pages/profile.vue]
<script setup lang="ts">
definePageMeta({
middleware: [
@ -112,7 +112,7 @@ middleware/
--| auth.ts
```
::callout{color="blue" icon="i-ph-info-duotone"}
::note
In case you're new to 'alphabetical' numbering, remember that filenames are sorted as strings, not as numeric values. For example, `10.new.global.ts` would come before `2.new.global.ts`. This is why the example prefixes single digit numbers with `0`.
::
@ -122,15 +122,15 @@ If your site is server-rendered or generated, middleware for the initial page wi
However, if you want to avoid this behaviour you can do so:
```js [middleware/example.ts]
```ts twoslash [middleware/example.ts]
export default defineNuxtRouteMiddleware(to => {
// skip middleware on server
if (process.server) return
if (import.meta.server) return
// skip middleware on client side entirely
if (process.client) return
if (import.meta.client) return
// or only skip middleware on initial client load
const nuxtApp = useNuxtApp()
if (process.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) return
if (import.meta.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) return
})
```
@ -138,7 +138,7 @@ export default defineNuxtRouteMiddleware(to => {
It is possible to add global or named route middleware manually using the [`addRouteMiddleware()`](/docs/api/utils/add-route-middleware) helper function, such as from within a plugin.
```ts
```ts twoslash
export default defineNuxtPlugin(() => {
addRouteMiddleware('global-test', () => {
console.log('this global middleware was added in a plugin and will be run on every route change')
@ -159,7 +159,7 @@ export default defineNuxtPlugin(() => {
In your page file, you can reference this route middleware:
```vue
```vue twoslash
<script setup lang="ts">
definePageMeta({
middleware: ["auth"]
@ -176,7 +176,7 @@ Now, before navigation to that page can complete, the `auth` route middleware wi
Instead of using `definePageMeta` on each page, you can add named route middleware within the `pages:extend` hook.
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
import type { NuxtPage } from 'nuxt/schema'
export default defineNuxtConfig({

View File

@ -15,7 +15,7 @@ You don't need to add those local modules to your [`nuxt.config.ts`](/docs/guide
::code-group
```ts [modules/hello/index.ts]
```ts twoslash [modules/hello/index.ts]
// `nuxt/kit` is a helper subpath import you can use when defining local modules
// that means you do not need to add `@nuxt/kit` to your project's dependencies
import { createResolver, defineNuxtModule, addServerHandler } from 'nuxt/kit'
@ -36,7 +36,7 @@ export default defineNuxtModule({
})
```
```ts [modules/hello/runtime/api-route.ts]
```ts twoslash [modules/hello/runtime/api-route.ts]
export default defineEventHandler(() => {
return { hello: 'world' }
})
@ -56,3 +56,7 @@ modules/
```
:read-more{to="/docs/guide/going-further/modules"}
::tip{icon="i-ph-video-duotone" to="https://vueschool.io/lessons/creating-your-first-module-from-scratch" target="_blank"}
Watch Vue School video about Nuxt private modules.
::

View File

@ -7,6 +7,6 @@ navigation.icon: i-ph-folder-duotone
The package manager ([`npm`](https://docs.npmjs.com/cli/commands/npm) or [`yarn`](https://yarnpkg.com) or [`pnpm`](https://pnpm.io/cli/install) or [`bun`](https://bun.sh/package-manager)) creates this directory to store the dependencies of your project.
::callout
::important
This directory should be added to your [`.gitignore`](/docs/guide/directory-structure/gitignore) file to avoid pushing the dependencies to your repository.
::

View File

@ -5,8 +5,8 @@ head.title: "pages/"
navigation.icon: i-ph-folder-duotone
---
::callout
To reduce your application's bundle size, this directory is **optional**, meaning that [`vue-router`](https://router.vuejs.org) won't be included if you only use [`app.vue`](/docs/guide/directory-structure/app). To force the pages system, set `pages: true` in `nuxt.config` or have a [`app/router.options.ts`](/docs/guide/directory-structure/pages#router-options).
::note
To reduce your application's bundle size, this directory is **optional**, meaning that [`vue-router`](https://router.vuejs.org) won't be included if you only use [`app.vue`](/docs/guide/directory-structure/app). To force the pages system, set `pages: true` in `nuxt.config` or have a [`app/router.options.ts`](/docs/guide/going-further/custom-routing#using-approuteroptions).
::
## Usage
@ -23,7 +23,7 @@ Nuxt will automatically create a route for every page in your `~/pages/` directo
</template>
```
```ts [pages/index.ts]
```ts twoslash [pages/index.ts]
// https://vuejs.org/guide/extras/render-function.html
export default defineComponent({
render () {
@ -32,7 +32,7 @@ export default defineComponent({
})
```
```ts [pages/index.tsx]
```tsx twoslash [pages/index.tsx]
// https://nuxt.com/docs/examples/advanced/jsx
// https://vuejs.org/guide/extras/render-function.html#jsx-tsx
export default defineComponent({
@ -57,7 +57,7 @@ If you are using [`app.vue`](/docs/guide/directory-structure/app), make sure to
</template>
```
Pages **must have a single root element** to allow [route transitions](/docs/getting-started/transitions) between pages, HTML comments are considered elements as well.
Pages **must have a single root element** to allow [route transitions](/docs/getting-started/transitions) between pages. HTML comments are considered elements as well.
This means that when the route is server-rendered, or statically generated, you will be able to see its contents correctly, but when you navigate towards that route during client-side navigation the transition between routes will fail and you'll see that the route will not be rendered.
@ -120,7 +120,7 @@ Navigating to `/users-admins/123` would render:
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 twoslash
<script setup lang="ts">
const route = useRoute()
@ -130,7 +130,7 @@ if (route.params.group === 'admins' && !route.params.id) {
</script>
```
::callout
::note
Named parent routes will take priority over nested dynamic routes. For the `/foo/hello` route, `~/pages/foo.vue` will take priority over `~/pages/foo/[slug].vue`. :br Use `~/pages/foo/index.vue` and `~/pages/foo/[slug].vue` to match `/foo` and `/foo/hello` with different pages,.
::
@ -184,7 +184,7 @@ This file tree will generate these routes:
To display the `child.vue` component, you have to insert the `<NuxtPage>` component inside `pages/parent.vue`:
```html{}[pages/parent.vue]
```vue {}[pages/parent.vue]
<template>
<div>
<h1>I am the parent view</h1>
@ -193,11 +193,19 @@ To display the `child.vue` component, you have to insert the `<NuxtPage>` compon
</template>
```
```vue {}[pages/parent/child.vue]
<script setup lang="ts">
const props = defineProps(['foobar'])
console.log(props.foobar)
</script>
```
### Child Route Keys
If you want more control over when the `<NuxtPage>` component is re-rendered (for example, for transitions), you can either pass a string or function via the `pageKey` prop, or you can define a `key` value via `definePageMeta`:
```html{}[pages/parent.vue]
```vue {}[pages/parent.vue]
<template>
<div>
<h1>I am the parent view</h1>
@ -208,7 +216,7 @@ If you want more control over when the `<NuxtPage>` component is re-rendered (fo
Or alternatively:
```html{}[pages/child.vue]
```vue twoslash {}[pages/parent/child.vue]
<script setup lang="ts">
definePageMeta({
key: route => route.fullPath
@ -222,7 +230,7 @@ definePageMeta({
You might want to define metadata for each route in your app. You can do this using the `definePageMeta` macro, which will work both in `<script>` and in `<script setup>`:
```vue
```vue twoslash
<script setup lang="ts">
definePageMeta({
title: 'My home page'
@ -232,7 +240,7 @@ definePageMeta({
This data can then be accessed throughout the rest of your app from the `route.meta` object.
```vue
```vue twoslash
<script setup lang="ts">
const route = useRoute()
@ -322,7 +330,7 @@ This component is included with Nuxt and therefore you don't have to import it a
A simple link to the `index.vue` page in your `pages` folder:
```html
```vue
<template>
<NuxtLink to="/">Home page</NuxtLink>
</template>
@ -336,11 +344,11 @@ Learn more about `<NuxtLink>` usage.
Nuxt 3 allows programmatic navigation through the `navigateTo()` utility method. Using this utility method, you will be able to programmatically navigate the user in your app. This is great for taking input from the user and navigating them dynamically throughout your application. In this example, we have a simple method called `navigate()` that gets called when the user submits a search form.
::callout{color="blue" icon="i-ph-info-duotone"}
::note
Ensure to always `await` on `navigateTo` or chain its result by returning from functions.
::
```vue
```vue twoslash
<script setup lang="ts">
const name = ref('');
const type = ref(1);
@ -357,13 +365,25 @@ function navigate(){
</script>
```
## Custom routing
## Client-Only Pages
You can define a page as [client only](/docs/guide/directory-structure/components#client-components) by giving it a `.client.vue` suffix. None of the content of this page will be rendered on the server.
## Server-Only Pages
You can define a page as [server only](/docs/guide/directory-structure/components#server-components) by giving it a `.server.vue` suffix. While you will be able to navigate to the page using client-side navigation, controlled by `vue-router`, it will be rendered with a server component automatically, meaning the code required to render the page will not be in your client-side bundle.
::alert{type=warning}
Server-only pages must have a single root element. (HTML comments are considered elements as well.)
::
## Custom Routing
As your app gets bigger and more complex, your routing might require more flexibility. For this reason, Nuxt directly exposes the router, routes and router options for customization in different ways.
:read-more{to="/docs/guide/going-further/custom-routing"}
## Multiple pages directories
## Multiple Pages Directories
By default, all your pages should be in one `pages` directory at the root of your project.
@ -377,13 +397,13 @@ However, you can use [Nuxt Layers](/docs/getting-started/layers) to create group
-| nuxt.config.ts
```
```ts [some-app/nuxt.config.ts]
```ts twoslash [some-app/nuxt.config.ts]
// some-app/nuxt.config.ts
export default defineNuxtConfig({
})
```
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
extends: ['./some-app'],
})

View File

@ -7,11 +7,11 @@ navigation.icon: i-ph-folder-duotone
Nuxt automatically reads the files in the `plugins/` directory and loads them at the creation of the Vue application.
::callout{color="blue" icon="i-ph-info-duotone"}
All plugins inside are auto-registered, you don't need not add them to your `nuxt.config` separately.
::note
All plugins inside are auto-registered, you don't need to add them to your `nuxt.config` separately.
::
::callout{color="yellow" icon="i-ph-lightbulb-duotone"}
::note
You can use `.server` or `.client` suffix in the file name to load a plugin only on the server or client side.
::
@ -19,7 +19,7 @@ You can use `.server` or `.client` suffix in the file name to load a plugin only
Only files at the top level of the directory (or index files within any subdirectories) will be auto-registered as plugins.
```bash [Directory sturcture]
```bash [Directory structure]
-| plugins/
---| foo.ts // scanned
---| bar/
@ -32,7 +32,7 @@ Only `foo.ts` and `bar/index.ts` would be registered.
To add plugins in subdirectories, you can use the [`plugins`](/docs/api/nuxt-config#plugins-1) option in `nuxt.config.ts`:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
plugins: [
'~/plugins/bar/baz',
@ -45,7 +45,7 @@ export default defineNuxtConfig({
The only argument passed to a plugin is [`nuxtApp`](/docs/api/composables/use-nuxt-app).
```ts [plugins/hello.ts]
```ts twoslash [plugins/hello.ts]
export default defineNuxtPlugin(nuxtApp => {
// Doing something with nuxtApp
})
@ -55,7 +55,7 @@ export default defineNuxtPlugin(nuxtApp => {
It is also possible to define a plugin using an object syntax, for more advanced use cases. For example:
```ts [plugins/hello.ts]
```ts twoslash [plugins/hello.ts]
export default defineNuxtPlugin({
name: 'my-plugin',
enforce: 'pre', // or 'post'
@ -76,9 +76,9 @@ export default defineNuxtPlugin({
})
```
::callout
::note
If you are using the object-syntax, the properties may be statically analyzed in future to produce a more optimized build. So you should not define them at runtime. :br
For example, setting `enforce: process.server ? 'pre' : 'post'` would defeat any future optimization Nuxt is able to do for your plugins.
For example, setting `enforce: import.meta.server ? 'pre' : 'post'` would defeat any future optimization Nuxt is able to do for your plugins.
::
## Registration Order
@ -95,7 +95,7 @@ In this example, `02.myOtherPlugin.ts` will be able to access anything that was
This is useful in situations where you have a plugin that depends on another plugin.
::callout{color="blue" icon="i-ph-info-duotone"}
::note
In case you're new to 'alphabetical' numbering, remember that filenames are sorted as strings, not as numeric values. For example, `10.myPlugin.ts` would come before `2.myOtherPlugin.ts`. This is why the example prefixes single digit numbers with `0`.
::
@ -105,7 +105,7 @@ In case you're new to 'alphabetical' numbering, remember that filenames are sort
By default, Nuxt loads plugins sequentially. You can define a plugin as `parallel` so Nuxt won't wait the end of the plugin's execution before loading the next plugin.
```ts [plugins/my-plugin.ts]
```ts twoslash [plugins/my-plugin.ts]
export default defineNuxtPlugin({
name: 'my-plugin',
parallel: true,
@ -117,12 +117,12 @@ export default defineNuxtPlugin({
### Plugins With Dependencies
If a plugin needs to await a parallel plugin before it runs, you can add the plugin's name to the `dependsOn` array.
If a plugin needs to wait for another plugin before it runs, you can add the plugin's name to the `dependsOn` array.
```ts [plugins/depending-on-my-plugin.ts]
```ts twoslash [plugins/depending-on-my-plugin.ts]
export default defineNuxtPlugin({
name: 'depends-on-my-plugin',
dependsOn: ['my-plugin']
dependsOn: ['my-plugin'],
async setup (nuxtApp) {
// this plugin will wait for the end of `my-plugin`'s execution before it runs
}
@ -141,13 +141,13 @@ export default defineNuxtPlugin((nuxtApp) => {
However, keep in mind there are some limitations and differences:
::callout
::important
**If a composable depends on another plugin registered later, it might not work.** :br
Plugins are called in order sequentially and before everything else. You might use a composable that depends on another plugin which has not been called yet.
::
::callout
::important
**If a composable depends on the Vue.js lifecycle, it won't work.** :br
Normally, Vue.js composables are bound to the current component instance while plugins are only bound to [`nuxtApp`](/docs/api/composables/use-nuxt-app) instance.
@ -158,7 +158,7 @@ Normally, Vue.js composables are bound to the current component instance while p
If you would like to provide a helper on the [`NuxtApp`](/docs/api/composables/use-nuxt-app) instance, return it from the plugin under a `provide` key.
::code-group
```ts [plugins/hello.ts]
```ts twoslash [plugins/hello.ts]
export default defineNuxtPlugin(() => {
return {
provide: {
@ -167,7 +167,7 @@ export default defineNuxtPlugin(() => {
}
})
```
```ts [plugins/hello-object-syntax.ts]
```ts twoslash [plugins/hello-object-syntax.ts]
export default defineNuxtPlugin({
name: 'hello',
setup () {
@ -196,11 +196,11 @@ const { $hello } = useNuxtApp()
</template>
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
Note that we highly recommend using [`composables`](/docs/guide/directory-structure/composables) instead of providing helpers to avoid polluting the global namespace and keep your main bundle entry small.
::
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
**If your plugin provides a `ref` or `computed`, it will not be unwrapped in a component `<template>`.** :br
This is due to how Vue works with refs that aren't top-level to the template. You can read more about it [in the Vue documentation](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#caveat-when-unwrapping-in-templates).
::
@ -209,7 +209,7 @@ This is due to how Vue works with refs that aren't top-level to the template. Yo
If you return your helpers from the plugin, they will be typed automatically; you'll find them typed for the return of `useNuxtApp()` and within your templates.
::callout
::note
If you need to use a provided helper _within_ another plugin, you can call [`useNuxtApp()`](/docs/api/composables/use-nuxt-app) to get the typed version. But in general, this should be avoided unless you are certain of the plugins' order.
::
@ -231,7 +231,7 @@ declare module 'vue' {
export {}
```
::callout
::note
If you are using WebStorm, you may need to augment `@vue/runtime-core` until [this issue](https://youtrack.jetbrains.com/issue/WEB-59818/VUE-TypeScript-WS-PS-does-not-correctly-display-type-of-globally-injected-properties) is resolved.
::
@ -275,7 +275,7 @@ export default defineNuxtPlugin((nuxtApp) => {
Similarly, you can register a custom Vue directive in a plugin.
```ts [plugins/my-directive.ts]
```ts twoslash [plugins/my-directive.ts]
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('focus', {
mounted (el) {
@ -289,7 +289,7 @@ export default defineNuxtPlugin((nuxtApp) => {
})
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
If you register a Vue directive, you _must_ register it on both client and server side unless you are only using it when rendering one side. If the directive only makes sense from a client side, you can always move it to `~/plugins/my-directive.client.ts` and provide a 'stub' directive for the server in `~/plugins/my-directive.server.ts`.
::

View File

@ -15,13 +15,13 @@ Files contained within the `public/` directory are served at the root and are no
```
```vue [app.vue]
<script setup>
<script setup lang="ts">
useSeoMeta({
ogImage: '/og-image.png'
})
</script>
```
::callout{to="https://v2.nuxt.com/docs/directory-structure/static" target="_blank"}
::tip{to="https://v2.nuxt.com/docs/directory-structure/static" target="_blank"}
This is known as the [`static/`] directory in Nuxt 2.
::

View File

@ -21,7 +21,7 @@ Each file should export a default function defined with `defineEventHandler()` o
The handler can directly return JSON data, a `Promise`, or use `event.node.res.end()` to send a response.
```ts [server/api/hello.ts]
```ts twoslash [server/api/hello.ts]
export default defineEventHandler((event) => {
return {
hello: 'world'
@ -55,7 +55,7 @@ export default defineEventHandler(() => 'Hello World!')
Given the example above, the `/hello` route will be accessible at <http://localhost:3000/hello>.
::callout
::note
Note that currently server routes do not support the full functionality of dynamic routes as [pages](/docs/guide/directory-structure/pages#dynamic-routes) do.
::
@ -65,7 +65,7 @@ Nuxt will automatically read in any file in the `~/server/middleware` to create
Middleware handlers will run on every request before any other server route to add or check headers, log requests, or extend the event's request object.
::callout
::note
Middleware handlers should not return anything (nor close or respond to the request) and only inspect or extend the request context or throw an error.
::
@ -130,7 +130,7 @@ export const defineWrappedResponseHandler = <T extends EventHandlerRequest, D> (
## Server Types
::callout
::tip
This feature is available from Nuxt >= 3.5
::
@ -158,7 +158,7 @@ export default defineEventHandler((event) => {
})
```
::callout{icon="i-ph-lightbulb" color="green"}
::tip
Alternatively, use `getValidatedRouterParams` with a schema validator such as Zod for runtime and type safety.
::
@ -234,14 +234,14 @@ export default defineEventHandler(async (event) => {
})
```
::callout{icon="i-ph-lightbulb" color="green" to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web#runtime-type-safe-request-utils"}
::tip{to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web#runtime-type-safe-request-utils"}
Alternatively, use `readValidatedBody` with a schema validator such as Zod for runtime and type safety.
::
You can now universally call this API using:
```vue [app.vue]
<script setup>
<script setup lang="ts">
async function submit() {
const { body } = await $fetch('/api/submit', {
method: 'post',
@ -251,7 +251,7 @@ async function submit() {
</script>
```
::callout
::note
We are using `submit.post.ts` in the filename only to match requests with `POST` method that can accept the request body. When using `readBody` within a GET request, `readBody` will throw a `405 Method Not Allowed` HTTP error.
::
@ -267,7 +267,7 @@ export default defineEventHandler((event) => {
})
```
::callout{icon="i-ph-lightbulb" color="green" to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web#runtime-type-safe-request-utils"}
::tip{to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web#runtime-type-safe-request-utils"}
Alternatively, use `getValidatedQuery` with a schema validator such as Zod for runtime and type safety.
::
@ -333,7 +333,7 @@ NUXT_GITHUB_TOKEN='<my-super-token>'
```
::
::callout
::note
Giving the `event` as argument to `useRuntimeConfig` is optional, but it is recommended to pass it to get the runtime config overwritten by [environment variables](/docs/guide/going-further/runtime-config#environment-variables) at runtime for server routes.
::
@ -353,7 +353,7 @@ export default defineEventHandler((event) => {
You can use `nitro` key in `nuxt.config` to directly set [Nitro configuration](https://nitro.unjs.io/config).
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
This is an advanced option. Custom config can affect production deployments, as the configuration interface might change over time when Nitro is upgraded in semver-minor versions of Nuxt.
::
@ -380,7 +380,7 @@ export default useBase('/api/hello', router.handler)
### Sending Streams
::callout
::tip
This is an experimental feature and is available in all environments.
::
@ -409,7 +409,7 @@ export default fromNodeMiddleware((req, res) => {
})
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
Legacy support is possible using [unjs/h3](https://github.com/unjs/h3), but it is advised to avoid legacy handlers as much as you can.
::
@ -420,7 +420,7 @@ export default fromNodeMiddleware((req, res, next) => {
})
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Never combine `next()` callback with a legacy middleware that is `async` or returns a `Promise`.
::

View File

@ -11,7 +11,7 @@ The main purpose of the [`utils/` directory](/docs/guide/directory-structure/uti
**Method 1:** Using named export
```js [utils/index.ts]
```ts twoslash [utils/index.ts]
export const { format: formatNumber } = Intl.NumberFormat('en-GB', {
notation: 'compact',
maximumFractionDigits: 1
@ -20,7 +20,7 @@ export const { format: formatNumber } = Intl.NumberFormat('en-GB', {
**Method 2:** Using default export
```js [utils/random-entry.ts or utils/randomEntry.ts]
```ts twoslash [utils/random-entry.ts or utils/randomEntry.ts]
// It will be available as randomEntry() (camelCase of file name without extension)
export default function (arr: Array<any>) {
return arr[Math.floor(Math.random() * arr.length)]
@ -39,11 +39,11 @@ You can now use auto imported utility functions in `.js`, `.ts` and `.vue` files
:link-example{to="/docs/examples/features/auto-imports"}
::callout
::tip
The way `utils/` auto-imports work and are scanned is identical to the [`composables/`](/docs/guide/directory-structure/composables) directory.
::
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
These utils are only available within the Vue part of your app. :br
Only `server/utils` are auto-imported in the [`server/`](/docs/guide/directory-structure/server#server-utilities) directory.
::

View File

@ -5,7 +5,7 @@ head.title: ".env"
navigation.icon: i-ph-file-duotone
---
::callout{icon="i-ph-warning-duotone" color="amber"}
::important
This file should be added to your [`.gitignore`](/docs/guide/directory-structure/gitignore) file to avoid pushing secrets to your repository.
::
@ -19,7 +19,7 @@ In addition to any process environment variables, if you have a `.env` file in y
MY_ENV_VARIABLE=hello
```
::callout
::note
Note that removing a variable from `.env` or removing the `.env` file entirely will not unset values that have already been set.
::
@ -51,7 +51,7 @@ Note that for a purely static site, it is not possible to set runtime configurat
:read-more{to="/docs/guide/going-further/runtime-config"}
::callout
::note
If you want to use environment variables set at build time but do not care about updating these down the line (or only need to update them reactively _within_ your app) then `appConfig` may be a better choice. You can define `appConfig` both within your `nuxt.config` (using environment variables) and also within an `~/app.config.ts` file in your project.
:read-more{to="/docs/guide/directory-structure/app-config"}
::

View File

@ -9,7 +9,7 @@ The `.nuxtignore` file tells Nuxt to ignore files in your projects root direc
It is subject to the same specification as [`.gitignore`](/docs/guide/directory-structure/gitignore) and `.eslintignore` files, in which each line is a glob pattern indicating which files should be ignored.
::callout
::tip
You can also configure [`ignoreOptions`](/docs/api/nuxt-config#ignoreoptions), [`ignorePrefix`](/docs/api/nuxt-config#ignoreprefix) and [`ignore`](/docs/api/nuxt-config#ignore) in your `nuxt.config` file.
::

View File

@ -9,13 +9,13 @@ Nuxt 3 provides an `app.config` config file to expose reactive configuration wit
You can easily provide runtime app configuration using `app.config.ts` file. It can have either of `.ts`, `.js`, or `.mjs` extensions.
```ts [app.config.ts]
```ts twoslash [app.config.ts]
export default defineAppConfig({
foo: 'bar'
})
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::caution
Do not put any secret values inside `app.config` file. It is exposed to the user client bundle.
::
@ -23,7 +23,7 @@ Do not put any secret values inside `app.config` file. It is exposed to the user
To expose config and environment variables to the rest of your app, you will need to define configuration in `app.config` file.
```ts [app.config.ts]
```ts twoslash [app.config.ts]
export default defineAppConfig({
theme: {
primaryColor: '#ababab'
@ -34,7 +34,7 @@ export default defineAppConfig({
When adding `theme` to the `app.config`, Nuxt uses Vite or webpack to bundle the code. We can universally access `theme` both when server-rendering the page and in the browser using [`useAppConfig`](/docs/api/composables/use-app-config) composable.
```vue [pages/index.vue]
<script setup>
<script setup lang="ts">
const appConfig = useAppConfig()
console.log(appConfig.theme)
@ -72,7 +72,7 @@ export {}
If you want to type the result of calling [`useAppConfig()`](/docs/api/composables/use-app-config), then you will want to extend `AppConfig`.
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Be careful when typing `AppConfig` as you will overwrite the types Nuxt infers from your actually defined app config.
::
@ -98,22 +98,22 @@ Nuxt uses a custom merging strategy for the `AppConfig` within [the layers](/doc
This strategy is implemented using a [Function Merger](https://github.com/unjs/defu#function-merger), which allows defining a custom merging strategy for every key in `app.config` that has an array as value.
::callout
The Function Merger should only be used in the base `app.config` of your application.
::note
The function merger can only be used in the extended layers and not the main `app.config` in project.
::
Here's an example of how you can use:
::code-group
```ts [layer/app.config.ts]
```ts twoslash [layer/app.config.ts]
export default defineAppConfig({
// Default array value
array: ['hello'],
})
```
```ts [app.config.ts]
```ts twoslash [app.config.ts]
export default defineAppConfig({
// Overwrite default array value by using a merger function
array: () => ['bonjour'],

View File

@ -31,11 +31,11 @@ If you have a [`pages/`](/docs/guide/directory-structure/pages) directory, to di
</template>
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Since [`<NuxtPage>`](/docs/api/components/nuxt-page) internally uses Vue's [`<Suspense>`](https://vuejs.org/guide/built-ins/suspense.html#suspense) component, it cannot be set as a root element.
::
::callout{color="blue" icon="i-ph-info-duotone"}
::note
Remember that `app.vue` acts as the main component of your Nuxt application. Anything you add to it (JS and CSS) will be global and included in every page.
::

View File

@ -0,0 +1,55 @@
---
title: "error.vue"
description: "The error.vue file is the error page in your Nuxt application."
head.title: "error.vue"
navigation.icon: i-ph-file-duotone
---
During the lifespan of your application, some errors may appear unexpectedly at runtime. In such case, we can use the `error.vue` file to override the default error files and display the error nicely.
```vue [error.vue]
<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps({
error: Object as () => NuxtError
})
</script>
<template>
<div>
<h1>{{ error.statusCode }}</h1>
<NuxtLink to="/">Go back home</NuxtLink>
</div>
</template>
```
::note
Although it is called an 'error page' it's not a route and shouldn't be placed in your `~/pages` directory. For the same reason, you shouldn't use `definePageMeta` within this page. That being said, you can still use layouts in the error file, by utilizing the [`NuxtLayout`](/docs/api/components/nuxt-layout) component and specifying the name of the layout.
::
The error page has a single prop - `error` which contains an error for you to handle.
The `error` object provides the following fields:
```ts
{
statusCode: number
fatal: boolean
unhandled: boolean
statusMessage?: string
data?: unknown
cause?: unknown
}
```
If you have an error with custom fields they will be lost; you should assign them to `data` instead:
```ts
throw createError({
statusCode: 404,
statusMessage: 'Page Not Found',
data: {
myCustomField: true
}
})
```

View File

@ -7,19 +7,19 @@ navigation.icon: i-ph-file-duotone
The `nuxt.config` file extension can either be `.js`, `.ts` or `.mjs`.
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
// My Nuxt config
})
```
::callout
::tip
`defineNuxtConfig` helper is globally available without import.
::
You can explicitly import `defineNuxtConfig` from `nuxt/config` if you prefer:
```ts [nuxt.config.ts]
```ts twoslash [nuxt.config.ts]
import { defineNuxtConfig } from 'nuxt/config'
export default defineNuxtConfig({
@ -33,7 +33,7 @@ Discover all the available options in the **Nuxt configuration** documentation.
To ensure your configuration is up to date, Nuxt will make a full restart when detecting changes in the main configuration file, the [`.env`](/docs/guide/directory-structure/env), [`.nuxtignore`](/docs/guide/directory-structure/nuxtignore) and `.nuxtrc` dotfiles.
The `.nuxtrc` file is a file that can be used to configure Nuxt with a fla syntax, it is based on [`unjs/rc9`](https://github.com/unjs/rc9).
The `.nuxtrc` file can be used to configure Nuxt with a flat syntax. It is based on [`unjs/rc9`](https://github.com/unjs/rc9).
``` [.nuxtrc]
ssr=false

View File

@ -15,10 +15,10 @@ You can benefit from this by creating a `tsconfig.json` in the root of your proj
}
```
::callout
::note
As you need to, you can customize the contents of this file. However, it is recommended that you don't overwrite `target`, `module` and `moduleResolution`.
::
::callout
::note
If you need to customize your `paths`, this will override the auto-generated path aliases. Instead, we recommend that you add any path aliases you need to the [`alias`](/docs/api/nuxt-config#alias) property within your `nuxt.config`, where they will get picked up and added to the auto-generated `tsconfig`.
::

View File

@ -7,7 +7,7 @@ The Nuxt experimental features can be enabled in the Nuxt configuration file.
Internally, Nuxt uses `@nuxt/schema` to define these experimental features. You can refer to the [API documentation](/docs/api/configuration/nuxt-config#experimental) or the [source code](https://github.com/nuxt/nuxt/blob/main/packages/schema/src/config/experimental.ts) for more information.
::callout
::note
Note that these features are experimental and could be removed or modified in the future.
::
@ -15,8 +15,8 @@ Note that these features are experimental and could be removed or modified in th
Enable native async context to be accessible for nested composables in Nuxt and in Nitro. This opens the possibility to use composables inside async composables and reduce the chance to get the `Nuxt instance is unavailable` error.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
asyncContext: true
}
@ -31,8 +31,8 @@ See full explanation on the GitHub pull-request.
Enables generation of an async entry point for the Vue bundle, aiding module federation support.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
asyncEntry: true
}
@ -45,15 +45,15 @@ Externalizes `vue`, `@vue/*` and `vue-router` when building.
*Enabled by default.*
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
externalVue: true
}
})
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
This feature will likely be removed in a near future.
::
@ -63,8 +63,8 @@ Tree shakes contents of client-only components from server bundle.
*Enabled by default.*
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
treeshakeClientOnly: true
}
@ -77,8 +77,8 @@ Emits `app:chunkError` hook when there is an error loading vite/webpack chunks.
You can disable automatic handling by setting this to `false`, or handle chunk errors manually by setting it to `manual`.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
emitRouteChunkError: 'automatic' // or 'manual' or false
}
@ -91,13 +91,13 @@ Allows Nuxt app state to be restored from `sessionStorage` when reloading the pa
To avoid hydration errors, it will be applied only after the Vue app has been mounted, meaning there may be a flicker on initial load.
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
Consider carefully before enabling this as it can cause unexpected behavior,
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]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
restoreState: true
}
@ -108,8 +108,8 @@ export defineNuxtConfig({
Define route rules at the page level using [`defineRouteRules`](/docs/api/utils/define-route-rules).
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
inlineRouteRules: true
}
@ -130,8 +130,8 @@ Allows rendering of JSON payloads with support for revivifying complex types.
*Enabled by default.*
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
renderJsonPayloads: true
}
@ -142,8 +142,8 @@ export defineNuxtConfig({
Disables Vue server renderer endpoint within Nitro.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
noVueServer: true
}
@ -154,8 +154,8 @@ export defineNuxtConfig({
Enables extraction of payloads of pages generated with `nuxt generate`.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
payloadExtraction: true
}
@ -166,8 +166,8 @@ export defineNuxtConfig({
Enables the experimental [`<NuxtClientFallback>`](/docs/api/components/nuxt-client-fallback) component for rendering content on the client if there's an error in SSR.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
clientFallback: true
}
@ -178,8 +178,8 @@ export defineNuxtConfig({
Enables cross-origin prefetch using the Speculation Rules API.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
crossOriginPrefetch: true
}
@ -194,8 +194,8 @@ Read more about the **Speculation Rules API**.
Enables View Transition API integration with client-side router.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
viewTransition: true
}
@ -212,8 +212,8 @@ Read more about the **View Transition API**.
Enables writing of early hints when using node server.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
writeEarlyHints: true
}
@ -224,8 +224,8 @@ export defineNuxtConfig({
Enables experimental component islands support with [`<NuxtIsland>`](/docs/api/components/nuxt-island) and `.island.vue` files.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
componentIslands: true // false or 'local+remote'
}
@ -244,8 +244,8 @@ Enables config schema support.
*Enabled by default.*
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
configSchema: true
}
@ -256,8 +256,8 @@ export defineNuxtConfig({
Adds a compatibility layer for modules, plugins, or user code relying on the old `@vueuse/head` API.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
polyfillVueUseHead: false
}
@ -268,8 +268,8 @@ export defineNuxtConfig({
Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header.
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
respectNoSSRHeader: false
}
@ -282,8 +282,8 @@ Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to th
*Enabled by default.*
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
localLayerAliases: true
}
@ -294,8 +294,8 @@ export defineNuxtConfig({
Enable the new experimental typed router using [`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router).
```ts [nuxt.config.ts]
export defineNuxtConfig({
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
typedPages: true
}
@ -318,12 +318,12 @@ performance in large projects or on Windows platforms.
You can also set this to `chokidar` to watch all files in your source directory.
```ts [nuxt.config.ts]
export defineNuxtConfig({
experimental: {
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
watcher: 'chokidar-granular' // 'chokidar' or 'parcel' are also options
}
})
}
})
```
## sharedPrerenderData
@ -332,17 +332,14 @@ Enabling this feature automatically shares payload *data* between pages that are
in a significant performance improvement when prerendering sites that use `useAsyncData` or `useFetch` and
fetch the same data in different pages.
```ts [nuxt.config.ts]
export defineNuxtConfig({
experimental: {
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
sharedPrerenderData: true
}
})
}
})
```
Note that by default Nuxt will render pages concurrently, meaning this does not guarantee that data will
not be fetched more than once.
It is particularly important when enabling this feature to make sure that any unique key of your data
is always resolvable to the same data. For example, if you are using `useAsyncData` to fetch
data related to a particular page, you should provide a key that uniquely matches that data. (`useFetch`
@ -374,3 +371,25 @@ import { Buffer } from 'node:buffer'
globalThis.Buffer = globalThis.Buffer || Buffer
```
::
## scanPageMeta
This option allows exposing some route metadata defined in `definePageMeta` at build-time to modules (specifically `alias`, `name`, `path`, `redirect`).
This only works with static or strings/arrays rather than variables or conditional assignment. See [original issue](https://github.com/nuxt/nuxt/issues/24770) for more information and context.
## cookieStore
Enables CookieStore support to listen for cookie updates (if supported by the browser) and refresh `useCookie` ref values.
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
cookieStore: true
}
})
```
::read-more{icon="i-simple-icons-mdnwebdocs" color="gray" to="https://developer.mozilla.org/en-US/docs/Web/API/CookieStore" target="_blank"}
Read more about the **CookieStore**.
::

View File

@ -14,7 +14,7 @@ Inlines styles when rendering HTML. This is currently available only when using
You can also pass a function that receives the path of a Vue component and returns a boolean indicating whether to inline the styles for that component.
```ts [nuxt.config.ts]
export defineNuxtConfig({
export default defineNuxtConfig({
features: {
inlineStyles: true // or a function to determine inlining
}
@ -26,7 +26,7 @@ export defineNuxtConfig({
Disables rendering of Nuxt scripts and JS resource hints. Can also be configured granularly within `routeRules`.
```ts [nuxt.config.ts]
export defineNuxtConfig({
export default defineNuxtConfig({
features: {
noScripts: true
}
@ -47,7 +47,7 @@ It improves type support when using modern libraries with `exports`.
See [the original TypeScript pull request](https://github.com/microsoft/TypeScript/pull/51669).
```ts [nuxt.config.ts]
export defineNuxtConfig({
export default defineNuxtConfig({
future: {
typescriptBundlerResolution: true
}

View File

@ -29,7 +29,7 @@ console.log(runtimeConfig.apiSecret)
console.log(runtimeConfig.public.apiBase)
```
::callout
::tip
Public runtime config is accessible in Vue templates with `$config.public`.
::
@ -43,7 +43,7 @@ Instead of passing non-serializable objects or functions into your application f
The most common way to provide configuration is by using [Environment Variables](https://medium.com/chingu/an-introduction-to-environment-variables-and-how-to-use-them-f602f66d15fa).
::callout
::note
Nuxi CLI has built-in support for reading your `.env` file in development, build and generate. But when you run your built server, **your `.env` file will not be read**.
:read-more{to="/docs/guide/directory-structure/env"}
::
@ -56,7 +56,7 @@ There are two key requirements:
1. Only a specially-named environment variable can override a runtime config property. That is, an uppercase environment variable starting with `NUXT_` which uses `_` to separate keys and case changes.
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Setting the default of `runtimeConfig` values to *differently named environment variables* (for example setting `myVar` to `process.env.OTHER_VARIABLE`) will only work during build-time and will break on runtime.
It is advised to use environment variables that match the structure of your `runtimeConfig` object.
::
@ -85,7 +85,7 @@ export default defineNuxtConfig({
Within the Vue part of your Nuxt app, you will need to call [`useRuntimeConfig()`](/docs/api/composables/use-runtime-config) to access the runtime config.
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
The behavior is different between the client-side and server-side:
- On client-side, only keys in `runtimeConfig.public` are available, and the object is both writable and reactive.
@ -98,7 +98,7 @@ The behavior is different between the client-side and server-side:
const config = useRuntimeConfig()
console.log('Runtime config:', config)
if (process.server) {
if (import.meta.server) {
console.log('API secret:', config.apiSecret)
}
</script>
@ -110,7 +110,7 @@ if (process.server) {
</template>
```
::callout{icon="i-ph-flag-duotone" color="red"}
::caution
**Security note:** Be careful not to expose runtime config keys to the client-side by either rendering them or passing them to `useState`.
::
@ -142,7 +142,7 @@ export default defineEventHandler(async (event) => {
})
```
::callout
::note
Giving the `event` as argument to `useRuntimeConfig` is optional, but it is recommended to pass it to get the runtime config overwritten by [environment variables](/docs/guide/going-further/runtime-config#environment-variables) at runtime for server routes.
::
@ -164,3 +164,7 @@ declare module 'nuxt/schema' {
// It is always important to ensure you import/export something when augmenting a type
export {}
```
::note
`nuxt/schema` is provided as a convenience for end-users to access the version of the schema used by Nuxt in their project. Module authors should instead augment `@nuxt/schema`.
::

View File

@ -11,7 +11,7 @@ You can use these 'nightly' releases to beta test new features and changes.
The build and publishing method and quality of these 'nightly' releases are the same as stable ones. The only difference is that you should often check the GitHub repository for updates. There is a slight chance of regressions not being caught during the review process and by the automated tests. Therefore, we internally use this channel to double-check everything before each release.
::callout
::note
Features that are only available on the nightly release channel are marked with an alert in the documentation.
::
@ -47,7 +47,7 @@ Remove lockfile (`package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, or `bun.loc
## Using Nightly `nuxi`
::callout
::note
All cli dependencies are bundled because of the building method for reducing `nuxi` package size. :br You can get dependency updates and CLI improvements using the nightly release channel.
::

View File

@ -3,7 +3,7 @@ title: "Lifecycle Hooks"
description: "Nuxt provides a powerful hooking system to expand almost every aspect using hooks."
---
::callout
::tip
The hooking system is powered by [unjs/hookable](https://github.com/unjs/hookable).
::

View File

@ -30,6 +30,10 @@ This will create a `my-module` project with all the boilerplate necessary to dev
Learn how to perform basic tasks with the module starter.
::tip{icon="i-ph-video-duotone" to="https://vueschool.io/lessons/navigating-the-official-starter-template" target="_blank"}
Watch Vue School video about Nuxt module starter template.
::
#### How to Develop
While your module source code lives inside the `src` directory, in most cases, to develop a module, you need a Nuxt application. That's what the `playground` directory is about. It's a Nuxt application you can tinker with that is already configured to run with your module.
@ -39,7 +43,7 @@ You can interact with the playground like with any Nuxt application.
- Launch its development server with `npm run dev`, it should reload itself as you make changes to your module in the `src` directory
- Build it with `npm run dev:build`
::callout{color="blue" icon="i-ph-info-duotone"}
::note
All other `nuxi` commands can be used against the `playground` directory (e.g. `nuxi <COMMAND> playground`). Feel free to declare additional `dev:*` scripts within your `package.json` referencing them for convenience.
::
@ -50,7 +54,7 @@ The module starter comes with a basic test suite:
- A linter powered by [ESLint](https://eslint.org), run it with `npm run lint`
- A test runner powered by [Vitest](https://vitest.dev), run it with `npm run test` or `npm run test:watch`
::callout
::tip
Feel free to augment this default test strategy to better suit your needs.
::
@ -60,13 +64,13 @@ Nuxt Modules come with their own builder provided by [`@nuxt/module-builder`](ht
You can build your module by running `npm run prepack`.
::callout
::tip
While building your module can be useful in some cases, most of the time you won't need to build it on your own: the `playground` takes care of it while developing, and the release script also has you covered when publishing.
::
#### How to Publish
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
Before publishing your module to npm, makes sure you have an [npmjs.com](https://www.npmjs.com) account and that you're authenticated to it locally with `npm login`.
::
@ -85,7 +89,7 @@ When running the release script, the following will happen:
- Publishing the module to npm (for that purpose, the module will be built again to ensure its updated version number is taken into account in the published artifact)
- Pushing a git tag representing the newly published version to your git remote origin
::callout
::tip
As with other scripts, feel free to fine-tune the default `release` script in your `package.json` to better suit your needs.
::
@ -104,7 +108,7 @@ In either case, their anatomy is similar.
#### Module Definition
::callout
::note
When using the starter, your module definition is available at `src/module.ts`.
::
@ -179,7 +183,7 @@ Ultimately `defineNuxtModule` returns a wrapper function with the lower level `(
#### Runtime Directory
::callout
::note
When using the starter, the runtime directory is available at `src/runtime`.
::
@ -203,11 +207,11 @@ Or any other kind of asset you want to inject in users' Nuxt applications:
You'll then be able to inject all those assets inside the application from your [module definition](#module-definition).
::callout
::tip
Learn more about asset injection in [the recipes section](#recipes).
::
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Published modules cannot leverage auto-imports for assets within their runtime directory. Instead, they have to import them explicitly from `#imports` or alike.
Indeed, auto-imports are not enabled for files within `node_modules` (the location where a published module will eventually live) for performance reasons.
@ -255,6 +259,10 @@ export default defineNuxtModule({
When you need to handle more complex configuration alterations, you should consider using [defu](https://github.com/unjs/defu).
::tip{icon="i-ph-video-duotone" to="https://vueschool.io/lessons/extending-and-altering-nuxt-configuration-and-options" target="_blank"}
Watch Vue School video about altering Nuxt configuration.
::
#### Exposing Options to Runtime
Because modules aren't part of the application runtime, their options aren't either. However, in many cases, you might need access to some of these module options within your runtime code. We recommend exposing the needed config using Nuxt's [`runtimeConfig`](/docs/api/nuxt-config#runtimeconfig).
@ -282,12 +290,16 @@ You can then access your module options in a plugin, component, the application
const options = useRuntimeConfig().public.myModule
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Be careful not to expose any sensitive module configuration on the public runtime config, such as private API keys, as they will end up in the public bundle.
::
:read-more{to="/docs/guide/going-further/runtime-config"}
::tip{icon="i-ph-video-duotone" to="https://vueschool.io/lessons/passing-and-exposing-module-options" target="_blank"}
Watch Vue School video about passing and exposing Nuxt module options.
::
#### Injecting Plugins With `addPlugin`
Plugins are a common way for a module to add runtime logic. You can use the `addPlugin` utility to register them from your module.
@ -344,8 +356,8 @@ export default defineNuxtModule({
setup(options, nuxt) {
const resolver = createResolver(import.meta.url)
addComponentsDir({
path: resolver.resolve('runtime/components')
addComponentsDir({
path: resolver.resolve('runtime/components')
})
}
})
@ -364,8 +376,8 @@ export default defineNuxtModule({
addImports({
name: 'useComposable', // name of the composable to be used
as: 'useComposable',
from: resolver.resolve('runtime/composables/useComposable') // path of composable
as: 'useComposable',
from: resolver.resolve('runtime/composables/useComposable') // path of composable
})
}
})
@ -396,7 +408,7 @@ export default defineNuxtModule({
addServerHandler({
route: '/api/hello',
handler: resolver.resolve('./runtime/server/api/hello/index.get.ts')
handler: resolver.resolve('./runtime/server/api/hello/index.get')
})
}
})
@ -413,7 +425,7 @@ export default defineNuxtModule({
addServerHandler({
route: '/api/hello/:name',
handler: resolver.resolve('./runtime/server/api/hello/[name].get.ts')
handler: resolver.resolve('./runtime/server/api/hello/[name].get')
})
}
})
@ -462,7 +474,7 @@ If your module depends on other modules, you can add them by using Nuxt Kit's `i
```ts
import { defineNuxtModule, createResolver, installModule } from '@nuxt/kit'
export default defineNuxtModule<ModuleOptions>({
export default defineNuxtModule<ModuleOptions>({
async setup (options, nuxt) {
const { resolve } = createResolver(import.meta.url)
@ -511,9 +523,14 @@ export default defineNuxtModule({
:read-more{to="/docs/api/advanced/hooks"}
::callout
**Module cleanup**
::tip{icon="i-ph-video-duotone" to="https://vueschool.io/lessons/nuxt-lifecycle-hooks" target="_blank"}
Watch Vue School video about using Nuxt lifecycle hooks in modules.
::
::note
**Module cleanup**
:br
:br
If your module opens, handles, or starts a watcher, you should close it when the Nuxt lifecycle is done. The `close` hook is available for this.
```ts
@ -527,7 +544,6 @@ export default defineNuxtModule({
}
})
```
::
#### Adding Templates/Virtual Files
@ -592,7 +608,7 @@ If you need to update your templates/virtual files, you can leverage the `update
```ts
nuxt.hook('builder:watch', async (event, path) => {
if (path.includes('my-module-feature.config')) {
if (path.includes('my-module-feature.config')) {
// This will reload the template that you registered
updateTemplates({ filter: t => t.filename === 'my-module-feature.mjs' })
}
@ -605,7 +621,7 @@ Testing helps ensuring your module works as expected given various setup. Find i
#### Unit and Integration
::callout
::tip
We're still discussing and exploring how to ease unit and integration testing on Nuxt Modules.
[Check out this RFC to join the conversation](https://github.com/nuxt/nuxt/discussions/18399).
@ -661,7 +677,7 @@ describe('ssr', async () => {
describe('csr', async () => { /* ... */ })
```
::callout
::tip
An example of such a workflow is available on [the module starter](https://github.com/nuxt/starter/blob/module/test/basic.test.ts).
::
@ -683,7 +699,7 @@ As we've seen, Nuxt Modules can be asynchronous. For example, you may want to de
However, be careful with asynchronous behaviors as Nuxt will wait for your module to setup before going to the next module and starting the development server, build process, etc. Prefer deferring time-consuming logic to Nuxt hooks.
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
If your module takes more than **1 second** to setup, Nuxt will emit a warning about it.
::
@ -733,6 +749,10 @@ The module starter comes with a default set of tools and configurations (e.g. ES
[Nuxt Module ecosystem](/modules) represents more than 15 million monthly NPM downloads and provides extended functionalities and integrations with all sort of tools. You can be part of this ecosystem!
::tip{icon="i-ph-video-duotone" to="https://vueschool.io/lessons/exploring-nuxt-modules-ecosystem-and-module-types" target="_blank"}
Watch Vue School video about Nuxt module types.
::
### Module Types
**Official modules** are modules prefixed (scoped) with `@nuxt/` (e.g. [`@nuxt/content`](https://content.nuxtjs.org)). They are made and maintained actively by the Nuxt team. Like with the framework, contributions from the community are more than welcome to help make them better!

View File

@ -31,7 +31,7 @@ import { useNuxt } from '@nuxt/kit'
:read-more{to="/docs/api/kit"}
::callout
::note
Nuxt Kit utilities are only available for modules and not meant to be imported in runtime (components, Vue composables, pages, plugins, or server routes).
::

View File

@ -19,6 +19,14 @@ In Nuxt 2, this was referred to as **Nuxt context**.
Jump over the `NuxtApp` interface documentation.
::
## The Nuxt Context
Many composables and utilities, both built-in and user-made, may require access to the Nuxt instance. This doesn't exist everywhere on your application, because a fresh instance is created on every request.
Currently, the Nuxt context is only accessible in [plugins](/docs/guide/directory-structure/plugins), [Nuxt hooks](/docs/guide/going-further/hooks), [Nuxt middleware](/docs/guide/directory-structure/middleware), and [setup functions](https://vuejs.org/api/composition-api-setup.html) (in pages and components).
If a composable is called without access to the context, you may get an error stating that 'A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function.' In that case, you can also explicitly call functions within this context by using [`nuxtApp.runWithContext`](/docs/api/composables/use-nuxt-app#runwithcontext).
## Accessing NuxtApp
Within composables, plugins and components you can access `nuxtApp` with [`useNuxtApp()`](/docs/api/composables/use-nuxt-app):

View File

@ -17,7 +17,9 @@ Additionally, certain other files in the layer directory will be auto-scanned an
- [`components/*`](/docs/guide/directory-structure/components) - Extend the default components
- [`composables/*`](/docs/guide/directory-structure/composables) - Extend the default composables
- [`layouts/*`](/docs/guide/directory-structure/layouts) - Extend the default layouts
- [`pages/*`](/docs/guide/directory-structure/pages) - Extend the default pages
- [`plugins/*`](/docs/guide/directory-structure/plugins) - Extend the default plugins
- [`server/*`](/docs/guide/directory-structure/server) - Extend the default server endpoints & middleware
- [`utils/*`](/docs/guide/directory-structure/utils) - Extend the default utils
- [`nuxt.config.ts`](/docs/guide/directory-structure/nuxt-config)- Extend the default nuxt config
@ -94,11 +96,15 @@ export default defineNuxtConfig({
})
```
::callout
::tip
If you want to extend a private remote source, you need to add the environment variable `GIGET_AUTH=<token>` to provide a token.
::
::callout{color="blue" icon="i-ph-info-duotone"}
::tip
If you want to extend a remote source from a self-hosted GitHub or GitLab instance, you need to supply its URL with the `GIGET_GITHUB_URL=<url>` or `GIGET_GITLAB_URL=<url>` environment variable - or directly configure it with [the `auth` option](https://github.com/unjs/c12#extending-config-layer-from-remote-sources) in your `nuxt.config`.
::
::note
When using git remote sources, if a layer has npm dependencies and you wish to install them, you can do so by specifying `install: true` in your layer options.
```ts [nuxt.config.ts]
@ -142,13 +148,13 @@ To publish a layer directory as an npm package, you want to make sure that the `
}
```
::callout
::important
Make sure any dependency imported in the layer is **explicitly added** to the `dependencies`. The `nuxt` dependency, and anything only used for testing the layer before publishing, should remain in the `devDependencies` field.
::
Now you can proceed to publish the module to npm, either publicly or privately.
::callout{color="amber" icon="i-ph-warning-duotone"}
::important
When publishing the layer as a private npm package, you need to make sure you log in, to authenticate with npm to download the node module.
::

View File

@ -28,7 +28,7 @@ export default <RouterConfig> {
}
```
::callout
::note
Nuxt will not augment any new routes you return from the `routes` function with metadata defined in `definePageMeta` of the component you provide. If you want that to happen, you should use the `pages:extend` hook which is [called at build-time](/docs/api/advanced/hooks#nuxt-hooks-build-time).
::
@ -92,6 +92,27 @@ export default <RouterConfig> {
}
```
It is possible to add more router options files by adding files within the `pages:routerOptions` hook. Later items in the array override earlier ones.
::alert
Adding a router options file in this hook will switch on page-based routing, unless `optional` is set, in which case it will only apply when page-based routing is already enabled.
::
```ts [nuxt.config.ts]
export default defineNuxtConfig({
hooks: {
'pages:routerOptions' ({ files }) {
const resolver = createResolver(import.meta.url)
// add a route
files.push({
path: resolver.resolve('./runtime/app/router-options'),
optional: true
})
}
}
})
```
### Using `nuxt.config`
**Note:** Only JSON serializable [options](/docs/api/nuxt-config#router) are configurable:
@ -130,7 +151,7 @@ export default defineNuxtConfig({
### Scroll Behavior for hash links
You can optionally customize the scroll behavior for hash links. When you set the [config](/docs/api/nuxt-config#router) to be `smooth` and you load a page with a hash link (e.g. `https://example.com/blog/my-article#comments`), you will see that the browser smoothly scrolls to this anchor.
```ts [nuxt.config.ts]
export default defineNuxtConfig({
router: {
@ -151,6 +172,6 @@ import { createMemoryHistory } from 'vue-router'
export default <RouterConfig> {
// https://router.vuejs.org/api/interfaces/routeroptions.html
history: base => process.client ? createMemoryHistory(base) : null /* default */
history: base => import.meta.client ? createMemoryHistory(base) : null /* default */
}
```

View File

@ -17,6 +17,19 @@ export default defineNuxtConfig({
})
```
## Debugging with Node Inspector
You can use [Node inspector](https://nodejs.org/en/learn/getting-started/debugging) to debug Nuxt server-side.
```bash
nuxi dev --inspect
```
This will start Nuxt in `dev` mode with debugger active. If everything is working correctly a Node.js icon will appear on your Chrome DevTools and you can attach to the debugger.
::important
Note that the Node.js and Chrome processes need to be run on the same platform. This doesn't work inside of Docker.
::
## Debugging in Your IDE
It is possible to debug your Nuxt app in your IDE while you are developing it.
@ -25,6 +38,10 @@ It is possible to debug your Nuxt app in your IDE while you are developing it.
You may need to update the config below with a path to your web browser. For more information, visit the [VS Code documentation about debug configuration](https://go.microsoft.com/fwlink/?linkid=830387).
::important
If you use `pnpm`, you will need to have `nuxi` installed as a devDependency for the configuration below to work.
::
```json5
{
// Use IntelliSense to learn about possible attributes.

View File

@ -8,7 +8,11 @@ links:
size: xs
---
The `<ClientOnly>` component renders its slot only in client-side. To import a component only on the client, register the component in a client-side only plugin.
The `<ClientOnly>` component is used for purposely rendering a component only on client side.
::note
The content of the default slot will be tree-shaken out of the server build. (This does mean that any CSS used by components within it may not be inlined when rendering the initial HTML.)
::
## Props
@ -19,6 +23,7 @@ The `<ClientOnly>` component renders its slot only in client-side. To import a c
<template>
<div>
<Sidebar />
<!-- The <Comment> component will only be rendered on client-side -->
<ClientOnly fallback-tag="span" fallback="Loading comments...">
<Comment />
</ClientOnly>
@ -28,14 +33,16 @@ The `<ClientOnly>` component renders its slot only in client-side. To import a c
## Slots
- `#fallback`: specify a content to be displayed server-side.
- `#fallback`: specify a content to be rendered on the server and displayed until `<ClientOnly>` is mounted in the browser.
```vue
```vue [pages/example.vue]
<template>
<div>
<Sidebar />
<ClientOnly>
<!-- ... -->
<!-- This renders the "span" element on the server side -->
<ClientOnly fallbackTag="span">
<!-- this component will only be rendered on client side -->
<Comments />
<template #fallback>
<!-- this will be rendered on server side -->
<p>Loading comments...</p>

View File

@ -0,0 +1,51 @@
---
title: '<DevOnly>'
description: Render components only during development with the <DevOnly> component.
links:
- label: Source
icon: i-simple-icons-github
to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/dev-only.ts
size: xs
---
Nuxt provides the `<DevOnly>` component to render a component only during development.
The content will not be included in production builds.
```vue [pages/example.vue]
<template>
<div>
<Sidebar />
<DevOnly>
<!-- this component will only be rendered during development -->
<LazyDebugBar />
<!-- if you ever require to have a replacement during production -->
<!-- be sure to test these using `nuxt preview` -->
<template #fallback>
<div><!-- empty div for flex.justify-between --></div>
</template>
</DevOnly>
</div>
</template>
```
## Slots
- `#fallback`: if you ever require to have a replacement during production.
```vue
<template>
<div>
<Sidebar />
<DevOnly>
<!-- this component will only be rendered during development -->
<LazyDebugBar />
<!-- be sure to test these using `nuxt preview` -->
<template #fallback>
<div><!-- empty div for flex.justify-between --></div>
</template>
</DevOnly>
</div>
</template>
```

View File

@ -12,10 +12,25 @@ links:
size: xs
---
::callout{to="/docs/guide/going-further/experimental-features#clientfallback"}
Nuxt provides the `<NuxtClientFallback>` component to render its content on the client if any of its children trigger an error in SSR.
::note{to="/docs/guide/going-further/experimental-features#clientfallback"}
This component is experimental and in order to use it you must enable the `experimental.clientFallback` option in your `nuxt.config`.
::
```vue [pages/example.vue]
<template>
<div>
<Sidebar />
<!-- this component will be rendered on client-side -->
<NuxtClientFallback fallback-tag="span">
<Comments />
<BrokeInSSR />
</NuxtClientFallback>
</div>
</template>
```
## Events
- `@ssr-error`: Event emitted when a child triggers an error in SSR. Note that this will only be triggered on the server.
@ -30,7 +45,7 @@ This component is experimental and in order to use it you must enable the `exper
## Props
- `placeholderTag` | `fallbackTag`: Specify a fallback tag to be rendered if the slot fails to render.
- `placeholderTag` | `fallbackTag`: Specify a fallback tag to be rendered if the slot fails to render on the server.
- **type**: `string`
- **default**: `div`
- `placeholder` | `fallback`: Specify fallback content to be rendered if the slot fails to render.
@ -63,4 +78,3 @@ This component is experimental and in order to use it you must enable the `exper
</NuxtClientFallback>
</template>
```

View File

@ -3,7 +3,7 @@ title: '<Teleport>'
description: The <Teleport> component teleports a component to a different location in the DOM.
---
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
The `to` target of [`<Teleport>`](https://vuejs.org/guide/built-ins/teleport.html) expects a CSS selector string or an actual DOM node. Nuxt currently has SSR support for teleports to `body` only, with client-side support for other targets using a `<ClientOnly>` wrapper.
::

View File

@ -0,0 +1,56 @@
---
title: '<NuxtRouteAnnouncer>'
description: 'Add a hidden element with the page title for assistive technologies.'
navigation:
badge: New
links:
- label: Source
icon: i-simple-icons-github
to: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-route-announcer.ts
size: xs
---
::important
This component will be available in Nuxt v3.12.
::
## Usage
Add `<NuxtRouteAnnouncer/>` in your [`app.vue`](/docs/guide/directory-structure/app) or [`layouts/`](/docs/guide/directory-structure/layouts) to enhance accessibility by informing assistive technologies about page's title changes. This ensures that navigational changes are announced to users relying on screen readers.
```vue [app.vue]
<template>
<NuxtRouteAnnouncer />
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
```
## Slots
You can pass custom HTML or components through the route announcer default slot.
```vue
<template>
<NuxtRouteAnnouncer>
<template #default="{ message }">
<p>{{ message }} was loaded.</p>
</template>
</NuxtRouteAnnouncer>
</template>
```
## Props
- `atomic`: Controls if screen readers announce only changes or the entire content. Set to true for full content readout on updates, false for changes only. (default `false`)
- `politeness`: Sets the urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`)
::callout
This component is optional. :br
To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-route-announcer.ts).
::
::callout
You can hook into the underlying announcer instance using [the `useRouteAnnouncer` composable](/docs/api/composables/use-route-announcer), which allows you to set a custom announcement message.
::

View File

@ -10,12 +10,12 @@ links:
`<NuxtPage>` is a built-in component that comes with Nuxt. It lets you display top-level or nested pages located in the [`pages/`](/docs/guide/directory-structure/pages) directory.
::callout
::note
`<NuxtPage>` is a wrapper around [`<RouterView>`](https://router.vuejs.org/api/interfaces/RouterViewProps.html#interface-routerviewprops) component from Vue Router. :br
It accepts same `name` and `route` props.
::
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
`<NuxtPage>` should be used instead of `<RouterView>` as the former takes additional care on internal states. Otherwise, `useRoute()` may return incorrect paths.
::
@ -32,7 +32,7 @@ It accepts same `name` and `route` props.
- `keepalive`: control state preservation of pages rendered with the `NuxtPage` component.
- type: `boolean` or `KeepAliveProps`
::callout
::tip
Nuxt automatically resolves the `name` and `route` by scanning and rendering all Vue component files found in the `/pages` directory.
::
@ -52,7 +52,7 @@ You can also use a dynamic key based on the current route:
<NuxtPage :page-key="route => route.fullPath" />
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
Don't use `$route` object here as it can cause problems with how `<NuxtPage>` renders pages with `<Suspense>`.
::
@ -86,6 +86,18 @@ function logFoo () {
</template>
````
````vue [my-page.vue]
<script setup lang="ts">
const foo = () => {
console.log('foo method called')
}
defineExpose({
foo,
})
</script>
````
## Custom Props
In addition, `<NuxtPage>` also accepts custom props that you may need to pass further down the hierarchy.

View File

@ -39,7 +39,7 @@ const layout = 'custom'
</template>
```
::callout
::note
Please note the layout name is normalized to kebab-case, so if your layout file is named `errorLayout.vue`, it will become `error-layout` when passed as a `name` property to `<NuxtLayout />`.
::
@ -55,6 +55,10 @@ Please note the layout name is normalized to kebab-case, so if your layout file
Read more about dynamic layouts.
::
- `fallback`: If an invalid layout is passed to the `name` prop, no layout will be rendered. Specify a `fallback` layout to be rendered in this scenario. It **must** match the name of the corresponding layout file in the [`layouts/`](/docs/guide/directory-structure/layouts) directory.
- **type**: `string`
- **default**: `null`
## Additional Props
`NuxtLayout` also accepts any additional props that you may need to pass to the layout. These custom props are then made accessible as attributes.
@ -83,6 +87,8 @@ console.log(layoutCustomProps.title) // I am a custom layout
`<NuxtLayout />` renders incoming content via `<slot />`, which is then wrapped around Vues `<Transition />` component to activate layout transition. For this to work as expected, it is recommended that `<NuxtLayout />` is **not** the root element of the page component.
::code-group
```vue [pages/index.vue]
<template>
<div>
@ -93,13 +99,27 @@ console.log(layoutCustomProps.title) // I am a custom layout
</template>
```
```vue [layouts/custom.vue]
<template>
<div>
<!-- named slot -->
<slot name="header" />
<slot />
</div>
</template>
```
::
:read-more{to="/docs/getting-started/transitions"}
## Layout's Ref
To get the ref of a layout component, access it through `ref.value.layoutRef`.
````vue [app.vue]
::code-group
```vue [app.vue]
<script setup lang="ts">
const layout = ref()
@ -109,8 +129,28 @@ function logFoo () {
</script>
<template>
<NuxtLayout ref="layout" />
<NuxtLayout ref="layout">
default layout
</NuxtLayout>
</template>
````
```
```vue [layouts/default.vue]
<script setup lang="ts">
const foo = () => console.log('foo')
defineExpose({
foo
})
</script>
<template>
<div>
default layout
<slot />
</div>
</template>
```
::
:read-more{to="/docs/guide/directory-structure/layouts"}

View File

@ -8,7 +8,7 @@ links:
size: xs
---
::callout
::note
`<NuxtLink>` is a drop-in replacement for both Vue Router's `<RouterLink>` component and HTML's `<a>` tag. It intelligently determines whether the link is _internal_ or _external_ and renders it accordingly with available optimizations (prefetching, default attributes, etc.)
::
@ -25,6 +25,23 @@ In this example, we use `<NuxtLink>` component to link to another page of the ap
</template>
```
### Handling 404s
When using `<NuxtLink>` for `/public` directory files or when pointing to a different app on the same domain, you should use the `external` prop.
Using `external` forces the link to be rendered as an `a` tag instead of a Vue Router `RouterLink`.
```vue [pages/index.vue]
<template>
<NuxtLink to="/the-important-report.pdf" external>
Download Report
</NuxtLink>
<!-- <a href="/the-important-report.pdf"></a> -->
</template>
```
The external logic is applied by default when using absolute URLs and when providing a `target` prop.
## External Routing
In this example, we use `<NuxtLink>` component to link to a website.
@ -40,7 +57,13 @@ In this example, we use `<NuxtLink>` component to link to a website.
## `target` and `rel` Attributes
In this example, we use `<NuxtLink>` with `target`, `rel`, and `noRel` props.
A `rel` attribute of `noopener noreferrer` is applied by default to absolute links and links that open in new tabs.
- `noopener` solves a [security bug](https://mathiasbynens.github.io/rel-noopener/) in older browsers.
- `noreferrer` improves privacy for your users by not sending the `Referer` header to the linked site.
These defaults have no negative impact on SEO and are considered [best practice](https://developer.chrome.com/docs/lighthouse/best-practices/external-anchors-use-rel-noopener).
When you need to overwrite this behavior you can use the `rel` and `noRel` props.
```vue [app.vue]
<template>
@ -68,26 +91,65 @@ In this example, we use `<NuxtLink>` with `target`, `rel`, and `noRel` props.
## Props
### RouterLink
When not using `external`, `<NuxtLink>` supports all Vue Router's [`RouterLink` props](https://router.vuejs.org/api/interfaces/RouterLinkProps.html)
- `to`: Any URL or a [route location object](https://router.vuejs.org/api/interfaces/RouteLocation.html) from Vue Router
- `href`: An alias for `to`. If used with `to`, `href` will be ignored
- `target`: A `target` attribute value to apply on the link
- `rel`: A `rel` attribute value to apply on the link. Defaults to `"noopener noreferrer"` for external links.
- `noRel`: If set to `true`, no `rel` attribute will be added to the link
- `activeClass`: A class to apply on active links. Works the same as [Vue Router's `active-class` prop](https://router.vuejs.org/api/interfaces/RouterLinkProps.html#Properties-activeClass) on internal links. Defaults to Vue Router's default (`"router-link-active"`)
- `custom`: Whether `<NuxtLink>` should wrap its content in an `<a>` element. It allows taking full control of how a link is rendered and how navigation works when it is clicked. Works the same as [Vue Router's `custom` prop](https://router.vuejs.org/api/interfaces/RouterLinkProps.html#Properties-custom)
- `exactActiveClass`: A class to apply on exact active links. Works the same as [Vue Router's `exact-active-class` prop](https://router.vuejs.org/api/interfaces/RouterLinkProps.html#Properties-exactActiveClass) on internal links. Defaults to Vue Router's default `"router-link-exact-active"`)
- `replace`: Works the same as [Vue Router's `replace` prop](https://router.vuejs.org/api/interfaces/RouteLocationOptions.html#Properties-replace) on internal links
- `ariaCurrentValue`: An `aria-current` attribute value to apply on exact active links. Works the same as [Vue Router's `aria-current-value` prop](https://router.vuejs.org/api/interfaces/RouterLinkProps.html#Properties-ariaCurrentValue) on internal links
- `external`: Forces the link to be considered as external (`true`) or internal (`false`). This is helpful to handle edge-cases
- `prefetch` and **noPrefetch**: Whether to enable prefetching assets for links that enter the view port.
- `prefetchedClass`: A class to apply to links that have been prefetched.
- `custom`: Whether `<NuxtLink>` should wrap its content in an `<a>` element. It allows taking full control of how a link is rendered and how navigation works when it is clicked. Works the same as [Vue Router's `custom` prop](https://router.vuejs.org/api/interfaces/RouterLinkProps.html#Properties-custom)
- `activeClass`: A class to apply on active links. Works the same as [Vue Router's `active-class` prop](https://router.vuejs.org/api/interfaces/RouterLinkProps.html#Properties-activeClass) on internal links. Defaults to Vue Router's default (`"router-link-active"`)
::callout
### NuxtLink
- `href`: An alias for `to`. If used with `to`, `href` will be ignored
- `noRel`: If set to `true`, no `rel` attribute will be added to the link
- `external`: Forces the link to be rendered as an `a` tag instead of a Vue Router `RouterLink`.
- `prefetch`: When enabled will prefetch middleware, layouts and payloads (when using [payloadExtraction](/docs/api/nuxt-config#crossoriginprefetch)) of links in the viewport. Used by the experimental [crossOriginPrefetch](/docs/api/nuxt-config#crossoriginprefetch) config.
- `noPrefetch`: Disables prefetching.
- `prefetchedClass`: A class to apply to links that have been prefetched.
### Anchor
- `target`: A `target` attribute value to apply on the link
- `rel`: A `rel` attribute value to apply on the link. Defaults to `"noopener noreferrer"` for external links.
::tip
Defaults can be overwritten, see [overwriting defaults](#overwriting-defaults) if you want to change them.
::
## Overwriting Defaults
### In Nuxt Config
You can overwrite some `<NuxtLink>` defaults in your [`nuxt.config`](https://nuxt.com/docs/api/nuxt-config#defaults)
::important
These options will likely be moved elsewhere in the future, such as into `app.config` or into the `app/` directory.
::
```ts [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
defaults: {
nuxtLink: {
// default values
componentName: 'NuxtLink',
externalRelAttribute: 'noopener noreferrer',
activeClass: 'router-link-active',
exactActiveClass: 'router-link-exact-active',
prefetchedClass: undefined, // can be any valid string class name
trailingSlash: undefined // can be 'append' or 'remove'
}
}
}
})
```
### Custom Link Component
You can overwrite `<NuxtLink>` defaults by creating your own link component using `defineNuxtLink`.
```js [components/MyNuxtLink.ts]
@ -102,17 +164,18 @@ You can then use `<MyNuxtLink />` component as usual with your new defaults.
### `defineNuxtLink` Signature
```ts
defineNuxtLink({
interface NuxtLinkOptions {
componentName?: string;
externalRelAttribute?: string;
activeClass?: string;
exactActiveClass?: string;
prefetchedClass?: string;
trailingSlash?: 'append' | 'remove'
}) => Component
}
function defineNuxtLink(options: NuxtLinkOptions): Component {}
```
- `componentName`: A name for the defined `<NuxtLink>` component.
- `componentName`: A name for the component. Default is `NuxtLink`.
- `externalRelAttribute`: A default `rel` attribute value applied on external links. Defaults to `"noopener noreferrer"`. Set it to `""` to disable
- `activeClass`: A default class to apply on active links. Works the same as [Vue Router's `linkActiveClass` option](https://router.vuejs.org/api/interfaces/RouterOptions.html#Properties-linkActiveClass). Defaults to Vue Router's default (`"router-link-active"`)
- `exactActiveClass`: A default class to apply on exact active links. Works the same as [Vue Router's `linkExactActiveClass` option](https://router.vuejs.org/api/interfaces/RouterOptions.html#Properties-linkExactActiveClass). Defaults to Vue Router's default (`"router-link-exact-active"`)

View File

@ -33,12 +33,17 @@ You can pass custom HTML or components through the loading indicator's default s
- `height`: Height of the loading bar, in pixels (default `3`).
- `duration`: Duration of the loading bar, in milliseconds (default `2000`).
- `throttle`: Throttle the appearing and hiding, in milliseconds (default `200`).
- `estimatedProgress`: By default Nuxt will back off as it approaches 100%. You can provide a custom function to customize the progress estimation, which is a function that receives the duration of the loading bar (above) and the elapsed time. It should return a value between 0 and 100.
::callout
::note
This component is optional. :br
To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-loading-indicator.ts).
::
::callout
::note
You can hook into the underlying indicator instance using [the `useLoadingIndicator` composable](/docs/api/composables/use-loading-indicator), which will allow you to trigger start/finish events yourself.
::
::tip
The loading indicator's speed gradually decreases after reaching a specific point controlled by `estimatedProgress`. This adjustment provides a more accurate reflection of longer page loading times and prevents the indicator from prematurely showing 100% completion.
::

View File

@ -8,7 +8,7 @@ links:
size: xs
---
::callout
::tip
The `<NuxtErrorBoundary>` uses Vue's [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle.html#onerrorcaptured) hook under the hood.
::

View File

@ -20,6 +20,6 @@ It includes links to the Nuxt documentation, source code, and social media accou
Preview the `<NuxtWelcome />` component.
::
::callout
::tip
This component is part of [nuxt/assets](https://github.com/nuxt/assets).
::

View File

@ -12,15 +12,11 @@ When rendering an island component, the content of the island component is stati
Changing the island component props triggers a refetch of the island component to re-render it again.
::read-more{to="/docs/guide/going-further/experimental-features#componentislands" icon="i-ph-star-duotone"}
This component is experimental and in order to use it you must enable the `experimental.componentIslands` option in your `nuxt.config`.
::
::callout
::note
Global styles of your application are sent with the response.
::
::callout
::tip
Server only components use `<NuxtIsland>` under the hood
::
@ -40,7 +36,7 @@ Server only components use `<NuxtIsland>` under the hood
- **type**: `boolean`
- **default**: `false`
::callout{color="blue" icon="i-ph-info-duotone"}
::note
Remote islands need `experimental.componentIslands` to be `'local+remote'` in your `nuxt.config`.
It is strongly discouraged to enable `dangerouslyLoadClientComponents` as you can't trust a remote server's javascript.
::
@ -60,3 +56,11 @@ Some slots are reserved to `NuxtIsland` for special cases.
- `refresh()`
- **type**: `() => Promise<void>`
- **description**: force refetch the server component by refetching it.
## Events
- `error`
- **parameters**:
- **error**:
- **type**: `unknown`
- **description**: emitted when when `NuxtIsland` fails to fetch the new island.

View File

@ -10,14 +10,14 @@ links:
Within your pages, components, and plugins you can use useAsyncData to get access to data that resolves asynchronously.
::callout
[`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.
::note
[`useAsyncData`](/docs/api/composables/use-async-data) is a composable meant to be called directly in the [Nuxt context](/docs/guide/going-further/nuxt-app#the-nuxt-context). 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.
::
## Usage
```vue [pages/index.vue]
<script setup>
<script setup lang="ts">
const { data, pending, error, refresh } = await useAsyncData(
'mountains',
() => $fetch('https://api.nuxtjs.dev/mountains')
@ -25,7 +25,7 @@ const { data, pending, error, refresh } = await useAsyncData(
</script>
```
::callout
::note
`data`, `pending`, `status` and `error` are Vue refs and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` is a plain function for refetching data.
::
@ -34,7 +34,7 @@ const { data, pending, error, refresh } = await useAsyncData(
The built-in `watch` option allows automatically rerunning the fetcher function when any changes are detected.
```vue [pages/index.vue]
<script setup>
<script setup lang="ts">
const page = ref(1)
const { data: posts } = await useAsyncData(
'posts',
@ -49,7 +49,7 @@ const { data: posts } = await useAsyncData(
</script>
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
[`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) .
::
@ -73,7 +73,7 @@ const { data: posts } = await useAsyncData(
- `cancel` - cancels existing requests when a new one is made
- `defer` - does not make new requests at all if there is a pending request
::callout
::note
Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the route before the data has been fetched. Consider using `lazy: true` and implementing a loading state instead for a snappier user experience.
::
@ -81,7 +81,7 @@ Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the rout
You can use `useLazyAsyncData` to have the same behavior as `lazy: true` with `useAsyncData`.
::
::callout{icon="i-simple-icons-youtube" color="gray" to="https://www.youtube.com/watch?v=aQPR0xn-MMk" target="_blank"}
::tip{icon="i-simple-icons-youtube" color="gray" to="https://www.youtube.com/watch?v=aQPR0xn-MMk" target="_blank"}
Learn how to use `transform` and `getCachedData` to avoid superfluous calls to an API and cache data for visitors on the client.
::
@ -95,7 +95,7 @@ Learn how to use `transform` and `getCachedData` to avoid superfluous calls to a
By default, Nuxt waits until a `refresh` is finished before it can be executed again.
::callout
::note
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>`.
::
@ -119,10 +119,10 @@ type AsyncDataOptions<DataT> = {
deep?: boolean
dedupe?: 'cancel' | 'defer'
default?: () => DataT | Ref<DataT> | null
transform?: (input: DataT) => DataT
transform?: (input: DataT) => DataT | Promise<DataT>
pick?: string[]
watch?: WatchSource[]
getCachedData?: (key: string) => DataT
getCachedData?: (key: string, nuxtApp: NuxtApp) => DataT
}
type AsyncData<DataT, ErrorT> = {
@ -130,6 +130,7 @@ type AsyncData<DataT, ErrorT> = {
pending: Ref<boolean>
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
clear: () => void
error: Ref<ErrorT | null>
status: Ref<AsyncDataRequestStatus>
};

View File

@ -14,7 +14,11 @@ Within your pages, components and plugins you can use `useCookie`, an SSR-friend
const cookie = useCookie(name, options)
```
::callout
::note
`useCookie` only works in the [Nuxt context](/docs/guide/going-further/nuxt-app#the-nuxt-context).
::
::tip
`useCookie` ref will automatically serialize and deserialize cookie value to JSON.
::
@ -58,13 +62,13 @@ The given number will be converted to an integer by rounding down. By default, n
By default, no expiration is set. Most clients will consider this a "non-persistent cookie" and
will delete it on a condition like exiting a web browser application.
::callout
::note
The [cookie storage model specification](https://tools.ietf.org/html/rfc6265#section-5.3) states that if both `expires` and
`maxAge` is set, then `maxAge` takes precedence, but not all clients may obey this,
so if both are set, they should point to the same date and time!
::
::callout
::note
If neither of `expires` and `maxAge` is set, the cookie will be session-only and removed when the user closes their browser.
::
@ -73,7 +77,7 @@ If neither of `expires` and `maxAge` is set, the cookie will be session-only and
Specifies the `boolean` value for the [`HttpOnly` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.6). When truthy,
the `HttpOnly` attribute is set; otherwise it is not. By default, the `HttpOnly` attribute is not set.
::callout
::warning
Be careful when setting this to `true`, as compliant clients will not allow client-side
JavaScript to see the cookie in `document.cookie`.
::
@ -83,7 +87,7 @@ JavaScript to see the cookie in `document.cookie`.
Specifies the `boolean` value for the [`Secure` `Set-Cookie` attribute](https://tools.ietf.org/html/rfc6265#section-5.2.5). When truthy,
the `Secure` attribute is set; otherwise it is not. By default, the `Secure` attribute is not set.
::callout
::warning
Be careful when setting this to `true`, as compliant clients will not send the cookie back to
the server in the future if the browser does not have an HTTPS connection. This can lead to hydration errors.
::
@ -124,7 +128,7 @@ a previously encoded cookie value into a JavaScript string or other object.
The default decoder is `decodeURIComponent` + [destr](https://github.com/unjs/destr).
::callout
::note
If an error is thrown from this function, the original, non-decoded cookie value will
be returned as the cookie's value.
::

View File

@ -11,21 +11,21 @@ links:
This composable provides a convenient wrapper around [`useAsyncData`](/docs/api/composables/use-async-data) and [`$fetch`](/docs/api/utils/dollarfetch).
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.
::callout
::note
`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.
::
## Usage
```vue [pages/modules.vue]
<script setup>
<script setup lang="ts">
const { data, pending, error, refresh } = await useFetch('/api/modules', {
pick: ['title']
})
</script>
```
::callout
::note
`data`, `pending`, `status` and `error` are Vue refs and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` is a plain function for refetching data.
::
@ -62,7 +62,7 @@ const { data, pending, error, refresh } = await useFetch('/api/auth/login', {
})
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
`useFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useFetch`.
::
@ -84,7 +84,7 @@ const { data, pending, error, refresh } = await useFetch('/api/auth/login', {
- `baseURL`: Base URL for the request.
- `timeout`: Milliseconds to automatically abort request
::callout
::note
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.
::
@ -103,11 +103,11 @@ All fetch options can be given a `computed` or `ref` value. These will be watche
- `cancel` - cancels existing requests when a new one is made
- `defer` - does not make new requests at all if there is a pending request
::callout
::note
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`.
::
::callout{icon="i-simple-icons-youtube" color="gray" to="https://www.youtube.com/watch?v=aQPR0xn-MMk" target="_blank"}
::tip{icon="i-simple-icons-youtube" color="gray" to="https://www.youtube.com/watch?v=aQPR0xn-MMk" target="_blank"}
Learn how to use `transform` and `getCachedData` to avoid superfluous calls to an API and cache data for visitors on the client.
::
@ -121,7 +121,7 @@ Learn how to use `transform` and `getCachedData` to avoid superfluous calls to a
By default, Nuxt waits until a `refresh` is finished before it can be executed again.
::callout
::note
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>`.
::
@ -144,11 +144,11 @@ type UseFetchOptions<DataT> = {
server?: boolean
lazy?: boolean
immediate?: boolean
getCachedData?: (key: string) => DataT
getCachedData?: (key: string, nuxtApp: NuxtApp) => DataT
deep?: boolean
dedupe?: 'cancel' | 'defer'
default?: () => DataT
transform?: (input: DataT) => DataT
transform?: (input: DataT) => DataT | Promise<DataT>
pick?: string[]
watch?: WatchSource[] | false
}
@ -158,6 +158,7 @@ type AsyncData<DataT, ErrorT> = {
pending: Ref<boolean>
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
clear: () => void
error: Ref<ErrorT | null>
status: Ref<AsyncDataRequestStatus>
}

View File

@ -37,7 +37,7 @@ interface MetaObject {
See [@unhead/schema](https://github.com/unjs/unhead/blob/main/packages/schema/src/schema.ts) for more detailed types.
::callout
::note
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.
::

View File

@ -10,7 +10,7 @@ links:
`useHydration` is a built-in composable that provides a way to set data on the server side every time a new HTTP request is made and receive that data on the client side. This way `useHydration` allows you to take full control of the hydration cycle.
::callout
::note
This is an advanced composable and is mostly used internally (`useAsyncData`) or by Nuxt modules.
::

View File

@ -0,0 +1,37 @@
---
title: "useId"
description: Generate an SSR-friendly unique identifier that can be passed to accessibility attributes.
---
::important
This composable is available since [Nuxt v3.10](/blog/v3-10#ssr-safe-accessible-unique-id-creation).
::
`useId` generates an SSR-friendly unique identifier that can be passed to accessibility attributes.
Call `useId` at the top level of your component to generate a unique string identifier:
```vue [components/EmailField.vue]
<script setup lang="ts">
const id = useId()
</script>
<template>
<div>
<label :for="id">Email</label>
<input :id="id" name="email" type="email" />
</div>
</template>
```
::note
`useId` must be used in a component with a single root element, as it uses this root element's attributes to pass the id from server to client.
::
## Parameters
`useId` does not take any parameters.
## Returns
`useId` returns a unique string associated with this particular `useId` call in this particular component.

View File

@ -12,7 +12,7 @@ links:
By default, [`useAsyncData`](/docs/api/composables/use-async-data) blocks navigation until its async handler is resolved. `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`.
::callout
::note
`useLazyAsyncData` has the same signature as [`useAsyncData`](/docs/api/composables/use-async-data).
::
@ -40,7 +40,7 @@ watch(count, (newCount) => {
</template>
```
::callout{color="amber" icon="i-ph-warning-duotone"}
::warning
`useLazyAsyncData` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyAsyncData`.
::

View File

@ -12,7 +12,7 @@ links:
By default, [`useFetch`](/docs/api/composables/use-fetch) blocks navigation until its async handler is resolved. `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`.
::callout
::note
`useLazyFetch` has the same signature as [`useFetch`](/docs/api/composables/use-fetch).
::
@ -44,7 +44,7 @@ watch(posts, (newPosts) => {
</template>
```
::callout
::note
`useLazyFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyFetch`.
::

View File

@ -13,6 +13,12 @@ links:
A composable which returns the loading state of the page. Used by [`<NuxtLoadingIndicator>`](/docs/api/components/nuxt-loading-indicator) and controllable.
It hooks into [`page:loading:start`](/docs/api/advanced/hooks#app-hooks-runtime) and [`page:loading:end`](/docs/api/advanced/hooks#app-hooks-runtime) to change its state.
## Parameters
- `duration`: Duration of the loading bar, in milliseconds (default `2000`).
- `throttle`: Throttle the appearing and hiding, in milliseconds (default `200`).
- `estimatedProgress`: By default Nuxt will back off as it approaches 100%. You can provide a custom function to customize the progress estimation, which is a function that receives the duration of the loading bar (above) and the elapsed time. It should return a value between 0 and 100.
## Properties
### `isLoading`
@ -33,8 +39,21 @@ Set `isLoading` to true and start to increase the `progress` value.
### `finish()`
Set the `progress` value to `100`, stop all timers and intervals then reset the loading state `500` ms later.
Set the `progress` value to `100`, stop all timers and intervals then reset the loading state `500` ms later. `finish` accepts a `{ force: true }` option to skip the interval before the state is reset.
### `clear()`
Used by `finish()`. Clear all timers and intervals used by the composable.
## Example
```vue
<script setup lang="ts">
const { progress, isLoading, start, finish, clear } = useLoadingIndicator({
duration: 2000,
throttle: 200,
// This is how progress is calculated by default
estimatedProgress: (duration, elapsed) => (2 / Math.PI * 100) * Math.atan(elapsed / duration * 100 / 50)
})
</script>
```

View File

@ -8,7 +8,7 @@ links:
size: xs
---
`useNuxtApp` is a built-in composable that provides a way to access shared runtime context of Nuxt, which is available on both client and server side. It helps you access the Vue app instance, runtime hooks, runtime config variables and internal states, such as `ssrContext` and `payload`.
`useNuxtApp` is a built-in composable that provides a way to access shared runtime context of Nuxt, also known as the [Nuxt context](/docs/guide/going-further/nuxt-app#the-nuxt-context), which is available on both client and server side. It helps you access the Vue app instance, runtime hooks, runtime config variables and internal states, such as `ssrContext` and `payload`.
```vue [app.vue]
<script setup lang="ts">
@ -51,7 +51,7 @@ export default defineNuxtPlugin((nuxtApp) => {
})
nuxtApp.hook('vue:error', (..._args) => {
console.log('vue:error')
// if (process.client) {
// if (import.meta.client) {
// console.log(..._args)
// }
})
@ -120,7 +120,7 @@ Nuxt exposes the following properties through `ssrContext`:
export const useColor = () => useState<string>('color', () => 'pink')
export default defineNuxtPlugin((nuxtApp) => {
if (process.server) {
if (import.meta.server) {
const color = useColor()
}
})
@ -128,9 +128,9 @@ Nuxt exposes the following properties through `ssrContext`:
It is also possible to use more advanced types, such as `ref`, `reactive`, `shallowRef`, `shallowReactive` and `NuxtError`.
Since [Nuxt v3.4](https://nuxt.com/blog/v3-4#payload-enhancements), it is possible to define your own serializer/deserializer for types that are not supported by Nuxt.
Since [Nuxt v3.4](https://nuxt.com/blog/v3-4#payload-enhancements), it is possible to define your own reducer/reviver for types that are not supported by Nuxt.
In the example below, we define a serializer for the [Luxon](https://moment.github.io/luxon/#/) DateTime class.
In the example below, we define a reducer (or a serializer) and a reviver (or deserializer) for the [Luxon](https://moment.github.io/luxon/#/) DateTime class, using a payload plugin.
```ts [plugins/date-time-payload.ts]
/**
@ -159,7 +159,7 @@ export default defineComponent({
setup (_props, { slots, emit }) {
const nuxtApp = useNuxtApp()
onErrorCaptured((err) => {
if (process.client && !nuxtApp.isHydrating) {
if (import.meta.client && !nuxtApp.isHydrating) {
// ...
}
})
@ -169,7 +169,7 @@ export default defineComponent({
### `runWithContext`
::callout
::note
You are likely here because you got a "Nuxt instance unavailable" message. Please use this method sparingly, and report examples that are causing issues, so that it can ultimately be solved at the framework level.
::
@ -186,7 +186,7 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
user = null
}
if (!user) {
// apply the correct Nuxt context to our `navigateTo` call.
// apply the correct Nuxt context to our `navigateTo` call.
return nuxtApp.runWithContext(() => navigateTo('/auth'))
}
})
@ -254,7 +254,7 @@ The `unjs/unctx` transformation to automatically restore context seems buggy wit
Using a new experimental feature, it is possible to enable native async context support using [Node.js `AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage) and new unctx support to make async context available **natively** to **any nested async composable** without needing a transform or manual passing/calling with context.
::callout
::tip
Native async context support works currently in Bun and Node.
::

View File

@ -8,7 +8,7 @@ links:
size: xs
---
::callout
::note
`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.
::
@ -17,13 +17,14 @@ links:
The example below shows how you can use cached data as a placeholder while the most recent data is being fetched from the server.
```vue [pages/posts.vue]
<script setup>
<script setup lang="ts">
// We can access same data later using 'posts' key
const { data } = await useFetch('/api/posts', { key: 'posts' })
</script>
```
```ts [pages/posts/[id\\].vue]
```vue [pages/posts/[id\\].vue]
<script setup lang="ts">
// Access to the cached value of useFetch in posts.vue (parent route)
const { id } = useRoute().params
const { data: posts } = useNuxtData('posts')
@ -34,6 +35,7 @@ const { data } = useLazyFetch(`/api/posts/${id}`, {
return posts.value.find(post => post.id === id)
}
})
</script>
```
## Optimistic Updates
@ -41,14 +43,14 @@ const { data } = useLazyFetch(`/api/posts/${id}`, {
We can leverage the cache to update the UI after a mutation, while the data is being invalidated in the background.
```vue [pages/todos.vue]
<script setup>
<script setup lang="ts">
// We can access same data later using 'todos' key
const { data } = await useAsyncData('todos', () => $fetch('/api/todos'))
</script>
```
```vue [components/NewTodo.vue]
<script setup>
<script setup lang="ts">
const newTodo = ref('')
const previousTodos = ref([])

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