mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-22 08:29:46 +00:00
Merge branch 'main' into payload-extraction
This commit is contained in:
commit
66c3549e1e
4
.github/workflows/autofix-docs.yml
vendored
4
.github/workflows/autofix-docs.yml
vendored
@ -18,8 +18,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
4
.github/workflows/autofix.yml
vendored
4
.github/workflows/autofix.yml
vendored
@ -14,8 +14,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
4
.github/workflows/changelog.yml
vendored
4
.github/workflows/changelog.yml
vendored
@ -25,8 +25,8 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
40
.github/workflows/ci.yml
vendored
40
.github/workflows/ci.yml
vendored
@ -38,8 +38,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
@ -78,7 +78,7 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
|
uses: github/codeql-action/init@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
|
||||||
with:
|
with:
|
||||||
config: |
|
config: |
|
||||||
paths:
|
paths:
|
||||||
@ -95,7 +95,7 @@ jobs:
|
|||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
|
uses: github/codeql-action/analyze@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
|
||||||
with:
|
with:
|
||||||
category: "/language:${{ matrix.language }}"
|
category: "/language:${{ matrix.language }}"
|
||||||
|
|
||||||
@ -112,8 +112,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
@ -143,8 +143,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
@ -170,8 +170,8 @@ jobs:
|
|||||||
- build
|
- build
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
@ -195,8 +195,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
@ -220,8 +220,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
@ -280,8 +280,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
@ -332,8 +332,8 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
@ -364,8 +364,8 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
2
.github/workflows/docs-check-links.yml
vendored
2
.github/workflows/docs-check-links.yml
vendored
@ -29,7 +29,7 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Lychee link checker
|
- name: Lychee link checker
|
||||||
uses: lycheeverse/lychee-action@f796c8b7d468feb9b8c0a46da3fac0af6874d374 # for v1.8.0
|
uses: lycheeverse/lychee-action@f613c4a64e50d792e0b31ec34bbcbba12263c6a6 # for v1.8.0
|
||||||
with:
|
with:
|
||||||
# arguments with file types to check
|
# arguments with file types to check
|
||||||
args: >-
|
args: >-
|
||||||
|
4
.github/workflows/docs.yml
vendored
4
.github/workflows/docs.yml
vendored
@ -22,8 +22,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
4
.github/workflows/lint-monorepo.yml
vendored
4
.github/workflows/lint-monorepo.yml
vendored
@ -26,8 +26,8 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -22,8 +22,8 @@ jobs:
|
|||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: corepack enable
|
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||||
with:
|
with:
|
||||||
node-version: lts/*
|
node-version: lts/*
|
||||||
registry-url: "https://registry.npmjs.org/"
|
registry-url: "https://registry.npmjs.org/"
|
||||||
|
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
|||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
|
uses: github/codeql-action/upload-sarif@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
|
||||||
if: github.repository == 'nuxt/nuxt' && success()
|
if: github.repository == 'nuxt/nuxt' && success()
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
@ -176,7 +176,7 @@ Now, before navigation to that page can complete, the `auth` route middleware wi
|
|||||||
|
|
||||||
:link-example{to="/docs/examples/routing/middleware"}
|
:link-example{to="/docs/examples/routing/middleware"}
|
||||||
|
|
||||||
## Setting Middleware At Build Time
|
## Setting Middleware at Build Time
|
||||||
|
|
||||||
Instead of using `definePageMeta` on each page, you can add named route middleware within the `pages:extend` hook.
|
Instead of using `definePageMeta` on each page, you can add named route middleware within the `pages:extend` hook.
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ This configuration will observe when the element enters the viewport and also li
|
|||||||
|
|
||||||
### Enable Cross-origin Prefetch
|
### Enable Cross-origin Prefetch
|
||||||
|
|
||||||
To enable cross-origin prefetching, you can set the `crossOriginPrefetch` option in your `nuxt.config`. This will enabled cross-origin prefetch using the [Speculation Rules API](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API).
|
To enable cross-origin prefetching, you can set the `crossOriginPrefetch` option in your `nuxt.config`. This will enable cross-origin prefetching using the [Speculation Rules API](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API).
|
||||||
|
|
||||||
```ts [nuxt.config.ts]
|
```ts [nuxt.config.ts]
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
|
@ -34,4 +34,7 @@ exclude = [
|
|||||||
# single-quotes are required for regexp
|
# single-quotes are required for regexp
|
||||||
'(https?:\/\/github\.com\/)(.*\/)(generate)',
|
'(https?:\/\/github\.com\/)(.*\/)(generate)',
|
||||||
"https://github.com/nuxt-contrib/vue3-ssr-starter/generate",
|
"https://github.com/nuxt-contrib/vue3-ssr-starter/generate",
|
||||||
|
# excluded URLs from test suite
|
||||||
|
"http://auth.com",
|
||||||
|
"http://example2.com/",
|
||||||
]
|
]
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// For pnpm typecheck:docs to generate correct types
|
// For pnpm typecheck:docs to generate correct types
|
||||||
|
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
import { addPluginTemplate, addRouteMiddleware } from 'nuxt/kit'
|
import { addPluginTemplate, addRouteMiddleware } from 'nuxt/kit'
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
@ -17,6 +18,9 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
pages: process.env.DOCS_TYPECHECK === 'true',
|
pages: process.env.DOCS_TYPECHECK === 'true',
|
||||||
|
dir: {
|
||||||
|
app: fileURLToPath(new URL('./test/runtime/app', import.meta.url)),
|
||||||
|
},
|
||||||
typescript: {
|
typescript: {
|
||||||
shim: process.env.DOCS_TYPECHECK === 'true',
|
shim: process.env.DOCS_TYPECHECK === 'true',
|
||||||
hoist: ['@vitejs/plugin-vue', 'vue-router'],
|
hoist: ['@vitejs/plugin-vue', 'vue-router'],
|
||||||
|
40
package.json
40
package.json
@ -39,13 +39,13 @@
|
|||||||
"resolutions": {
|
"resolutions": {
|
||||||
"@babel/core": "7.26.7",
|
"@babel/core": "7.26.7",
|
||||||
"@babel/helper-plugin-utils": "7.26.5",
|
"@babel/helper-plugin-utils": "7.26.5",
|
||||||
"@nuxt/cli": "3.20.0",
|
"@nuxt/cli": "3.21.1",
|
||||||
"@nuxt/kit": "workspace:*",
|
"@nuxt/kit": "workspace:*",
|
||||||
"@nuxt/rspack-builder": "workspace:*",
|
"@nuxt/rspack-builder": "workspace:*",
|
||||||
"@nuxt/schema": "workspace:*",
|
"@nuxt/schema": "workspace:*",
|
||||||
"@nuxt/vite-builder": "workspace:*",
|
"@nuxt/vite-builder": "workspace:*",
|
||||||
"@nuxt/webpack-builder": "workspace:*",
|
"@nuxt/webpack-builder": "workspace:*",
|
||||||
"@types/node": "22.10.10",
|
"@types/node": "22.13.1",
|
||||||
"@unhead/dom": "1.11.18",
|
"@unhead/dom": "1.11.18",
|
||||||
"@unhead/schema": "1.11.18",
|
"@unhead/schema": "1.11.18",
|
||||||
"@unhead/shared": "1.11.18",
|
"@unhead/shared": "1.11.18",
|
||||||
@ -58,18 +58,18 @@
|
|||||||
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
||||||
"jiti": "2.4.2",
|
"jiti": "2.4.2",
|
||||||
"magic-string": "^0.30.17",
|
"magic-string": "^0.30.17",
|
||||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28938837.19ec5395",
|
"nitro": "npm:nitro-nightly@3.0.0-beta-28969273.f7aa9de6",
|
||||||
"nuxt": "workspace:*",
|
"nuxt": "workspace:*",
|
||||||
"ohash": "1.1.4",
|
"ohash": "1.1.4",
|
||||||
"postcss": "8.5.1",
|
"postcss": "8.5.1",
|
||||||
"rollup": "4.32.0",
|
"rollup": "4.34.4",
|
||||||
"send": ">=1.1.0",
|
"send": ">=1.1.0",
|
||||||
"typescript": "5.7.3",
|
"typescript": "5.7.3",
|
||||||
"ufo": "1.5.4",
|
"ufo": "1.5.4",
|
||||||
"unbuild": "3.3.1",
|
"unbuild": "3.3.1",
|
||||||
"unhead": "1.11.18",
|
"unhead": "1.11.18",
|
||||||
"unimport": "4.0.0",
|
"unimport": "4.0.0",
|
||||||
"vite": "6.0.11",
|
"vite": "6.1.0",
|
||||||
"vue": "3.5.13"
|
"vue": "3.5.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -77,8 +77,8 @@
|
|||||||
"@babel/core": "7.26.7",
|
"@babel/core": "7.26.7",
|
||||||
"@babel/helper-plugin-utils": "7.26.5",
|
"@babel/helper-plugin-utils": "7.26.5",
|
||||||
"@codspeed/vitest-plugin": "4.0.0",
|
"@codspeed/vitest-plugin": "4.0.0",
|
||||||
"@nuxt/cli": "3.20.0",
|
"@nuxt/cli": "3.21.1",
|
||||||
"@nuxt/eslint-config": "0.7.5",
|
"@nuxt/eslint-config": "1.0.0",
|
||||||
"@nuxt/kit": "workspace:*",
|
"@nuxt/kit": "workspace:*",
|
||||||
"@nuxt/rspack-builder": "workspace:*",
|
"@nuxt/rspack-builder": "workspace:*",
|
||||||
"@nuxt/test-utils": "3.15.4",
|
"@nuxt/test-utils": "3.15.4",
|
||||||
@ -86,11 +86,11 @@
|
|||||||
"@testing-library/vue": "8.1.0",
|
"@testing-library/vue": "8.1.0",
|
||||||
"@types/babel__core": "7.20.5",
|
"@types/babel__core": "7.20.5",
|
||||||
"@types/babel__helper-plugin-utils": "7.10.3",
|
"@types/babel__helper-plugin-utils": "7.10.3",
|
||||||
"@types/node": "22.10.10",
|
"@types/node": "22.13.1",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.5.8",
|
||||||
"@unhead/schema": "1.11.18",
|
"@unhead/schema": "1.11.18",
|
||||||
"@unhead/vue": "1.11.18",
|
"@unhead/vue": "1.11.18",
|
||||||
"@vitest/coverage-v8": "3.0.4",
|
"@vitest/coverage-v8": "3.0.5",
|
||||||
"@vue/test-utils": "2.4.6",
|
"@vue/test-utils": "2.4.6",
|
||||||
"acorn": "8.14.0",
|
"acorn": "8.14.0",
|
||||||
"autoprefixer": "10.4.20",
|
"autoprefixer": "10.4.20",
|
||||||
@ -102,40 +102,40 @@
|
|||||||
"devalue": "5.1.1",
|
"devalue": "5.1.1",
|
||||||
"eslint": "9.19.0",
|
"eslint": "9.19.0",
|
||||||
"eslint-plugin-no-only-tests": "3.3.0",
|
"eslint-plugin-no-only-tests": "3.3.0",
|
||||||
"eslint-plugin-perfectionist": "4.7.0",
|
"eslint-plugin-perfectionist": "4.8.0",
|
||||||
"eslint-typegen": "1.0.0",
|
"eslint-typegen": "1.0.0",
|
||||||
"estree-walker": "3.0.3",
|
"estree-walker": "3.0.3",
|
||||||
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
||||||
"happy-dom": "16.7.2",
|
"happy-dom": "17.0.0",
|
||||||
"installed-check": "9.3.0",
|
"installed-check": "9.3.0",
|
||||||
"jiti": "2.4.2",
|
"jiti": "2.4.2",
|
||||||
"knip": "5.43.3",
|
"knip": "5.43.6",
|
||||||
"magic-string": "0.30.17",
|
"magic-string": "0.30.17",
|
||||||
"markdownlint-cli": "0.44.0",
|
"markdownlint-cli": "0.44.0",
|
||||||
"memfs": "4.17.0",
|
"memfs": "4.17.0",
|
||||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28938837.19ec5395",
|
"nitro": "npm:nitro-nightly@3.0.0-beta-28969273.f7aa9de6",
|
||||||
"nuxt": "workspace:*",
|
"nuxt": "workspace:*",
|
||||||
"nuxt-content-twoslash": "0.1.2",
|
"nuxt-content-twoslash": "0.1.2",
|
||||||
"ofetch": "1.4.1",
|
"ofetch": "1.4.1",
|
||||||
"pathe": "2.0.2",
|
"pathe": "2.0.2",
|
||||||
"pkg-pr-new": "0.0.39",
|
"pkg-pr-new": "0.0.39",
|
||||||
"playwright-core": "1.50.0",
|
"playwright-core": "1.50.1",
|
||||||
"rollup": "4.32.0",
|
"rollup": "4.34.4",
|
||||||
"semver": "7.6.3",
|
"semver": "7.7.1",
|
||||||
"sherif": "1.2.0",
|
"sherif": "1.3.0",
|
||||||
"std-env": "3.8.0",
|
"std-env": "3.8.0",
|
||||||
"tinyexec": "0.3.2",
|
"tinyexec": "0.3.2",
|
||||||
"tinyglobby": "0.2.10",
|
"tinyglobby": "0.2.10",
|
||||||
"ts-blank-space": "0.5.0",
|
"ts-blank-space": "0.5.1",
|
||||||
"typescript": "5.7.3",
|
"typescript": "5.7.3",
|
||||||
"ufo": "1.5.4",
|
"ufo": "1.5.4",
|
||||||
"unbuild": "3.3.1",
|
"unbuild": "3.3.1",
|
||||||
"vitest": "3.0.4",
|
"vitest": "3.0.5",
|
||||||
"vitest-environment-nuxt": "1.0.1",
|
"vitest-environment-nuxt": "1.0.1",
|
||||||
"vue": "3.5.13",
|
"vue": "3.5.13",
|
||||||
"vue-tsc": "2.2.0",
|
"vue-tsc": "2.2.0",
|
||||||
"webpack": "5.97.1"
|
"webpack": "5.97.1"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@9.15.4",
|
"packageManager": "pnpm@10.2.0",
|
||||||
"version": ""
|
"version": ""
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
"test:attw": "attw --pack"
|
"test:attw": "attw --pack"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/schema": "workspace:*",
|
|
||||||
"c12": "^2.0.1",
|
"c12": "^2.0.1",
|
||||||
"consola": "^3.4.0",
|
"consola": "^3.4.0",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
@ -42,7 +41,7 @@
|
|||||||
"pathe": "^2.0.2",
|
"pathe": "^2.0.2",
|
||||||
"pkg-types": "^1.3.1",
|
"pkg-types": "^1.3.1",
|
||||||
"scule": "^1.3.0",
|
"scule": "^1.3.0",
|
||||||
"semver": "^7.6.3",
|
"semver": "^7.7.1",
|
||||||
"std-env": "^3.8.0",
|
"std-env": "^3.8.0",
|
||||||
"ufo": "^1.5.4",
|
"ufo": "^1.5.4",
|
||||||
"unctx": "^2.4.1",
|
"unctx": "^2.4.1",
|
||||||
@ -50,12 +49,13 @@
|
|||||||
"untyped": "^1.5.2"
|
"untyped": "^1.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@nuxt/schema": "workspace:*",
|
||||||
"@rspack/core": "1.2.2",
|
"@rspack/core": "1.2.2",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.5.8",
|
||||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28938837.19ec5395",
|
"nitro": "npm:nitro-nightly@3.0.0-beta-28969273.f7aa9de6",
|
||||||
"unbuild": "3.3.1",
|
"unbuild": "3.3.1",
|
||||||
"vite": "6.0.11",
|
"vite": "6.1.0",
|
||||||
"vitest": "3.0.4",
|
"vitest": "3.0.5",
|
||||||
"webpack": "5.97.1"
|
"webpack": "5.97.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -1,27 +1,21 @@
|
|||||||
import { existsSync } from 'node:fs'
|
import { existsSync } from 'node:fs'
|
||||||
|
import { pathToFileURL } from 'node:url'
|
||||||
import type { JSValue } from 'untyped'
|
import type { JSValue } from 'untyped'
|
||||||
import { applyDefaults } from 'untyped'
|
import { applyDefaults } from 'untyped'
|
||||||
import type { ConfigLayer, ConfigLayerMeta, LoadConfigOptions } from 'c12'
|
import type { ConfigLayer, ConfigLayerMeta, LoadConfigOptions } from 'c12'
|
||||||
import { loadConfig } from 'c12'
|
import { loadConfig } from 'c12'
|
||||||
import type { NuxtConfig, NuxtOptions } from '@nuxt/schema'
|
import type { NuxtConfig, NuxtOptions } from '@nuxt/schema'
|
||||||
import { NuxtConfigSchema } from '@nuxt/schema'
|
|
||||||
import { globby } from 'globby'
|
import { globby } from 'globby'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
import { join } from 'pathe'
|
import { join } from 'pathe'
|
||||||
|
import { isWindows } from 'std-env'
|
||||||
|
import { tryResolveModule } from '../internal/esm'
|
||||||
|
|
||||||
export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig>, 'overrides'> {
|
export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig>, 'overrides'> {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||||
overrides?: Exclude<LoadConfigOptions<NuxtConfig>['overrides'], Promise<any> | Function>
|
overrides?: Exclude<LoadConfigOptions<NuxtConfig>['overrides'], Promise<any> | Function>
|
||||||
}
|
}
|
||||||
|
|
||||||
const layerSchemaKeys = ['future', 'srcDir', 'rootDir', 'serverDir', 'dir']
|
|
||||||
const layerSchema = Object.create(null)
|
|
||||||
for (const key of layerSchemaKeys) {
|
|
||||||
if (key in NuxtConfigSchema) {
|
|
||||||
layerSchema[key] = NuxtConfigSchema[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<NuxtOptions> {
|
export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<NuxtOptions> {
|
||||||
// Automatically detect and import layers from `~~/layers/` directory
|
// Automatically detect and import layers from `~~/layers/` directory
|
||||||
opts.overrides = defu(opts.overrides, {
|
opts.overrides = defu(opts.overrides, {
|
||||||
@ -54,6 +48,16 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
|
|||||||
nuxtConfig.buildDir = join(nuxtConfig.rootDir!, 'node_modules/.cache/nuxt/.nuxt')
|
nuxtConfig.buildDir = join(nuxtConfig.rootDir!, 'node_modules/.cache/nuxt/.nuxt')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NuxtConfigSchema = await loadNuxtSchema(nuxtConfig.rootDir || cwd || process.cwd())
|
||||||
|
|
||||||
|
const layerSchemaKeys = ['future', 'srcDir', 'rootDir', 'serverDir', 'dir']
|
||||||
|
const layerSchema = Object.create(null)
|
||||||
|
for (const key of layerSchemaKeys) {
|
||||||
|
if (key in NuxtConfigSchema) {
|
||||||
|
layerSchema[key] = NuxtConfigSchema[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const _layers: ConfigLayer<NuxtConfig, ConfigLayerMeta>[] = []
|
const _layers: ConfigLayer<NuxtConfig, ConfigLayerMeta>[] = []
|
||||||
const processedLayers = new Set<string>()
|
const processedLayers = new Set<string>()
|
||||||
for (const layer of layers) {
|
for (const layer of layers) {
|
||||||
@ -89,3 +93,13 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
|
|||||||
// Resolve and apply defaults
|
// Resolve and apply defaults
|
||||||
return await applyDefaults(NuxtConfigSchema, nuxtConfig as NuxtConfig & Record<string, JSValue>) as unknown as NuxtOptions
|
return await applyDefaults(NuxtConfigSchema, nuxtConfig as NuxtConfig & Record<string, JSValue>) as unknown as NuxtOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadNuxtSchema (cwd: string) {
|
||||||
|
const paths = [cwd]
|
||||||
|
const nuxtPath = await tryResolveModule('nuxt', cwd) ?? await tryResolveModule('nuxt-nightly', cwd)
|
||||||
|
if (nuxtPath) {
|
||||||
|
paths.unshift(nuxtPath)
|
||||||
|
}
|
||||||
|
const schemaPath = await tryResolveModule('@nuxt/schema', paths) ?? '@nuxt/schema'
|
||||||
|
return await import(isWindows ? pathToFileURL(schemaPath).href : schemaPath).then(r => r.NuxtConfigSchema)
|
||||||
|
}
|
||||||
|
@ -120,7 +120,7 @@ function _defineNuxtModule<
|
|||||||
// Measure setup time
|
// Measure setup time
|
||||||
if (setupTime > 5000 && uniqueKey !== '@nuxt/telemetry') {
|
if (setupTime > 5000 && uniqueKey !== '@nuxt/telemetry') {
|
||||||
logger.warn(`Slow module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`)
|
logger.warn(`Slow module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`)
|
||||||
} else if (nuxt.options.debug) {
|
} else if (nuxt.options.debug && nuxt.options.debug.modules) {
|
||||||
logger.info(`Module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`)
|
logger.info(`Module \`${uniqueKey || '<no name>'}\` took \`${setupTime}ms\` to setup.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
76
packages/kit/src/runtime-config.test.ts
Normal file
76
packages/kit/src/runtime-config.test.ts
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
import { useRuntimeConfig } from './runtime-config'
|
||||||
|
|
||||||
|
const { useNuxt, klona } = vi.hoisted(() => ({ useNuxt: vi.fn(), klona: vi.fn() }))
|
||||||
|
|
||||||
|
vi.mock('./context', () => ({ useNuxt }))
|
||||||
|
vi.mock('klona', () => ({ klona }))
|
||||||
|
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'should return runtime config with environment variables applied',
|
||||||
|
runtimeConfig: {
|
||||||
|
apiUrl: 'http://localhost',
|
||||||
|
authUrl: 'http://auth.com',
|
||||||
|
},
|
||||||
|
envExpansion: true,
|
||||||
|
env: {
|
||||||
|
NITRO_API_URL: 'http://example.com',
|
||||||
|
},
|
||||||
|
expected: {
|
||||||
|
apiUrl: 'http://example.com',
|
||||||
|
authUrl: 'http://auth.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'should expand environment variables in strings',
|
||||||
|
runtimeConfig: {
|
||||||
|
apiUrl: '{{BASE_URL}}/api',
|
||||||
|
mail: '{{MAIL_SCHEME}}://{{MAIL_HOST}}:{{MAIL_PORT}}',
|
||||||
|
},
|
||||||
|
envExpansion: true,
|
||||||
|
env: {
|
||||||
|
BASE_URL: 'http://example.com',
|
||||||
|
MAIL_SCHEME: 'http',
|
||||||
|
MAIL_HOST: 'localhost',
|
||||||
|
MAIL_PORT: '3366',
|
||||||
|
},
|
||||||
|
expected: {
|
||||||
|
apiUrl: 'http://example.com/api',
|
||||||
|
mail: 'http://localhost:3366',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description:
|
||||||
|
'should not expand environment variables if envExpansion is false',
|
||||||
|
runtimeConfig: {
|
||||||
|
apiUrl: '{{BASE_URL}}/api',
|
||||||
|
someUrl: '',
|
||||||
|
},
|
||||||
|
envExpansion: false,
|
||||||
|
env: {
|
||||||
|
BASE_URL: 'http://example1.com',
|
||||||
|
NITRO_NOT_API_URL: 'http://example2.com',
|
||||||
|
NUXT_SOME_URL: 'http://example3.com',
|
||||||
|
},
|
||||||
|
expected: {
|
||||||
|
apiUrl: '{{BASE_URL}}/api',
|
||||||
|
someUrl: 'http://example3.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
describe('useRuntimeConfig', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
vi.unstubAllEnvs()
|
||||||
|
})
|
||||||
|
|
||||||
|
it.each(testCases)('$description', ({ runtimeConfig, envExpansion, env, expected }) => {
|
||||||
|
useNuxt.mockReturnValue({ options: { nitro: { runtimeConfig, experimental: { envExpansion } } } })
|
||||||
|
klona.mockReturnValue(runtimeConfig)
|
||||||
|
Object.entries(env).forEach(([key, value]) => vi.stubEnv(key, value))
|
||||||
|
|
||||||
|
expect(useRuntimeConfig()).toEqual(expected)
|
||||||
|
})
|
||||||
|
})
|
@ -94,7 +94,7 @@ function applyEnv (
|
|||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
const envExpandRx = /\{\{(.*?)\}\}/g
|
const envExpandRx = /\{\{([^{}]*)\}\}/g
|
||||||
|
|
||||||
function _expandFromEnv (value: string, env: Record<string, any> = process.env) {
|
function _expandFromEnv (value: string, env: Record<string, any> = process.env) {
|
||||||
return value.replace(envExpandRx, (match, key) => {
|
return value.replace(envExpandRx, (match, key) => {
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import { afterAll, bench, describe } from 'vitest'
|
import { rm } from 'node:fs/promises'
|
||||||
import { join, normalize } from 'pathe'
|
import { afterAll, beforeAll, bench, describe } from 'vitest'
|
||||||
|
import { join, normalize, resolve } from 'pathe'
|
||||||
import { withoutTrailingSlash } from 'ufo'
|
import { withoutTrailingSlash } from 'ufo'
|
||||||
import { loadNuxt, writeTypes } from '@nuxt/kit'
|
import { loadNuxt, writeTypes } from '@nuxt/kit'
|
||||||
|
import type { Nuxt } from 'nuxt/schema'
|
||||||
|
|
||||||
describe('writeTypes', async () => {
|
describe('writeTypes', () => {
|
||||||
const relativeDir = join('../../..', 'test/fixtures/basic-types')
|
const relativeDir = join('../../..', 'test/fixtures/basic-types')
|
||||||
const path = withoutTrailingSlash(normalize(fileURLToPath(new URL(relativeDir, import.meta.url))))
|
const path = withoutTrailingSlash(normalize(fileURLToPath(new URL(relativeDir, import.meta.url))))
|
||||||
|
|
||||||
const nuxt = await loadNuxt({ cwd: path })
|
let nuxt: Nuxt
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
nuxt = await loadNuxt({ cwd: path })
|
||||||
|
await rm(resolve(path, '.nuxt'), { recursive: true, force: true })
|
||||||
|
}, 20_000)
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await nuxt.close()
|
await nuxt.close()
|
||||||
})
|
}, 20_000)
|
||||||
|
|
||||||
bench('writeTypes in the basic-types fixture', async () => {
|
bench('writeTypes in the basic-types fixture', async () => {
|
||||||
await writeTypes(nuxt)
|
await writeTypes(nuxt)
|
||||||
|
@ -64,9 +64,9 @@
|
|||||||
"test:attw": "attw --pack"
|
"test:attw": "attw --pack"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/cli": "^3.20.0",
|
"@nuxt/cli": "^3.21.1",
|
||||||
"@nuxt/devalue": "^2.0.2",
|
"@nuxt/devalue": "^2.0.2",
|
||||||
"@nuxt/devtools": "^1.7.0",
|
"@nuxt/devtools": "^2.0.0",
|
||||||
"@nuxt/kit": "workspace:*",
|
"@nuxt/kit": "workspace:*",
|
||||||
"@nuxt/schema": "workspace:*",
|
"@nuxt/schema": "workspace:*",
|
||||||
"@nuxt/telemetry": "^2.6.4",
|
"@nuxt/telemetry": "^2.6.4",
|
||||||
@ -100,8 +100,8 @@
|
|||||||
"magic-string": "^0.30.17",
|
"magic-string": "^0.30.17",
|
||||||
"mlly": "^1.7.4",
|
"mlly": "^1.7.4",
|
||||||
"nanotar": "^0.2.0",
|
"nanotar": "^0.2.0",
|
||||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28938837.19ec5395",
|
"nitro": "npm:nitro-nightly@3.0.0-beta-28969273.f7aa9de6",
|
||||||
"nypm": "^0.5.0",
|
"nypm": "^0.5.2",
|
||||||
"ofetch": "^1.4.1",
|
"ofetch": "^1.4.1",
|
||||||
"ohash": "^1.1.4",
|
"ohash": "^1.1.4",
|
||||||
"pathe": "^2.0.2",
|
"pathe": "^2.0.2",
|
||||||
@ -109,7 +109,7 @@
|
|||||||
"pkg-types": "^1.3.1",
|
"pkg-types": "^1.3.1",
|
||||||
"radix3": "^1.1.2",
|
"radix3": "^1.1.2",
|
||||||
"scule": "^1.3.0",
|
"scule": "^1.3.0",
|
||||||
"semver": "^7.6.3",
|
"semver": "^7.7.1",
|
||||||
"std-env": "^3.8.0",
|
"std-env": "^3.8.0",
|
||||||
"strip-literal": "^3.0.0",
|
"strip-literal": "^3.0.0",
|
||||||
"tinyglobby": "0.2.10",
|
"tinyglobby": "0.2.10",
|
||||||
@ -136,8 +136,8 @@
|
|||||||
"@vitejs/plugin-vue": "5.2.1",
|
"@vitejs/plugin-vue": "5.2.1",
|
||||||
"@vue/compiler-sfc": "3.5.13",
|
"@vue/compiler-sfc": "3.5.13",
|
||||||
"unbuild": "3.3.1",
|
"unbuild": "3.3.1",
|
||||||
"vite": "6.0.11",
|
"vite": "6.1.0",
|
||||||
"vitest": "3.0.4"
|
"vitest": "3.0.5"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@parcel/watcher": "^2.1.0",
|
"@parcel/watcher": "^2.1.0",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { DefineComponent, MaybeRef, VNode } from 'vue'
|
import type { DefineComponent, ExtractPublicPropTypes, MaybeRef, PropType, VNode } from 'vue'
|
||||||
import { Suspense, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from 'vue'
|
import { Suspense, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from 'vue'
|
||||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||||
|
|
||||||
@ -30,19 +30,23 @@ const LayoutLoader = defineComponent({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// props are moved outside of defineComponent to later explicitly assert the prop types
|
||||||
|
// this avoids type loss/simplification resulting in things like MaybeRef<string | false>, keeping type hints for layout names
|
||||||
|
const nuxtLayoutProps = {
|
||||||
|
name: {
|
||||||
|
type: [String, Boolean, Object] as PropType<unknown extends PageMeta['layout'] ? MaybeRef<string | false> : PageMeta['layout']>,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
fallback: {
|
||||||
|
type: [String, Object] as PropType<unknown extends PageMeta['layout'] ? MaybeRef<string> : PageMeta['layout']>,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'NuxtLayout',
|
name: 'NuxtLayout',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: {
|
props: nuxtLayoutProps,
|
||||||
name: {
|
|
||||||
type: [String, Boolean, Object] as unknown as () => unknown extends PageMeta['layout'] ? MaybeRef<string | false> : PageMeta['layout'],
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
fallback: {
|
|
||||||
type: [String, Object] as unknown as () => unknown extends PageMeta['layout'] ? MaybeRef<string> : PageMeta['layout'],
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup (props, context) {
|
setup (props, context) {
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
// Need to ensure (if we are not a child of `<NuxtPage>`) that we use synchronous route (not deferred)
|
// Need to ensure (if we are not a child of `<NuxtPage>`) that we use synchronous route (not deferred)
|
||||||
@ -95,9 +99,7 @@ export default defineComponent({
|
|||||||
}).default()
|
}).default()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}) as unknown as DefineComponent<{
|
}) as DefineComponent<ExtractPublicPropTypes<typeof nuxtLayoutProps>>
|
||||||
name?: (unknown extends PageMeta['layout'] ? MaybeRef<string | false> : PageMeta['layout']) | undefined
|
|
||||||
}>
|
|
||||||
|
|
||||||
const LayoutProvider = defineComponent({
|
const LayoutProvider = defineComponent({
|
||||||
name: 'NuxtLayoutProvider',
|
name: 'NuxtLayoutProvider',
|
||||||
|
@ -3,7 +3,8 @@ import type { Ref, VNode } from 'vue'
|
|||||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||||
import { PageRouteSymbol } from './injections'
|
import { PageRouteSymbol } from './injections'
|
||||||
|
|
||||||
export const RouteProvider = defineComponent({
|
export const defineRouteProvider = (name = 'RouteProvider') => defineComponent({
|
||||||
|
name,
|
||||||
props: {
|
props: {
|
||||||
vnode: {
|
vnode: {
|
||||||
type: Object as () => VNode,
|
type: Object as () => VNode,
|
||||||
@ -55,3 +56,5 @@ export const RouteProvider = defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const RouteProvider = defineRouteProvider()
|
||||||
|
@ -18,7 +18,7 @@ export const useRouter: typeof _useRouter = () => {
|
|||||||
|
|
||||||
/** @since 3.0.0 */
|
/** @since 3.0.0 */
|
||||||
export const useRoute: typeof _useRoute = () => {
|
export const useRoute: typeof _useRoute = () => {
|
||||||
if (import.meta.dev && isProcessingMiddleware()) {
|
if (import.meta.dev && !getCurrentInstance() && isProcessingMiddleware()) {
|
||||||
console.warn('[nuxt] Calling `useRoute` within middleware may lead to misleading results. Instead, use the (to, from) arguments passed to the middleware to access the new and old routes.')
|
console.warn('[nuxt] Calling `useRoute` within middleware may lead to misleading results. Instead, use the (to, from) arguments passed to the middleware to access the new and old routes.')
|
||||||
}
|
}
|
||||||
if (hasInjectionContext()) {
|
if (hasInjectionContext()) {
|
||||||
|
@ -8,7 +8,7 @@ export { defineNuxtLink } from './components/index'
|
|||||||
export type { NuxtLinkOptions, NuxtLinkProps } from './components/index'
|
export type { NuxtLinkOptions, NuxtLinkProps } from './components/index'
|
||||||
export { _getAppConfig, updateAppConfig, useAppConfig } from './config'
|
export { _getAppConfig, updateAppConfig, useAppConfig } from './config'
|
||||||
export { cancelIdleCallback, requestIdleCallback } from './compat/idle-callback'
|
export { cancelIdleCallback, requestIdleCallback } from './compat/idle-callback'
|
||||||
export type { NuxtAppLiterals, NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext, PageMeta } from './types'
|
export type { NuxtAppLiterals, NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext, PageMeta, NuxtPageProps } from './types'
|
||||||
|
|
||||||
export const isVue2 = false
|
export const isVue2 = false
|
||||||
export const isVue3 = true
|
export const isVue3 = true
|
||||||
|
@ -2,7 +2,7 @@ import { createDebugger } from 'hookable'
|
|||||||
import { defineNuxtPlugin } from '../nuxt'
|
import { defineNuxtPlugin } from '../nuxt'
|
||||||
|
|
||||||
export default defineNuxtPlugin({
|
export default defineNuxtPlugin({
|
||||||
name: 'nuxt:debug',
|
name: 'nuxt:debug:hooks',
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
setup (nuxtApp) {
|
setup (nuxtApp) {
|
||||||
createDebugger(nuxtApp.hooks, { tag: 'nuxt-app' })
|
createDebugger(nuxtApp.hooks, { tag: 'nuxt-app' })
|
@ -1,4 +1,4 @@
|
|||||||
export type { PageMeta } from '../pages/runtime/index'
|
export type { PageMeta, NuxtPageProps } from '../pages/runtime/index'
|
||||||
|
|
||||||
export interface NuxtAppLiterals {
|
export interface NuxtAppLiterals {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
|
@ -88,7 +88,7 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp, options: { filter?:
|
|||||||
const perf = performance.now() - start
|
const perf = performance.now() - start
|
||||||
const setupTime = Math.round((perf * 100)) / 100
|
const setupTime = Math.round((perf * 100)) / 100
|
||||||
|
|
||||||
if (nuxt.options.debug || setupTime > 500) {
|
if ((nuxt.options.debug && nuxt.options.debug.templates) || setupTime > 500) {
|
||||||
logger.info(`Compiled \`${template.filename}\` in ${setupTime}ms`)
|
logger.info(`Compiled \`${template.filename}\` in ${setupTime}ms`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +108,18 @@ function createWatcher () {
|
|||||||
ignored: [isIgnored, /[\\/]node_modules[\\/]/],
|
ignored: [isIgnored, /[\\/]node_modules[\\/]/],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const restartPaths = new Set<string>()
|
||||||
|
const srcDir = nuxt.options.srcDir.replace(/\/?$/, '/')
|
||||||
|
for (const pattern of nuxt.options.watch) {
|
||||||
|
if (typeof pattern !== 'string') { continue }
|
||||||
|
const path = resolve(nuxt.options.srcDir, pattern)
|
||||||
|
if (!path.startsWith(srcDir)) {
|
||||||
|
restartPaths.add(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watcher.add([...restartPaths])
|
||||||
|
|
||||||
watcher.on('all', (event, path) => {
|
watcher.on('all', (event, path) => {
|
||||||
if (event === 'all' || event === 'ready' || event === 'error' || event === 'raw') {
|
if (event === 'all' || event === 'ready' || event === 'error' || event === 'raw') {
|
||||||
return
|
return
|
||||||
@ -121,7 +133,7 @@ function createGranularWatcher () {
|
|||||||
const nuxt = useNuxt()
|
const nuxt = useNuxt()
|
||||||
const isIgnored = createIsIgnored(nuxt)
|
const isIgnored = createIsIgnored(nuxt)
|
||||||
|
|
||||||
if (nuxt.options.debug) {
|
if (nuxt.options.debug && nuxt.options.debug.watchers) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.time('[nuxt] builder:chokidar:watch')
|
console.time('[nuxt] builder:chokidar:watch')
|
||||||
}
|
}
|
||||||
@ -166,7 +178,7 @@ function createGranularWatcher () {
|
|||||||
})
|
})
|
||||||
watcher.on('ready', () => {
|
watcher.on('ready', () => {
|
||||||
pending--
|
pending--
|
||||||
if (nuxt.options.debug && !pending) {
|
if (nuxt.options.debug && nuxt.options.debug.watchers && !pending) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.timeEnd('[nuxt] builder:chokidar:watch')
|
console.timeEnd('[nuxt] builder:chokidar:watch')
|
||||||
}
|
}
|
||||||
@ -177,7 +189,7 @@ function createGranularWatcher () {
|
|||||||
|
|
||||||
async function createParcelWatcher () {
|
async function createParcelWatcher () {
|
||||||
const nuxt = useNuxt()
|
const nuxt = useNuxt()
|
||||||
if (nuxt.options.debug) {
|
if (nuxt.options.debug && nuxt.options.debug.watchers) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.time('[nuxt] builder:parcel:watch')
|
console.time('[nuxt] builder:parcel:watch')
|
||||||
}
|
}
|
||||||
@ -203,7 +215,7 @@ async function createParcelWatcher () {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
watcher.then((subscription) => {
|
watcher.then((subscription) => {
|
||||||
if (nuxt.options.debug) {
|
if (nuxt.options.debug && nuxt.options.debug.watchers) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.timeEnd('[nuxt] builder:parcel:watch')
|
console.timeEnd('[nuxt] builder:parcel:watch')
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
const isNuxtV4 = nuxt.options.future?.compatibilityVersion === 4
|
const isNuxtV4 = nuxt.options.future?.compatibilityVersion === 4
|
||||||
|
|
||||||
const nitroConfig: NitroConfig = defu(nuxt.options.nitro, {
|
const nitroConfig: NitroConfig = defu(nuxt.options.nitro, {
|
||||||
debug: nuxt.options.debug,
|
debug: nuxt.options.debug ? nuxt.options.debug.nitro : false,
|
||||||
rootDir: nuxt.options.rootDir,
|
rootDir: nuxt.options.rootDir,
|
||||||
workspaceDir: nuxt.options.workspaceDir,
|
workspaceDir: nuxt.options.workspaceDir,
|
||||||
srcDir: nuxt.options.serverDir,
|
srcDir: nuxt.options.serverDir,
|
||||||
|
@ -83,7 +83,6 @@ const nightlies = {
|
|||||||
|
|
||||||
export const keyDependencies = [
|
export const keyDependencies = [
|
||||||
'@nuxt/kit',
|
'@nuxt/kit',
|
||||||
'@nuxt/schema',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
let warnedAboutCompatDate = false
|
let warnedAboutCompatDate = false
|
||||||
@ -414,7 +413,7 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
await nuxt.callHook('modules:before')
|
await nuxt.callHook('modules:before')
|
||||||
const modulesToInstall = new Map<string | NuxtModule, Record<string, any>>()
|
const modulesToInstall = new Map<string | NuxtModule, Record<string, any>>()
|
||||||
|
|
||||||
const watchedPaths = new Set<string>()
|
const modulePaths = new Set<string>()
|
||||||
const specifiedModules = new Set<string>()
|
const specifiedModules = new Set<string>()
|
||||||
|
|
||||||
for (const _mod of nuxt.options.modules) {
|
for (const _mod of nuxt.options.modules) {
|
||||||
@ -432,13 +431,15 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
`${modulesDir}/*/index{${nuxt.options.extensions.join(',')}}`,
|
`${modulesDir}/*/index{${nuxt.options.extensions.join(',')}}`,
|
||||||
])
|
])
|
||||||
for (const mod of layerModules) {
|
for (const mod of layerModules) {
|
||||||
watchedPaths.add(mod)
|
modulePaths.add(mod)
|
||||||
if (specifiedModules.has(mod)) { continue }
|
if (specifiedModules.has(mod)) { continue }
|
||||||
specifiedModules.add(mod)
|
specifiedModules.add(mod)
|
||||||
modulesToInstall.set(mod, {})
|
modulesToInstall.set(mod, {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nuxt.options.watch.push(...modulePaths)
|
||||||
|
|
||||||
// Register user and then ad-hoc modules
|
// Register user and then ad-hoc modules
|
||||||
for (const key of ['modules', '_modules'] as const) {
|
for (const key of ['modules', '_modules'] as const) {
|
||||||
for (const item of nuxt.options[key as 'modules']) {
|
for (const item of nuxt.options[key as 'modules']) {
|
||||||
@ -554,9 +555,13 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
addPlugin(resolve(nuxt.options.appDir, 'plugins/preload.server'))
|
addPlugin(resolve(nuxt.options.appDir, 'plugins/preload.server'))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add nuxt app debugger
|
// Add nuxt app hooks debugger
|
||||||
if (nuxt.options.debug) {
|
if (
|
||||||
addPlugin(resolve(nuxt.options.appDir, 'plugins/debug'))
|
nuxt.options.debug
|
||||||
|
&& nuxt.options.debug.hooks
|
||||||
|
&& (nuxt.options.debug.hooks === true || nuxt.options.debug.hooks.client)
|
||||||
|
) {
|
||||||
|
addPlugin(resolve(nuxt.options.appDir, 'plugins/debug-hooks'))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add experimental Chrome devtools timings support
|
// Add experimental Chrome devtools timings support
|
||||||
@ -661,7 +666,7 @@ export default defineNuxtPlugin({
|
|||||||
nuxt.hooks.hook('builder:watch', (event, relativePath) => {
|
nuxt.hooks.hook('builder:watch', (event, relativePath) => {
|
||||||
const path = resolve(nuxt.options.srcDir, relativePath)
|
const path = resolve(nuxt.options.srcDir, relativePath)
|
||||||
// Local module patterns
|
// Local module patterns
|
||||||
if (watchedPaths.has(path)) {
|
if (modulePaths.has(path)) {
|
||||||
return nuxt.callHook('restart', { hard: true })
|
return nuxt.callHook('restart', { hard: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,7 +744,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
|
|||||||
: options.devtools?.enabled !== false // enabled by default unless explicitly disabled
|
: options.devtools?.enabled !== false // enabled by default unless explicitly disabled
|
||||||
|
|
||||||
if (isDevToolsEnabled) {
|
if (isDevToolsEnabled) {
|
||||||
if (!options._modules.some(m => m === '@nuxt/devtools' || m === '@nuxt/devtools-edge')) {
|
if (!options._modules.some(m => m === '@nuxt/devtools' || m === '@nuxt/devtools-nightly' || m === '@nuxt/devtools-edge')) {
|
||||||
options._modules.push('@nuxt/devtools')
|
options._modules.push('@nuxt/devtools')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -815,7 +820,11 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
|
|||||||
nuxt.hooks.addHooks(opts.overrides.hooks)
|
nuxt.hooks.addHooks(opts.overrides.hooks)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nuxt.options.debug) {
|
if (
|
||||||
|
nuxt.options.debug
|
||||||
|
&& nuxt.options.debug.hooks
|
||||||
|
&& (nuxt.options.debug.hooks === true || nuxt.options.debug.hooks.server)
|
||||||
|
) {
|
||||||
createDebugger(nuxt.hooks, { tag: 'nuxt' })
|
createDebugger(nuxt.hooks, { tag: 'nuxt' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,18 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
|
|||||||
name: 'nuxt:resolve-bare-imports',
|
name: 'nuxt:resolve-bare-imports',
|
||||||
enforce: 'post',
|
enforce: 'post',
|
||||||
configResolved (config) {
|
configResolved (config) {
|
||||||
conditions = config.mode === 'test' ? [...config.resolve.conditions, 'import', 'require'] : config.resolve.conditions
|
const resolvedConditions = new Set([nuxt.options.dev ? 'development' : 'production', ...config.resolve.conditions])
|
||||||
|
if (resolvedConditions.has('browser')) {
|
||||||
|
resolvedConditions.add('web')
|
||||||
|
resolvedConditions.add('import')
|
||||||
|
resolvedConditions.add('module')
|
||||||
|
resolvedConditions.add('default')
|
||||||
|
}
|
||||||
|
if (config.mode === 'test') {
|
||||||
|
resolvedConditions.add('import')
|
||||||
|
resolvedConditions.add('require')
|
||||||
|
}
|
||||||
|
conditions = [...resolvedConditions]
|
||||||
},
|
},
|
||||||
async resolveId (id, importer) {
|
async resolveId (id, importer) {
|
||||||
if (!importer || isAbsolute(id) || (!isAbsolute(importer) && !importer.startsWith('virtual:') && !importer.startsWith('\0virtual:')) || exclude.some(e => id.startsWith(e))) {
|
if (!importer || isAbsolute(id) || (!isAbsolute(importer) && !importer.startsWith('virtual:') && !importer.startsWith('\0virtual:')) || exclude.some(e => id.startsWith(e))) {
|
||||||
|
@ -674,7 +674,7 @@ function getServerComponentHTML (body: string): string {
|
|||||||
|
|
||||||
const SSR_SLOT_TELEPORT_MARKER = /^uid=([^;]*);slot=(.*)$/
|
const SSR_SLOT_TELEPORT_MARKER = /^uid=([^;]*);slot=(.*)$/
|
||||||
const SSR_CLIENT_TELEPORT_MARKER = /^uid=([^;]*);client=(.*)$/
|
const SSR_CLIENT_TELEPORT_MARKER = /^uid=([^;]*);client=(.*)$/
|
||||||
const SSR_CLIENT_SLOT_MARKER = /^island-slot=[^;]*;(.*)$/
|
const SSR_CLIENT_SLOT_MARKER = /^island-slot=([^;]*);(.*)$/
|
||||||
|
|
||||||
function getSlotIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['slots'] {
|
function getSlotIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['slots'] {
|
||||||
if (!ssrContext.islandContext || !Object.keys(ssrContext.islandContext.slots).length) { return undefined }
|
if (!ssrContext.islandContext || !Object.keys(ssrContext.islandContext.slots).length) { return undefined }
|
||||||
@ -698,21 +698,21 @@ function getClientIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandRespons
|
|||||||
response[clientUid] = {
|
response[clientUid] = {
|
||||||
...component,
|
...component,
|
||||||
html,
|
html,
|
||||||
slots: getComponentSlotTeleport(ssrContext.teleports ?? {}),
|
slots: getComponentSlotTeleport(clientUid, ssrContext.teleports ?? {}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
function getComponentSlotTeleport (teleports: Record<string, string>) {
|
function getComponentSlotTeleport (clientUid: string, teleports: Record<string, string>) {
|
||||||
const entries = Object.entries(teleports)
|
const entries = Object.entries(teleports)
|
||||||
const slots: Record<string, string> = {}
|
const slots: Record<string, string> = {}
|
||||||
|
|
||||||
for (const [key, value] of entries) {
|
for (const [key, value] of entries) {
|
||||||
const match = key.match(SSR_CLIENT_SLOT_MARKER)
|
const match = key.match(SSR_CLIENT_SLOT_MARKER)
|
||||||
if (match) {
|
if (match) {
|
||||||
const [, slot] = match
|
const [, id, slot] = match
|
||||||
if (!slot) { continue }
|
if (!slot || clientUid !== id) { continue }
|
||||||
slots[slot] = value
|
slots[slot] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ export default defineNuxtModule({
|
|||||||
const options: TypedRouterOptions = {
|
const options: TypedRouterOptions = {
|
||||||
routesFolder: [],
|
routesFolder: [],
|
||||||
dts: resolve(nuxt.options.buildDir, declarationFile),
|
dts: resolve(nuxt.options.buildDir, declarationFile),
|
||||||
logs: nuxt.options.debug,
|
logs: nuxt.options.debug && nuxt.options.debug.router,
|
||||||
async beforeWriteFiles (rootPage) {
|
async beforeWriteFiles (rootPage) {
|
||||||
rootPage.children.forEach(child => child.delete())
|
rootPage.children.forEach(child => child.delete())
|
||||||
const pages = nuxt.apps.default?.pages || await resolvePagesRoutes(nuxt)
|
const pages = nuxt.apps.default?.pages || await resolvePagesRoutes(nuxt)
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export { definePageMeta, defineRouteRules } from './composables'
|
export { definePageMeta, defineRouteRules } from './composables'
|
||||||
export type { PageMeta } from './composables'
|
export type { PageMeta } from './composables'
|
||||||
|
export type { NuxtPageProps } from './page'
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Fragment, Suspense, defineComponent, h, inject, nextTick, ref, watch } from 'vue'
|
import { Fragment, Suspense, defineComponent, h, inject, nextTick, ref, watch } from 'vue'
|
||||||
import type { KeepAliveProps, TransitionProps, VNode } from 'vue'
|
import type { AllowedComponentProps, Component, ComponentCustomProps, ComponentPublicInstance, KeepAliveProps, Slot, TransitionProps, VNode, VNodeProps } from 'vue'
|
||||||
import { RouterView } from 'vue-router'
|
import { RouterView } from 'vue-router'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from 'vue-router'
|
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded, RouterViewProps } from 'vue-router'
|
||||||
|
|
||||||
import { generateRouteKey, toArray, wrapInKeepAlive } from './utils'
|
import { generateRouteKey, toArray, wrapInKeepAlive } from './utils'
|
||||||
import type { RouterViewSlotProps } from './utils'
|
import type { RouterViewSlotProps } from './utils'
|
||||||
import { RouteProvider } from '#app/components/route-provider'
|
import { RouteProvider, defineRouteProvider } from '#app/components/route-provider'
|
||||||
import { useNuxtApp } from '#app/nuxt'
|
import { useNuxtApp } from '#app/nuxt'
|
||||||
import { useRouter } from '#app/composables/router'
|
import { useRouter } from '#app/composables/router'
|
||||||
import { _wrapInTransition } from '#app/components/utils'
|
import { _wrapInTransition } from '#app/components/utils'
|
||||||
@ -14,6 +14,23 @@ import { LayoutMetaSymbol, PageRouteSymbol } from '#app/components/injections'
|
|||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { appKeepalive as defaultKeepaliveConfig, appPageTransition as defaultPageTransition } from '#build/nuxt.config.mjs'
|
import { appKeepalive as defaultKeepaliveConfig, appPageTransition as defaultPageTransition } from '#build/nuxt.config.mjs'
|
||||||
|
|
||||||
|
export interface NuxtPageProps extends RouterViewProps {
|
||||||
|
/**
|
||||||
|
* Define global transitions for all pages rendered with the `NuxtPage` component.
|
||||||
|
*/
|
||||||
|
transition?: boolean | TransitionProps
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control state preservation of pages rendered with the `NuxtPage` component.
|
||||||
|
*/
|
||||||
|
keepalive?: boolean | KeepAliveProps
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control when the `NuxtPage` component is re-rendered.
|
||||||
|
*/
|
||||||
|
pageKey?: string | ((route: RouteLocationNormalizedLoaded) => string)
|
||||||
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'NuxtPage',
|
name: 'NuxtPage',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
@ -66,6 +83,9 @@ export default defineComponent({
|
|||||||
nuxtApp._isNuxtPageUsed = true
|
nuxtApp._isNuxtPageUsed = true
|
||||||
}
|
}
|
||||||
let pageLoadingEndHookAlreadyCalled = false
|
let pageLoadingEndHookAlreadyCalled = false
|
||||||
|
|
||||||
|
const routerProviderLookup = new WeakMap<Component, ReturnType<typeof defineRouteProvider> | undefined>()
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
return h(RouterView, { name: props.name, route: props.route, ...attrs }, {
|
return h(RouterView, { name: props.name, route: props.route, ...attrs }, {
|
||||||
default: (routeProps: RouterViewSlotProps) => {
|
default: (routeProps: RouterViewSlotProps) => {
|
||||||
@ -111,7 +131,7 @@ export default defineComponent({
|
|||||||
default: () => {
|
default: () => {
|
||||||
const providerVNode = h(RouteProvider, {
|
const providerVNode = h(RouteProvider, {
|
||||||
key: key || undefined,
|
key: key || undefined,
|
||||||
vnode: slots.default ? h(Fragment, undefined, slots.default(routeProps)) : routeProps.Component,
|
vnode: slots.default ? normalizeSlot(slots.default, routeProps) : routeProps.Component,
|
||||||
route: routeProps.route,
|
route: routeProps.route,
|
||||||
renderKey: key || undefined,
|
renderKey: key || undefined,
|
||||||
vnodeRef: pageRef,
|
vnodeRef: pageRef,
|
||||||
@ -124,7 +144,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Client side rendering
|
// Client side rendering
|
||||||
|
|
||||||
const hasTransition = !!(props.transition ?? routeProps.route.meta.pageTransition ?? defaultPageTransition)
|
const hasTransition = !!(props.transition ?? routeProps.route.meta.pageTransition ?? defaultPageTransition)
|
||||||
const transitionProps = hasTransition && _mergeTransitionProps([
|
const transitionProps = hasTransition && _mergeTransitionProps([
|
||||||
props.transition,
|
props.transition,
|
||||||
@ -148,18 +167,28 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
default: () => {
|
default: () => {
|
||||||
const providerVNode = h(RouteProvider, {
|
const routeProviderProps = {
|
||||||
key: key || undefined,
|
key: key || undefined,
|
||||||
vnode: slots.default ? h(Fragment, undefined, slots.default(routeProps)) : routeProps.Component,
|
vnode: slots.default ? normalizeSlot(slots.default, routeProps) : routeProps.Component,
|
||||||
route: routeProps.route,
|
route: routeProps.route,
|
||||||
renderKey: key || undefined,
|
renderKey: key || undefined,
|
||||||
trackRootNodes: hasTransition,
|
trackRootNodes: hasTransition,
|
||||||
vnodeRef: pageRef,
|
vnodeRef: pageRef,
|
||||||
})
|
|
||||||
if (keepaliveConfig) {
|
|
||||||
(providerVNode.type as any).name = (routeProps.Component.type as any).name || (routeProps.Component.type as any).__name || 'RouteProvider'
|
|
||||||
}
|
}
|
||||||
return providerVNode
|
|
||||||
|
if (!keepaliveConfig) {
|
||||||
|
return h(RouteProvider, routeProviderProps)
|
||||||
|
}
|
||||||
|
|
||||||
|
const routerComponentType = routeProps.Component.type as any
|
||||||
|
let PageRouteProvider = routerProviderLookup.get(routerComponentType)
|
||||||
|
|
||||||
|
if (!PageRouteProvider) {
|
||||||
|
PageRouteProvider = defineRouteProvider(routerComponentType.name || routerComponentType.__name)
|
||||||
|
routerProviderLookup.set(routerComponentType, PageRouteProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
return h(PageRouteProvider, routeProviderProps)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)).default()
|
)).default()
|
||||||
@ -169,7 +198,24 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
}) as unknown as {
|
||||||
|
new(): {
|
||||||
|
$props: AllowedComponentProps &
|
||||||
|
ComponentCustomProps &
|
||||||
|
VNodeProps &
|
||||||
|
NuxtPageProps
|
||||||
|
|
||||||
|
$slots: {
|
||||||
|
default?: (routeProps: RouterViewSlotProps) => VNode[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// expose
|
||||||
|
/**
|
||||||
|
* Reference to the page component instance
|
||||||
|
*/
|
||||||
|
pageRef: Element | ComponentPublicInstance | null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function _mergeTransitionProps (routeProps: TransitionProps[]): TransitionProps {
|
function _mergeTransitionProps (routeProps: TransitionProps[]): TransitionProps {
|
||||||
const _props: TransitionProps[] = routeProps.map(prop => ({
|
const _props: TransitionProps[] = routeProps.map(prop => ({
|
||||||
@ -198,3 +244,8 @@ function hasChildrenRoutes (fork: RouteLocationNormalizedLoaded | null, newRoute
|
|||||||
const index = newRoute.matched.findIndex(m => m.components?.default === Component?.type)
|
const index = newRoute.matched.findIndex(m => m.components?.default === Component?.type)
|
||||||
return index < newRoute.matched.length - 1
|
return index < newRoute.matched.length - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeSlot (slot: Slot, data: RouterViewSlotProps) {
|
||||||
|
const slotContent = slot(data)
|
||||||
|
return slotContent.length === 1 ? h(slotContent[0]!) : h(Fragment, undefined, slotContent)
|
||||||
|
}
|
||||||
|
33
packages/nuxt/test/build.bench.ts
Normal file
33
packages/nuxt/test/build.bench.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import { rm } from 'node:fs/promises'
|
||||||
|
import { beforeAll, bench, describe } from 'vitest'
|
||||||
|
import { join, normalize } from 'pathe'
|
||||||
|
import { withoutTrailingSlash } from 'ufo'
|
||||||
|
import { build, loadNuxt } from 'nuxt'
|
||||||
|
|
||||||
|
const basicTestFixtureDir = withoutTrailingSlash(normalize(fileURLToPath(new URL('../../../test/fixtures/basic', import.meta.url))))
|
||||||
|
|
||||||
|
describe('build', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await rm(join(basicTestFixtureDir, '.nuxt'), { recursive: true, force: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
bench('initial dev server build in the basic test fixture', async () => {
|
||||||
|
const nuxt = await loadNuxt({
|
||||||
|
cwd: basicTestFixtureDir,
|
||||||
|
ready: true,
|
||||||
|
overrides: {
|
||||||
|
dev: true,
|
||||||
|
sourcemap: false,
|
||||||
|
builder: {
|
||||||
|
bundle: () => Promise.resolve(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
nuxt.hook('build:done', () => resolve())
|
||||||
|
build(nuxt)
|
||||||
|
})
|
||||||
|
await nuxt.close()
|
||||||
|
})
|
||||||
|
})
|
@ -57,8 +57,8 @@ describe('islandTransform - server and island components', () => {
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const someData = 'some data'
|
const someData = 'some data'
|
||||||
|
|
||||||
</script>`
|
</script>`,
|
||||||
, 'hello.server.vue')
|
'hello.server.vue')
|
||||||
|
|
||||||
expect(normalizeLineEndings(result)).toMatchInlineSnapshot(`
|
expect(normalizeLineEndings(result)).toMatchInlineSnapshot(`
|
||||||
"<template>
|
"<template>
|
||||||
@ -130,8 +130,8 @@ withDefaults(defineProps<{ things?: any[]; somethingElse?: string }>(), {
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const someData = 'some data'
|
const someData = 'some data'
|
||||||
|
|
||||||
</script>`
|
</script>`,
|
||||||
, 'hello.server.vue')
|
'hello.server.vue')
|
||||||
|
|
||||||
expect(normalizeLineEndings(result)).toMatchInlineSnapshot(`
|
expect(normalizeLineEndings(result)).toMatchInlineSnapshot(`
|
||||||
"<template>
|
"<template>
|
||||||
@ -182,8 +182,8 @@ withDefaults(defineProps<{ things?: any[]; somethingElse?: string }>(), {
|
|||||||
|
|
||||||
const message = "Hello World";
|
const message = "Hello World";
|
||||||
</script>
|
</script>
|
||||||
`
|
`,
|
||||||
, 'hello.server.vue')
|
'hello.server.vue')
|
||||||
|
|
||||||
expect(normalizeLineEndings(result)).toMatchInlineSnapshot(`
|
expect(normalizeLineEndings(result)).toMatchInlineSnapshot(`
|
||||||
"<template>
|
"<template>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
import { bench, describe } from 'vitest'
|
import { rm } from 'node:fs/promises'
|
||||||
import { normalize } from 'pathe'
|
import { beforeAll, bench, describe } from 'vitest'
|
||||||
|
import { join, normalize } from 'pathe'
|
||||||
import { withoutTrailingSlash } from 'ufo'
|
import { withoutTrailingSlash } from 'ufo'
|
||||||
import { loadNuxt } from 'nuxt'
|
import { loadNuxt } from 'nuxt'
|
||||||
|
|
||||||
@ -8,6 +9,13 @@ const emptyDir = withoutTrailingSlash(normalize(fileURLToPath(new URL('../../../
|
|||||||
const basicTestFixtureDir = withoutTrailingSlash(normalize(fileURLToPath(new URL('../../../test/fixtures/basic', import.meta.url))))
|
const basicTestFixtureDir = withoutTrailingSlash(normalize(fileURLToPath(new URL('../../../test/fixtures/basic', import.meta.url))))
|
||||||
|
|
||||||
describe('loadNuxt', () => {
|
describe('loadNuxt', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await Promise.all([
|
||||||
|
rm(join(emptyDir, '.nuxt'), { recursive: true, force: true }),
|
||||||
|
rm(join(basicTestFixtureDir, '.nuxt'), { recursive: true, force: true }),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
bench('loadNuxt in an empty directory', async () => {
|
bench('loadNuxt in an empty directory', async () => {
|
||||||
const nuxt = await loadNuxt({
|
const nuxt = await loadNuxt({
|
||||||
cwd: emptyDir,
|
cwd: emptyDir,
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
"@types/pify": "5.0.4",
|
"@types/pify": "5.0.4",
|
||||||
"@types/webpack-bundle-analyzer": "4.7.0",
|
"@types/webpack-bundle-analyzer": "4.7.0",
|
||||||
"@types/webpack-hot-middleware": "2.25.9",
|
"@types/webpack-hot-middleware": "2.25.9",
|
||||||
"rollup": "4.32.0",
|
"rollup": "4.34.4",
|
||||||
"unbuild": "3.3.1",
|
"unbuild": "3.3.1",
|
||||||
"vue": "3.5.13"
|
"vue": "3.5.13"
|
||||||
},
|
},
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
||||||
"hookable": "5.5.3",
|
"hookable": "5.5.3",
|
||||||
"ignore": "7.0.3",
|
"ignore": "7.0.3",
|
||||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28938837.19ec5395",
|
"nitro": "npm:nitro-nightly@3.0.0-beta-28969273.f7aa9de6",
|
||||||
"ofetch": "1.4.1",
|
"ofetch": "1.4.1",
|
||||||
"pkg-types": "1.3.1",
|
"pkg-types": "1.3.1",
|
||||||
"sass-loader": "16.0.4",
|
"sass-loader": "16.0.4",
|
||||||
@ -60,7 +60,7 @@
|
|||||||
"unctx": "2.4.1",
|
"unctx": "2.4.1",
|
||||||
"unimport": "4.0.0",
|
"unimport": "4.0.0",
|
||||||
"untyped": "1.5.2",
|
"untyped": "1.5.2",
|
||||||
"vite": "6.0.11",
|
"vite": "6.1.0",
|
||||||
"vue": "3.5.13",
|
"vue": "3.5.13",
|
||||||
"vue-bundle-renderer": "2.1.1",
|
"vue-bundle-renderer": "2.1.1",
|
||||||
"vue-loader": "17.4.2",
|
"vue-loader": "17.4.2",
|
||||||
|
@ -314,7 +314,7 @@ export default defineUntypedSchema({
|
|||||||
* animation: loader 400ms linear infinite;
|
* animation: loader 400ms linear infinite;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* \@-webkit-keyframes loader {
|
* @-webkit-keyframes loader {
|
||||||
* 0% {
|
* 0% {
|
||||||
* -webkit-transform: translate(-50%, -50%) rotate(0deg);
|
* -webkit-transform: translate(-50%, -50%) rotate(0deg);
|
||||||
* }
|
* }
|
||||||
@ -322,7 +322,7 @@ export default defineUntypedSchema({
|
|||||||
* -webkit-transform: translate(-50%, -50%) rotate(360deg);
|
* -webkit-transform: translate(-50%, -50%) rotate(360deg);
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* \@keyframes loader {
|
* @keyframes loader {
|
||||||
* 0% {
|
* 0% {
|
||||||
* transform: translate(-50%, -50%) rotate(0deg);
|
* transform: translate(-50%, -50%) rotate(0deg);
|
||||||
* }
|
* }
|
||||||
|
@ -8,6 +8,7 @@ import { defu } from 'defu'
|
|||||||
import { findWorkspaceDir } from 'pkg-types'
|
import { findWorkspaceDir } from 'pkg-types'
|
||||||
|
|
||||||
import type { RuntimeConfig } from '../types/config'
|
import type { RuntimeConfig } from '../types/config'
|
||||||
|
import type { NuxtDebugOptions } from '../types/debug'
|
||||||
|
|
||||||
export default defineUntypedSchema({
|
export default defineUntypedSchema({
|
||||||
/**
|
/**
|
||||||
@ -264,9 +265,32 @@ export default defineUntypedSchema({
|
|||||||
* At the moment, it prints out hook names and timings on the server, and
|
* At the moment, it prints out hook names and timings on the server, and
|
||||||
* logs hook arguments as well in the browser.
|
* logs hook arguments as well in the browser.
|
||||||
*
|
*
|
||||||
|
* You can also set this to an object to enable specific debug options.
|
||||||
|
*
|
||||||
|
* @type {boolean | (typeof import('../src/types/debug').NuxtDebugOptions) | undefined}
|
||||||
*/
|
*/
|
||||||
debug: {
|
debug: {
|
||||||
$resolve: val => val ?? isDebug,
|
$resolve: (val: boolean | NuxtDebugOptions | undefined) => {
|
||||||
|
val ??= isDebug
|
||||||
|
if (val === false) {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
if (val === true) {
|
||||||
|
return {
|
||||||
|
templates: true,
|
||||||
|
modules: true,
|
||||||
|
watchers: true,
|
||||||
|
hooks: {
|
||||||
|
client: true,
|
||||||
|
server: true,
|
||||||
|
},
|
||||||
|
nitro: true,
|
||||||
|
router: true,
|
||||||
|
hydration: true,
|
||||||
|
} satisfies Required<NuxtDebugOptions>
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@ import { consola } from 'consola'
|
|||||||
import { resolve } from 'pathe'
|
import { resolve } from 'pathe'
|
||||||
import { isTest } from 'std-env'
|
import { isTest } from 'std-env'
|
||||||
import { defineUntypedSchema } from 'untyped'
|
import { defineUntypedSchema } from 'untyped'
|
||||||
|
import type { NuxtDebugOptions } from '../types/debug'
|
||||||
|
|
||||||
export default defineUntypedSchema({
|
export default defineUntypedSchema({
|
||||||
/**
|
/**
|
||||||
@ -20,9 +21,10 @@ export default defineUntypedSchema({
|
|||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
$resolve: async (val: Record<string, any> | undefined, get) => {
|
$resolve: async (val: Record<string, any> | undefined, get) => {
|
||||||
const [isDev, isDebug] = await Promise.all([get('dev'), get('debug')]) as [boolean, boolean]
|
const [isDev, debug] = await Promise.all([get('dev'), get('debug')]) as [boolean, boolean | NuxtDebugOptions]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': isDebug,
|
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': Boolean(debug && (debug === true || debug.hydration)),
|
||||||
'process.dev': isDev,
|
'process.dev': isDev,
|
||||||
'import.meta.dev': isDev,
|
'import.meta.dev': isDev,
|
||||||
'process.test': isTest,
|
'process.test': isTest,
|
||||||
|
@ -8,6 +8,7 @@ export type { AppHeadMetaObject, MetaObject, MetaObjectRaw, HeadAugmentations }
|
|||||||
export type { ModuleDefinition, ModuleMeta, ModuleOptions, ModuleSetupInstallResult, ModuleSetupReturn, NuxtModule, ResolvedModuleOptions } from './types/module'
|
export type { ModuleDefinition, ModuleMeta, ModuleOptions, ModuleSetupInstallResult, ModuleSetupReturn, NuxtModule, ResolvedModuleOptions } from './types/module'
|
||||||
export type { Nuxt, NuxtApp, NuxtPlugin, NuxtPluginTemplate, NuxtTemplate, NuxtTypeTemplate, NuxtServerTemplate, ResolvedNuxtTemplate } from './types/nuxt'
|
export type { Nuxt, NuxtApp, NuxtPlugin, NuxtPluginTemplate, NuxtTemplate, NuxtTypeTemplate, NuxtServerTemplate, ResolvedNuxtTemplate } from './types/nuxt'
|
||||||
export type { RouterConfig, RouterConfigSerializable, RouterOptions } from './types/router'
|
export type { RouterConfig, RouterConfigSerializable, RouterOptions } from './types/router'
|
||||||
|
export type { NuxtDebugOptions } from './types/debug'
|
||||||
|
|
||||||
// Schema
|
// Schema
|
||||||
export { default as NuxtConfigSchema } from './config/index'
|
export { default as NuxtConfigSchema } from './config/index'
|
||||||
|
@ -76,9 +76,10 @@ export interface NuxtBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Normalized Nuxt options available as `nuxt.options.*`
|
// Normalized Nuxt options available as `nuxt.options.*`
|
||||||
export interface NuxtOptions extends Omit<ConfigSchema, 'vue' | 'sourcemap' | 'builder' | 'postcss' | 'webpack'> {
|
export interface NuxtOptions extends Omit<ConfigSchema, 'vue' | 'sourcemap' | 'debug' | 'builder' | 'postcss' | 'webpack'> {
|
||||||
vue: Omit<ConfigSchema['vue'], 'config'> & { config?: Partial<Filter<VueAppConfig, string | boolean>> }
|
vue: Omit<ConfigSchema['vue'], 'config'> & { config?: Partial<Filter<VueAppConfig, string | boolean>> }
|
||||||
sourcemap: Required<Exclude<ConfigSchema['sourcemap'], boolean>>
|
sourcemap: Required<Exclude<ConfigSchema['sourcemap'], boolean>>
|
||||||
|
debug: Required<Exclude<ConfigSchema['debug'], true>>
|
||||||
builder: '@nuxt/vite-builder' | '@nuxt/webpack-builder' | '@nuxt/rspack-builder' | NuxtBuilder
|
builder: '@nuxt/vite-builder' | '@nuxt/webpack-builder' | '@nuxt/rspack-builder' | NuxtBuilder
|
||||||
postcss: Omit<ConfigSchema['postcss'], 'order'> & { order: Exclude<ConfigSchema['postcss']['order'], string> }
|
postcss: Omit<ConfigSchema['postcss'], 'order'> & { order: Exclude<ConfigSchema['postcss']['order'], string> }
|
||||||
webpack: ConfigSchema['webpack'] & {
|
webpack: ConfigSchema['webpack'] & {
|
||||||
|
21
packages/schema/src/types/debug.ts
Normal file
21
packages/schema/src/types/debug.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import type { NitroOptions } from 'nitro/types'
|
||||||
|
|
||||||
|
export interface NuxtDebugOptions {
|
||||||
|
/** Debug for Nuxt templates */
|
||||||
|
templates?: boolean
|
||||||
|
/** Debug for modules setup timings */
|
||||||
|
modules?: boolean
|
||||||
|
/** Debug for file watchers */
|
||||||
|
watchers?: boolean
|
||||||
|
/** Debug options for Nitro */
|
||||||
|
nitro?: NitroOptions['debug']
|
||||||
|
/** Debug for production hydration mismatch */
|
||||||
|
hydration?: boolean
|
||||||
|
/** Debug for Vue Router */
|
||||||
|
router?: boolean
|
||||||
|
/** Debug for hooks, can be set to `true` or an object with `server` and `client` keys */
|
||||||
|
hooks?: boolean | {
|
||||||
|
server?: boolean
|
||||||
|
client?: boolean
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@unocss/reset": "65.4.3",
|
"@unocss/reset": "65.4.3",
|
||||||
"beasties": "0.2.0",
|
"beasties": "0.2.0",
|
||||||
"html-validate": "9.1.3",
|
"html-validate": "9.2.1",
|
||||||
"htmlnano": "2.1.1",
|
"htmlnano": "2.1.1",
|
||||||
"jiti": "2.4.2",
|
"jiti": "2.4.2",
|
||||||
"knitwork": "1.2.0",
|
"knitwork": "1.2.0",
|
||||||
@ -30,6 +30,6 @@
|
|||||||
"tinyexec": "0.3.2",
|
"tinyexec": "0.3.2",
|
||||||
"tinyglobby": "0.2.10",
|
"tinyglobby": "0.2.10",
|
||||||
"unocss": "65.4.3",
|
"unocss": "65.4.3",
|
||||||
"vite": "6.0.11"
|
"vite": "6.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
<h2 class="font-semibold text-base mt-1">Modules</h2>
|
<h2 class="font-semibold text-base mt-1">Modules</h2>
|
||||||
<p class="text-sm text-gray-700 dark:text-gray-200 group-hover:dark:text-gray-100">Discover our list of modules to supercharge your Nuxt project.</p>
|
<p class="text-sm text-gray-700 dark:text-gray-200 group-hover:dark:text-gray-100">Discover our list of modules to supercharge your Nuxt project.</p>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://nuxt.com/modules?utm_source=nuxt-welcome" target="_blank" class="relative flex flex-col gap-1 border p-6 rounded-lg border-gray-200 dark:border-white/10 dark:bg-white/5 bg-gray-50/10 group hover:dark:border-[#00DC82] hover:border-[#00DC82] transition-all">
|
<a href="https://nuxt.com/docs/examples?utm_source=nuxt-welcome" target="_blank" class="relative flex flex-col gap-1 border p-6 rounded-lg border-gray-200 dark:border-white/10 dark:bg-white/5 bg-gray-50/10 group hover:dark:border-[#00DC82] hover:border-[#00DC82] transition-all">
|
||||||
<div class="w-[32px] h-[32px] bg-[#00DC82]/5 flex items-center justify-center border rounded border-[#00DC82] transition-all dark:border-[#00DC82]/50 group-hover:dark:border-[#00DC82]/80 dark:bg-[#020420] text-[#00DC82] dark:text-[#00DC82]">
|
<div class="w-[32px] h-[32px] bg-[#00DC82]/5 flex items-center justify-center border rounded border-[#00DC82] transition-all dark:border-[#00DC82]/50 group-hover:dark:border-[#00DC82]/80 dark:bg-[#020420] text-[#00DC82] dark:text-[#00DC82]">
|
||||||
<svg class="size-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path fill="currentColor" d="M224 56v144a8 8 0 0 1-8 8H40a8 8 0 0 1-8-8V56a8 8 0 0 1 8-8h176a8 8 0 0 1 8 8Z" opacity=".2"/><path fill="currentColor" d="M216 40H40a16 16 0 0 0-16 16v144a16 16 0 0 0 16 16h176a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16Zm0 160H40V56h176v144ZM80 84a12 12 0 1 1-12-12a12 12 0 0 1 12 12Zm40 0a12 12 0 1 1-12-12a12 12 0 0 1 12 12Z"/></svg>
|
<svg class="size-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256"><path fill="currentColor" d="M224 56v144a8 8 0 0 1-8 8H40a8 8 0 0 1-8-8V56a8 8 0 0 1 8-8h176a8 8 0 0 1 8 8Z" opacity=".2"/><path fill="currentColor" d="M216 40H40a16 16 0 0 0-16 16v144a16 16 0 0 0 16 16h176a16 16 0 0 0 16-16V56a16 16 0 0 0-16-16Zm0 160H40V56h176v144ZM80 84a12 12 0 1 1-12-12a12 12 0 0 1 12 12Zm40 0a12 12 0 1 1-12-12a12 12 0 0 1 12 12Z"/></svg>
|
||||||
</div>
|
</div>
|
||||||
@ -93,6 +93,16 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584l-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584l-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"/></svg>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://go.nuxt.com/bluesky"
|
||||||
|
target="_blank"
|
||||||
|
class="focus-visible:ring-2 text-gray-500 hover:text-[#020420] dark:text-gray-400 dark:hover:text-white"
|
||||||
|
>
|
||||||
|
<span class="sr-only">Nuxt Bluesky</span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565C.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479c.815 2.736 3.713 3.66 6.383 3.364q.204-.03.415-.056q-.207.033-.415.056c-3.912.58-7.387 2.005-2.83 7.078c5.013 5.19 6.87-1.113 7.823-4.308c.953 3.195 2.05 9.271 7.733 4.308c4.267-4.308 1.172-6.498-2.74-7.078a9 9 0 0 1-.415-.056q.21.026.415.056c2.67.297 5.568-.628 6.383-3.364c.246-.828.624-5.79.624-6.478c0-.69-.139-1.861-.902-2.206c-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8"/></svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://go.nuxt.com/linkedin"
|
href="https://go.nuxt.com/linkedin"
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/schema": "workspace:*",
|
"@nuxt/schema": "workspace:*",
|
||||||
"rollup": "4.32.0",
|
"rollup": "4.34.4",
|
||||||
"unbuild": "3.3.1",
|
"unbuild": "3.3.1",
|
||||||
"vue": "3.5.13"
|
"vue": "3.5.13"
|
||||||
},
|
},
|
||||||
@ -41,6 +41,7 @@
|
|||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"esbuild": "^0.24.2",
|
"esbuild": "^0.24.2",
|
||||||
"escape-string-regexp": "^5.0.0",
|
"escape-string-regexp": "^5.0.0",
|
||||||
|
"externality": "^1.0.2",
|
||||||
"get-port-please": "^3.1.2",
|
"get-port-please": "^3.1.2",
|
||||||
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
||||||
"jiti": "^2.4.2",
|
"jiti": "^2.4.2",
|
||||||
@ -50,13 +51,13 @@
|
|||||||
"pathe": "^2.0.2",
|
"pathe": "^2.0.2",
|
||||||
"pkg-types": "^1.3.1",
|
"pkg-types": "^1.3.1",
|
||||||
"postcss": "^8.5.1",
|
"postcss": "^8.5.1",
|
||||||
"rollup-plugin-visualizer": "^5.13.1",
|
"rollup-plugin-visualizer": "^5.14.0",
|
||||||
"std-env": "^3.8.0",
|
"std-env": "^3.8.0",
|
||||||
"ufo": "^1.5.4",
|
"ufo": "^1.5.4",
|
||||||
"unenv": "^1.10.0",
|
"unenv": "^1.10.0",
|
||||||
"unplugin": "^2.1.2",
|
"unplugin": "^2.1.2",
|
||||||
"vite": "^6.0.11",
|
"vite": "^6.1.0",
|
||||||
"vite-node": "^3.0.4",
|
"vite-node": "^3.0.5",
|
||||||
"vite-plugin-checker": "^0.8.0",
|
"vite-plugin-checker": "^0.8.0",
|
||||||
"vue-bundle-renderer": "^2.1.1"
|
"vue-bundle-renderer": "^2.1.1"
|
||||||
},
|
},
|
||||||
|
@ -131,19 +131,6 @@ export async function buildClient (ctx: ViteBuildContext) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
|
||||||
name: 'nuxt:import-conditions',
|
|
||||||
enforce: 'post',
|
|
||||||
config (_config, env) {
|
|
||||||
if (env.mode !== 'test') {
|
|
||||||
return {
|
|
||||||
resolve: {
|
|
||||||
conditions: [ctx.nuxt.options.dev ? 'development' : 'production', 'web', 'browser', 'import', 'module', 'default'],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
devStyleSSRPlugin({
|
devStyleSSRPlugin({
|
||||||
srcDir: ctx.nuxt.options.srcDir,
|
srcDir: ctx.nuxt.options.srcDir,
|
||||||
buildAssetsURL: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir),
|
buildAssetsURL: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir),
|
||||||
|
36
packages/vite/src/utils/external.ts
Normal file
36
packages/vite/src/utils/external.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import type { ExternalsOptions } from 'externality'
|
||||||
|
import { ExternalsDefaults, isExternal } from 'externality'
|
||||||
|
import type { ViteDevServer } from 'vite'
|
||||||
|
import escapeStringRegexp from 'escape-string-regexp'
|
||||||
|
import { withTrailingSlash } from 'ufo'
|
||||||
|
import type { Nuxt } from 'nuxt/schema'
|
||||||
|
import { resolve } from 'pathe'
|
||||||
|
import { toArray } from '.'
|
||||||
|
|
||||||
|
export function createIsExternal (viteServer: ViteDevServer, nuxt: Nuxt) {
|
||||||
|
const externalOpts: ExternalsOptions = {
|
||||||
|
inline: [
|
||||||
|
/virtual:/,
|
||||||
|
/\.ts$/,
|
||||||
|
...ExternalsDefaults.inline || [],
|
||||||
|
...(
|
||||||
|
viteServer.config.ssr.noExternal && viteServer.config.ssr.noExternal !== true
|
||||||
|
? toArray(viteServer.config.ssr.noExternal)
|
||||||
|
: []
|
||||||
|
),
|
||||||
|
],
|
||||||
|
external: [
|
||||||
|
'#shared',
|
||||||
|
new RegExp('^' + escapeStringRegexp(withTrailingSlash(resolve(nuxt.options.rootDir, nuxt.options.dir.shared)))),
|
||||||
|
...(viteServer.config.ssr.external as string[]) || [],
|
||||||
|
/node_modules/,
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
modules: nuxt.options.modulesDir,
|
||||||
|
type: 'module',
|
||||||
|
extensions: ['.ts', '.js', '.json', '.vue', '.mjs', '.jsx', '.tsx', '.wasm'],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return (id: string) => isExternal(id, nuxt.options.rootDir, externalOpts)
|
||||||
|
}
|
@ -8,9 +8,11 @@ import { isFileServingAllowed } from 'vite'
|
|||||||
import type { ModuleNode, Plugin as VitePlugin } from 'vite'
|
import type { ModuleNode, Plugin as VitePlugin } from 'vite'
|
||||||
import { getQuery } from 'ufo'
|
import { getQuery } from 'ufo'
|
||||||
import { normalizeViteManifest } from 'vue-bundle-renderer'
|
import { normalizeViteManifest } from 'vue-bundle-renderer'
|
||||||
|
import { resolve as resolveModule } from 'mlly'
|
||||||
import { distDir } from './dirs'
|
import { distDir } from './dirs'
|
||||||
import type { ViteBuildContext } from './vite'
|
import type { ViteBuildContext } from './vite'
|
||||||
import { isCSS } from './utils'
|
import { isCSS } from './utils'
|
||||||
|
import { createIsExternal } from './utils/external'
|
||||||
|
|
||||||
// TODO: Remove this in favor of registerViteNodeMiddleware
|
// TODO: Remove this in favor of registerViteNodeMiddleware
|
||||||
// after Nitropack or h3 allows adding middleware after setup
|
// after Nitropack or h3 allows adding middleware after setup
|
||||||
@ -126,6 +128,15 @@ function createViteNodeApp (ctx: ViteBuildContext, invalidates: Set<string> = ne
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isExternal = createIsExternal(viteServer, ctx.nuxt)
|
||||||
|
node.shouldExternalize = async (id: string) => {
|
||||||
|
const result = await isExternal(id)
|
||||||
|
if (result?.external) {
|
||||||
|
return resolveModule(result.id, { url: ctx.nuxt.options.modulesDir }).catch(() => false)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return eventHandler(async (event) => {
|
return eventHandler(async (event) => {
|
||||||
const moduleId = decodeURI(event.path).substring(1)
|
const moduleId = decodeURI(event.path).substring(1)
|
||||||
if (moduleId === '/') {
|
if (moduleId === '/') {
|
||||||
|
@ -85,7 +85,7 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
|
|||||||
// https://github.com/vitejs/vite/tree/main/packages/vite/src/node/build.ts#L464-L478
|
// https://github.com/vitejs/vite/tree/main/packages/vite/src/node/build.ts#L464-L478
|
||||||
assetFileNames: nuxt.options.dev
|
assetFileNames: nuxt.options.dev
|
||||||
? undefined
|
? undefined
|
||||||
: chunk => withoutLeadingSlash(join(nuxt.options.app.buildAssetsDir, `${sanitizeFilePath(filename(chunk.name!))}.[hash].[ext]`)),
|
: chunk => withoutLeadingSlash(join(nuxt.options.app.buildAssetsDir, `${sanitizeFilePath(filename(chunk.names[0]!))}.[hash].[ext]`)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
"@types/pify": "5.0.4",
|
"@types/pify": "5.0.4",
|
||||||
"@types/webpack-bundle-analyzer": "4.7.0",
|
"@types/webpack-bundle-analyzer": "4.7.0",
|
||||||
"@types/webpack-hot-middleware": "2.25.9",
|
"@types/webpack-hot-middleware": "2.25.9",
|
||||||
"rollup": "4.32.0",
|
"rollup": "4.34.4",
|
||||||
"unbuild": "3.3.1",
|
"unbuild": "3.3.1",
|
||||||
"vue": "3.5.13"
|
"vue": "3.5.13"
|
||||||
},
|
},
|
||||||
|
@ -33,6 +33,6 @@ export function vue (ctx: WebpackConfigContext) {
|
|||||||
ctx.config.plugins!.push(new webpack.DefinePlugin({
|
ctx.config.plugins!.push(new webpack.DefinePlugin({
|
||||||
'__VUE_OPTIONS_API__': 'true',
|
'__VUE_OPTIONS_API__': 'true',
|
||||||
'__VUE_PROD_DEVTOOLS__': 'false',
|
'__VUE_PROD_DEVTOOLS__': 'false',
|
||||||
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': ctx.nuxt.options.debug,
|
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': ctx.nuxt.options.debug && ctx.nuxt.options.debug.hydration,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import pify from 'pify'
|
import pify from 'pify'
|
||||||
import { resolve } from 'pathe'
|
import { resolve } from 'pathe'
|
||||||
import { defineEventHandler, fromNodeMiddleware, handleCors, setHeader } from 'h3'
|
import { createError, defineEventHandler, fromNodeMiddleware, getRequestHeader, handleCors, setHeader } from 'h3'
|
||||||
import type { H3CorsOptions } from 'h3'
|
import type { H3CorsOptions } from 'h3'
|
||||||
import type { IncomingMessage, MultiWatching, ServerResponse } from 'webpack-dev-middleware'
|
import type { IncomingMessage, MultiWatching, ServerResponse } from 'webpack-dev-middleware'
|
||||||
import webpackDevMiddleware from 'webpack-dev-middleware'
|
import webpackDevMiddleware from 'webpack-dev-middleware'
|
||||||
@ -146,6 +146,12 @@ function wdmToH3Handler (devMiddleware: webpackDevMiddleware.API<IncomingMessage
|
|||||||
if (isPreflight) {
|
if (isPreflight) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disallow cross-site requests in no-cors mode
|
||||||
|
if (getRequestHeader(event, 'sec-fetch-mode') === 'no-cors' && getRequestHeader(event, 'sec-fetch-site') === 'cross-site') {
|
||||||
|
throw createError({ statusCode: 403 })
|
||||||
|
}
|
||||||
|
|
||||||
setHeader(event, 'Vary', 'Origin')
|
setHeader(event, 'Vary', 'Origin')
|
||||||
|
|
||||||
event.context.webpack = {
|
event.context.webpack = {
|
||||||
|
2211
pnpm-lock.yaml
2211
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -1943,6 +1943,7 @@ describe('server components/islands', () => {
|
|||||||
// test islands mounted client side with slot
|
// test islands mounted client side with slot
|
||||||
await page.locator('#show-island').click()
|
await page.locator('#show-island').click()
|
||||||
expect(await page.locator('#island-mounted-client-side').innerHTML()).toContain('Interactive testing slot post SSR')
|
expect(await page.locator('#island-mounted-client-side').innerHTML()).toContain('Interactive testing slot post SSR')
|
||||||
|
expect(await page.locator('#island-mounted-client-side').innerHTML()).toContain('Sugar Counter')
|
||||||
|
|
||||||
// test islands wrapped with client-only
|
// test islands wrapped with client-only
|
||||||
expect(await page.locator('#wrapped-client-only').innerHTML()).toContain('Was router enabled')
|
expect(await page.locator('#wrapped-client-only').innerHTML()).toContain('Was router enabled')
|
||||||
|
@ -23,8 +23,8 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
const [clientStats, clientStatsInlined] = await Promise.all((['.output', '.output-inline'])
|
const [clientStats, clientStatsInlined] = await Promise.all((['.output', '.output-inline'])
|
||||||
.map(outputDir => analyzeSizes(['**/*.js'], join(rootDir, outputDir, 'public'))))
|
.map(outputDir => analyzeSizes(['**/*.js'], join(rootDir, outputDir, 'public'))))
|
||||||
|
|
||||||
expect.soft(roundToKilobytes(clientStats!.totalBytes)).toMatchInlineSnapshot(`"116k"`)
|
expect.soft(roundToKilobytes(clientStats!.totalBytes)).toMatchInlineSnapshot(`"115k"`)
|
||||||
expect.soft(roundToKilobytes(clientStatsInlined!.totalBytes)).toMatchInlineSnapshot(`"116k"`)
|
expect.soft(roundToKilobytes(clientStatsInlined!.totalBytes)).toMatchInlineSnapshot(`"115k"`)
|
||||||
|
|
||||||
const files = new Set([...clientStats!.files, ...clientStatsInlined!.files].map(f => f.replace(/\..*\.js/, '.js')))
|
const files = new Set([...clientStats!.files, ...clientStatsInlined!.files].map(f => f.replace(/\..*\.js/, '.js')))
|
||||||
|
|
||||||
|
4
test/fixtures/basic-types/package.json
vendored
4
test/fixtures/basic-types/package.json
vendored
@ -10,8 +10,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"ofetch": "latest",
|
"ofetch": "latest",
|
||||||
"unplugin-vue-router": "^0.10.7",
|
"unplugin-vue-router": "latest",
|
||||||
"vitest": "1.6.0",
|
"vitest": "latest",
|
||||||
"vue": "latest",
|
"vue": "latest",
|
||||||
"vue-router": "latest"
|
"vue-router": "latest"
|
||||||
},
|
},
|
||||||
|
9
test/fixtures/basic-types/types.ts
vendored
9
test/fixtures/basic-types/types.ts
vendored
@ -258,7 +258,7 @@ describe('typed router integration', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('layouts', () => {
|
describe('layouts', () => {
|
||||||
it('recognizes named layouts', () => {
|
it('definePageMeta recognizes named layouts', () => {
|
||||||
definePageMeta({ layout: 'custom' })
|
definePageMeta({ layout: 'custom' })
|
||||||
definePageMeta({ layout: 'pascal-case' })
|
definePageMeta({ layout: 'pascal-case' })
|
||||||
definePageMeta({ layout: 'override' })
|
definePageMeta({ layout: 'override' })
|
||||||
@ -266,11 +266,14 @@ describe('layouts', () => {
|
|||||||
definePageMeta({ layout: 'invalid-layout' })
|
definePageMeta({ layout: 'invalid-layout' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('allows typing layouts', () => {
|
it('NuxtLayout recognizes named layouts', () => {
|
||||||
h(NuxtLayout, { name: 'custom' })
|
h(NuxtLayout, { name: 'custom' })
|
||||||
|
|
||||||
// @ts-expect-error Invalid layout
|
// @ts-expect-error Invalid layout
|
||||||
h(NuxtLayout, { name: 'invalid-layout' })
|
h(NuxtLayout, { name: 'invalid-layout' })
|
||||||
|
|
||||||
|
h(NuxtLayout, { fallback: 'custom' })
|
||||||
|
// @ts-expect-error Invalid layout
|
||||||
|
h(NuxtLayout, { fallback: 'invalid-layout' })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -661,14 +661,13 @@ describe('routing utilities: `encodeURL`', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('routing utilities: `useRoute`', () => {
|
describe('routing utilities: `useRoute`', () => {
|
||||||
it('should show provide a mock route', () => {
|
it('should provide a route', () => {
|
||||||
expect(useRoute()).toMatchObject({
|
expect(useRoute()).toMatchObject({
|
||||||
fullPath: '/',
|
fullPath: '/',
|
||||||
hash: '',
|
hash: '',
|
||||||
href: '/',
|
matched: expect.arrayContaining([]),
|
||||||
matched: [],
|
|
||||||
meta: {},
|
meta: {},
|
||||||
name: undefined,
|
name: 'catchall',
|
||||||
params: {},
|
params: {},
|
||||||
path: '/',
|
path: '/',
|
||||||
query: {},
|
query: {},
|
||||||
|
97
test/nuxt/nuxt-page.test.ts
Normal file
97
test/nuxt/nuxt-page.test.ts
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/// <reference path="../fixtures/basic/.nuxt/nuxt.d.ts" />
|
||||||
|
|
||||||
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
|
import { mountSuspended } from '@nuxt/test-utils/runtime'
|
||||||
|
import { NuxtLayout, NuxtPage } from '#components'
|
||||||
|
|
||||||
|
describe('NuxtPage should work with keepalive options', () => {
|
||||||
|
let visits = 0
|
||||||
|
const router = useRouter()
|
||||||
|
beforeEach(() => {
|
||||||
|
visits = 0
|
||||||
|
router.addRoute({
|
||||||
|
name: 'home',
|
||||||
|
path: '/home',
|
||||||
|
component: defineComponent({
|
||||||
|
name: 'home',
|
||||||
|
setup () {
|
||||||
|
visits++
|
||||||
|
return () => h('div', 'home')
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
afterEach(() => {
|
||||||
|
router.removeRoute('home')
|
||||||
|
})
|
||||||
|
// include/exclude/boolean
|
||||||
|
it('should reload setup every time a page is visited, without keepalive', async () => {
|
||||||
|
const el = await mountSuspended({
|
||||||
|
setup () {
|
||||||
|
return () => h(NuxtLayout, {}, { default: () => h(NuxtPage) })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await navigateTo('/home')
|
||||||
|
await navigateTo('/')
|
||||||
|
await navigateTo('/home')
|
||||||
|
expect(visits).toBe(2)
|
||||||
|
el.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not remount a page when keepalive is enabled', async () => {
|
||||||
|
const el = await mountSuspended({
|
||||||
|
setup () {
|
||||||
|
return () => h(NuxtLayout, {}, { default: () => h(NuxtPage, { keepalive: true }) })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await navigateTo('/home')
|
||||||
|
await navigateTo('/')
|
||||||
|
await navigateTo('/home')
|
||||||
|
expect(visits).toBe(1)
|
||||||
|
el.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not remount a page when keepalive is granularly enabled (with include)', async () => {
|
||||||
|
const el = await mountSuspended({
|
||||||
|
setup () {
|
||||||
|
return () => h(NuxtLayout, {}, { default: () => h(NuxtPage, { keepalive: { include: ['home'] } }) })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await navigateTo('/home')
|
||||||
|
await navigateTo('/')
|
||||||
|
await navigateTo('/home')
|
||||||
|
expect(visits).toBe(1)
|
||||||
|
el.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not remount a page when keepalive is granularly enabled (with exclude)', async () => {
|
||||||
|
const el = await mountSuspended({
|
||||||
|
setup () {
|
||||||
|
return () => h(NuxtLayout, {}, { default: () => h(NuxtPage, { keepalive: { exclude: ['catchall'] } }) })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await navigateTo('/home')
|
||||||
|
await navigateTo('/')
|
||||||
|
await navigateTo('/home')
|
||||||
|
expect(visits).toBe(1)
|
||||||
|
el.unmount()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not remount a page when keepalive options are modified', async () => {
|
||||||
|
const pages = ref('home')
|
||||||
|
const el = await mountSuspended({
|
||||||
|
setup () {
|
||||||
|
return () => h(NuxtLayout, {}, { default: () => h(NuxtPage, { keepalive: { include: pages.value } }) })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await navigateTo('/home')
|
||||||
|
await navigateTo('/')
|
||||||
|
await navigateTo('/home')
|
||||||
|
pages.value = 'home,catchall'
|
||||||
|
await navigateTo('/')
|
||||||
|
await navigateTo('/home')
|
||||||
|
expect(visits).toBe(1)
|
||||||
|
el.unmount()
|
||||||
|
})
|
||||||
|
})
|
17
test/runtime/app/router.options.ts
Normal file
17
test/runtime/app/router.options.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import type { RouterOptions } from 'nuxt/schema'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
export default <RouterOptions> {
|
||||||
|
routes (_routes) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'catchall',
|
||||||
|
path: '/:catchAll(.*)*',
|
||||||
|
component: defineComponent({
|
||||||
|
name: 'catchall',
|
||||||
|
setup: () => () => ({}),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
@ -13,6 +13,7 @@ export default defineVitestConfig({
|
|||||||
environmentOptions: {
|
environmentOptions: {
|
||||||
nuxt: {
|
nuxt: {
|
||||||
overrides: {
|
overrides: {
|
||||||
|
pages: true,
|
||||||
runtimeConfig: {
|
runtimeConfig: {
|
||||||
app: {
|
app: {
|
||||||
buildId: 'override',
|
buildId: 'override',
|
||||||
|
Loading…
Reference in New Issue
Block a user