mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-14 01:53:55 +00:00
Merge branch 'main' into patch-21
This commit is contained in:
commit
a80843f9d2
1
.github/workflows/check-links.yml
vendored
1
.github/workflows/check-links.yml
vendored
@ -7,6 +7,7 @@ on:
|
|||||||
- "*.md"
|
- "*.md"
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 3.x
|
||||||
|
|
||||||
# Remove default permissions of GITHUB_TOKEN for security
|
# Remove default permissions of GITHUB_TOKEN for security
|
||||||
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
|
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
|
||||||
|
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -7,12 +7,14 @@ on:
|
|||||||
- "*.md"
|
- "*.md"
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 3.x
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "docs/**"
|
- "docs/**"
|
||||||
- "*.md"
|
- "*.md"
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 3.x
|
||||||
- "!v[0-9]*"
|
- "!v[0-9]*"
|
||||||
|
|
||||||
# https://github.com/vitejs/vite/blob/main/.github/workflows/ci.yml
|
# https://github.com/vitejs/vite/blob/main/.github/workflows/ci.yml
|
||||||
@ -198,7 +200,6 @@ jobs:
|
|||||||
builder: ["vite", "webpack"]
|
builder: ["vite", "webpack"]
|
||||||
context: ["async", "default"]
|
context: ["async", "default"]
|
||||||
manifest: ["manifest-on", "manifest-off"]
|
manifest: ["manifest-on", "manifest-off"]
|
||||||
version: ["v4", "v3"]
|
|
||||||
payload: ["json", "js"]
|
payload: ["json", "js"]
|
||||||
node: [18]
|
node: [18]
|
||||||
exclude:
|
exclude:
|
||||||
@ -244,7 +245,6 @@ jobs:
|
|||||||
TEST_BUILDER: ${{ matrix.builder }}
|
TEST_BUILDER: ${{ matrix.builder }}
|
||||||
TEST_MANIFEST: ${{ matrix.manifest }}
|
TEST_MANIFEST: ${{ matrix.manifest }}
|
||||||
TEST_CONTEXT: ${{ matrix.context }}
|
TEST_CONTEXT: ${{ matrix.context }}
|
||||||
TEST_V4: ${{ matrix.version == 'v4' }}
|
|
||||||
TEST_PAYLOAD: ${{ matrix.payload }}
|
TEST_PAYLOAD: ${{ matrix.payload }}
|
||||||
SKIP_BUNDLE_SIZE: ${{ github.event_name != 'push' || matrix.env == 'dev' || matrix.builder == 'webpack' || matrix.context == 'default' || matrix.payload == 'js' || runner.os == 'Windows' }}
|
SKIP_BUNDLE_SIZE: ${{ github.event_name != 'push' || matrix.env == 'dev' || matrix.builder == 'webpack' || matrix.context == 'default' || matrix.payload == 'js' || runner.os == 'Windows' }}
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ jobs:
|
|||||||
path: packages
|
path: packages
|
||||||
|
|
||||||
- name: Release Edge
|
- name: Release Edge
|
||||||
run: ./scripts/release-edge.sh
|
run: ./scripts/release-edge.sh ${{ github.ref == 'refs/heads/main' && 'latest' || '3x' }}
|
||||||
env:
|
env:
|
||||||
NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}}
|
NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}}
|
||||||
NPM_CONFIG_PROVENANCE: true
|
NPM_CONFIG_PROVENANCE: true
|
||||||
|
1
.github/workflows/docs.yml
vendored
1
.github/workflows/docs.yml
vendored
@ -9,6 +9,7 @@ on:
|
|||||||
# autofix workflow will be triggered instead for PRs
|
# autofix workflow will be triggered instead for PRs
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 3.x
|
||||||
- "!v[0-9]*"
|
- "!v[0-9]*"
|
||||||
|
|
||||||
# Remove default permissions of GITHUB_TOKEN for security
|
# Remove default permissions of GITHUB_TOKEN for security
|
||||||
|
2
.github/workflows/introspect.yml
vendored
2
.github/workflows/introspect.yml
vendored
@ -6,11 +6,13 @@ on:
|
|||||||
- ".github/workflows/**"
|
- ".github/workflows/**"
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 3.x
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- ".github/workflows/**"
|
- ".github/workflows/**"
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 3.x
|
||||||
- "!v[0-9]*"
|
- "!v[0-9]*"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
1
.github/workflows/label-pr.yml
vendored
1
.github/workflows/label-pr.yml
vendored
@ -6,6 +6,7 @@ on:
|
|||||||
- opened
|
- opened
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 3.x
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
add-pr-labels:
|
add-pr-labels:
|
||||||
|
19
.github/workflows/release-pr.yml
vendored
19
.github/workflows/release-pr.yml
vendored
@ -29,10 +29,25 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Get PR Info
|
||||||
|
id: pr
|
||||||
|
env:
|
||||||
|
PR_NUMBER: ${{ github.event.issue.number }}
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
GH_REPO: ${{ github.repository }}
|
||||||
|
COMMENT_AT: ${{ github.event.comment.created_at }}
|
||||||
|
run: |
|
||||||
|
pr="$(gh api -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/${GH_REPO}/pulls/${PR_NUMBER})"
|
||||||
|
head_sha="$(echo "$pr" | jq -r .head.sha)"
|
||||||
|
updated_at="$(echo "$pr" | jq -r .updated_at)"
|
||||||
|
|
||||||
|
if [[ $(date -d $updated_at) > $(date -d $COMMENT_AT) ]]; exit 1; fi
|
||||||
|
|
||||||
|
echo "head_sha=$head_sha" >> $GITHUB_OUTPUT
|
||||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.issue.pull_request.head.sha }}
|
ref: ${{ steps.pr.outputs.head_sha }}
|
||||||
fetch-depth: 0
|
fetch-depth: 1
|
||||||
|
|
||||||
- run: corepack enable
|
- run: corepack enable
|
||||||
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
|
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
@ -12,7 +12,7 @@ on:
|
|||||||
schedule:
|
schedule:
|
||||||
- cron: '20 7 * * 2'
|
- cron: '20 7 * * 2'
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: ["main", "3.x"]
|
||||||
|
|
||||||
# Declare default permissions as read only.
|
# Declare default permissions as read only.
|
||||||
permissions: read-all
|
permissions: read-all
|
||||||
|
@ -209,6 +209,7 @@ Previously `data` was initialized to `null` but reset in `clearNuxtData` to `und
|
|||||||
If you encounter any issues you can revert back to the previous behavior with:
|
If you encounter any issues you can revert back to the previous behavior with:
|
||||||
|
|
||||||
```ts twoslash [nuxt.config.ts]
|
```ts twoslash [nuxt.config.ts]
|
||||||
|
// @errors: 2353
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
experimental: {
|
experimental: {
|
||||||
defaults: {
|
defaults: {
|
||||||
@ -232,6 +233,7 @@ Please report an issue if you are doing this, as we do not plan to keep this as
|
|||||||
Previously it was possible to pass `dedupe: boolean` to `refresh`. These were aliases of `cancel` (`true`) and `defer` (`false`).
|
Previously it was possible to pass `dedupe: boolean` to `refresh`. These were aliases of `cancel` (`true`) and `defer` (`false`).
|
||||||
|
|
||||||
```ts twoslash [app.vue]
|
```ts twoslash [app.vue]
|
||||||
|
// @errors: 2322
|
||||||
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' }))
|
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' }))
|
||||||
|
|
||||||
async function refreshData () {
|
async function refreshData () {
|
||||||
@ -280,6 +282,7 @@ Often users set an appropriately empty value, such as an empty array, to avoid t
|
|||||||
If you encounter any issues you can revert back to the previous behavior, for now, with:
|
If you encounter any issues you can revert back to the previous behavior, for now, with:
|
||||||
|
|
||||||
```ts twoslash [nuxt.config.ts]
|
```ts twoslash [nuxt.config.ts]
|
||||||
|
// @errors: 2353
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
experimental: {
|
experimental: {
|
||||||
resetAsyncDataToUndefined: true,
|
resetAsyncDataToUndefined: true,
|
||||||
|
@ -328,7 +328,7 @@ definePageMeta({
|
|||||||
},
|
},
|
||||||
middleware (to, from) {
|
middleware (to, from) {
|
||||||
if (to.meta.pageTransition && typeof to.meta.pageTransition !== 'boolean')
|
if (to.meta.pageTransition && typeof to.meta.pageTransition !== 'boolean')
|
||||||
to.meta.pageTransition.name = +to.params.id > +from.params.id ? 'slide-left' : 'slide-right'
|
to.meta.pageTransition.name = +to.params.id! > +from.params.id! ? 'slide-left' : 'slide-right'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -57,20 +57,6 @@ export default defineNuxtConfig({
|
|||||||
This feature will likely be removed in a near future.
|
This feature will likely be removed in a near future.
|
||||||
::
|
::
|
||||||
|
|
||||||
## treeshakeClientOnly
|
|
||||||
|
|
||||||
Tree shakes contents of client-only components from server bundle.
|
|
||||||
|
|
||||||
*Enabled by default.*
|
|
||||||
|
|
||||||
```ts twoslash [nuxt.config.ts]
|
|
||||||
export default defineNuxtConfig({
|
|
||||||
experimental: {
|
|
||||||
treeshakeClientOnly: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## emitRouteChunkError
|
## emitRouteChunkError
|
||||||
|
|
||||||
Emits `app:chunkError` hook when there is an error loading vite/webpack chunks. Default behavior is to perform a hard reload of the new route when a chunk fails to load.
|
Emits `app:chunkError` hook when there is an error loading vite/webpack chunks. Default behavior is to perform a hard reload of the new route when a chunk fails to load.
|
||||||
@ -238,44 +224,6 @@ export default defineNuxtConfig({
|
|||||||
You can follow the server components roadmap on GitHub.
|
You can follow the server components roadmap on GitHub.
|
||||||
::
|
::
|
||||||
|
|
||||||
## configSchema
|
|
||||||
|
|
||||||
Enables config schema support.
|
|
||||||
|
|
||||||
*Enabled by default.*
|
|
||||||
|
|
||||||
```ts twoslash [nuxt.config.ts]
|
|
||||||
export default defineNuxtConfig({
|
|
||||||
experimental: {
|
|
||||||
configSchema: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## polyfillVueUseHead
|
|
||||||
|
|
||||||
Adds a compatibility layer for modules, plugins, or user code relying on the old `@vueuse/head` API.
|
|
||||||
|
|
||||||
```ts twoslash [nuxt.config.ts]
|
|
||||||
export default defineNuxtConfig({
|
|
||||||
experimental: {
|
|
||||||
polyfillVueUseHead: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## respectNoSSRHeader
|
|
||||||
|
|
||||||
Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header.
|
|
||||||
|
|
||||||
```ts twoslash [nuxt.config.ts]
|
|
||||||
export default defineNuxtConfig({
|
|
||||||
experimental: {
|
|
||||||
respectNoSSRHeader: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## localLayerAliases
|
## localLayerAliases
|
||||||
|
|
||||||
Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories.
|
Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories.
|
||||||
|
@ -45,6 +45,10 @@ counter.value = counter.value || Math.round(Math.random() * 1000)
|
|||||||
|
|
||||||
:link-example{to="/docs/examples/advanced/use-cookie"}
|
:link-example{to="/docs/examples/advanced/use-cookie"}
|
||||||
|
|
||||||
|
::note
|
||||||
|
Refresh `useCookie` values manually when a cookie has changed with [`refreshCookie`](/api/utils/refresh-cookie).
|
||||||
|
::
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
Cookie composable accepts several options which let you modify the behavior of cookies.
|
Cookie composable accepts several options which let you modify the behavior of cookies.
|
||||||
@ -148,6 +152,10 @@ Specifies the `boolean` or `string` value for [watch](https://vuejs.org/api/reac
|
|||||||
- `shallow` - Will watch cookie ref data changes for only top level properties
|
- `shallow` - Will watch cookie ref data changes for only top level properties
|
||||||
- `false` - Will not watch cookie ref data changes.
|
- `false` - Will not watch cookie ref data changes.
|
||||||
|
|
||||||
|
::note
|
||||||
|
Refresh `useCookie` values manually when a cookie has changed with [`refreshCookie`](/api/utils/refresh-cookie).
|
||||||
|
::
|
||||||
|
|
||||||
**Example 1:**
|
**Example 1:**
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
|
10
package.json
10
package.json
@ -54,9 +54,9 @@
|
|||||||
"@testing-library/vue": "8.1.0",
|
"@testing-library/vue": "8.1.0",
|
||||||
"@types/eslint__js": "8.42.3",
|
"@types/eslint__js": "8.42.3",
|
||||||
"@types/fs-extra": "11.0.4",
|
"@types/fs-extra": "11.0.4",
|
||||||
"@types/node": "20.14.5",
|
"@types/node": "20.14.7",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.5.8",
|
||||||
"@unhead/schema": "1.9.13",
|
"@unhead/schema": "1.9.14",
|
||||||
"@vitejs/plugin-vue": "5.0.4",
|
"@vitejs/plugin-vue": "5.0.4",
|
||||||
"@vitest/coverage-v8": "1.6.0",
|
"@vitest/coverage-v8": "1.6.0",
|
||||||
"@vue/test-utils": "2.4.6",
|
"@vue/test-utils": "2.4.6",
|
||||||
@ -71,8 +71,8 @@
|
|||||||
"execa": "9.2.0",
|
"execa": "9.2.0",
|
||||||
"fs-extra": "11.2.0",
|
"fs-extra": "11.2.0",
|
||||||
"globby": "14.0.1",
|
"globby": "14.0.1",
|
||||||
"h3": "1.11.1",
|
"h3": "1.12.0",
|
||||||
"happy-dom": "14.12.0",
|
"happy-dom": "14.12.3",
|
||||||
"jiti": "1.21.6",
|
"jiti": "1.21.6",
|
||||||
"markdownlint-cli": "0.41.0",
|
"markdownlint-cli": "0.41.0",
|
||||||
"nitropack": "2.9.6",
|
"nitropack": "2.9.6",
|
||||||
@ -85,7 +85,7 @@
|
|||||||
"rimraf": "5.0.7",
|
"rimraf": "5.0.7",
|
||||||
"semver": "7.6.2",
|
"semver": "7.6.2",
|
||||||
"std-env": "3.7.0",
|
"std-env": "3.7.0",
|
||||||
"typescript": "5.4.5",
|
"typescript": "5.5.2",
|
||||||
"ufo": "1.5.3",
|
"ufo": "1.5.3",
|
||||||
"vitest": "1.6.0",
|
"vitest": "1.6.0",
|
||||||
"vitest-environment-nuxt": "1.0.0",
|
"vitest-environment-nuxt": "1.0.0",
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
"unbuild": "latest",
|
"unbuild": "latest",
|
||||||
"vite": "5.3.1",
|
"vite": "5.3.1",
|
||||||
"vitest": "1.6.0",
|
"vitest": "1.6.0",
|
||||||
"webpack": "5.92.0"
|
"webpack": "5.92.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^14.18.0 || >=16.10.0"
|
"node": "^14.18.0 || >=16.10.0"
|
||||||
|
@ -81,19 +81,26 @@ export async function hasNuxtCompatibility (constraints: NuxtCompatibility, nuxt
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if current nuxt instance is version 2 legacy
|
* Check if current Nuxt instance is of specified major version
|
||||||
*/
|
*/
|
||||||
export function isNuxt2 (nuxt: Nuxt = useNuxt()) {
|
export function isNuxtMajorVersion (majorVersion: 2 | 3 | 4, nuxt: Nuxt = useNuxt()) {
|
||||||
const version = getNuxtVersion(nuxt)
|
const version = getNuxtVersion(nuxt)
|
||||||
return version[0] === '2' && version[1] === '.'
|
|
||||||
|
return version[0] === majorVersion.toString() && version[1] === '.'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if current nuxt instance is version 3
|
* @deprecated Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in \@nuxt/kit v5 or a future major version.
|
||||||
|
*/
|
||||||
|
export function isNuxt2 (nuxt: Nuxt = useNuxt()) {
|
||||||
|
return isNuxtMajorVersion(2, nuxt)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use `isNuxtMajorVersion(3, nuxt)` instead. This may be removed in \@nuxt/kit v5 or a future major version.
|
||||||
*/
|
*/
|
||||||
export function isNuxt3 (nuxt: Nuxt = useNuxt()) {
|
export function isNuxt3 (nuxt: Nuxt = useNuxt()) {
|
||||||
const version = getNuxtVersion(nuxt)
|
return isNuxtMajorVersion(3, nuxt)
|
||||||
return version[0] === '3' && version[1] === '.'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { performance } from 'node:perf_hooks'
|
import { performance } from 'node:perf_hooks'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
import { applyDefaults } from 'untyped'
|
import { applyDefaults } from 'untyped'
|
||||||
import type { ModuleDefinition, ModuleOptions, ModuleSetupReturn, Nuxt, NuxtModule, NuxtOptions } from '@nuxt/schema'
|
import type { ModuleDefinition, ModuleOptions, ModuleSetupInstallResult, ModuleSetupReturn, Nuxt, NuxtModule, NuxtOptions, ResolvedModuleOptions } from '@nuxt/schema'
|
||||||
import { logger } from '../logger'
|
import { logger } from '../logger'
|
||||||
import { tryUseNuxt, useNuxt } from '../context'
|
import { tryUseNuxt, useNuxt } from '../context'
|
||||||
import { checkNuxtCompatibility } from '../compatibility'
|
import { checkNuxtCompatibility } from '../compatibility'
|
||||||
@ -10,28 +10,76 @@ import { checkNuxtCompatibility } from '../compatibility'
|
|||||||
* Define a Nuxt module, automatically merging defaults with user provided options, installing
|
* Define a Nuxt module, automatically merging defaults with user provided options, installing
|
||||||
* any hooks that are provided, and calling an optional setup function for full control.
|
* any hooks that are provided, and calling an optional setup function for full control.
|
||||||
*/
|
*/
|
||||||
export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: ModuleDefinition<OptionsT> | NuxtModule<OptionsT>): NuxtModule<OptionsT> {
|
export function defineNuxtModule<TOptions extends ModuleOptions> (
|
||||||
if (typeof definition === 'function') { return defineNuxtModule({ setup: definition }) }
|
definition: ModuleDefinition<TOptions, Partial<TOptions>, false> | NuxtModule<TOptions, Partial<TOptions>, false>
|
||||||
|
): NuxtModule<TOptions, TOptions, false>
|
||||||
|
|
||||||
// Normalize definition and meta
|
export function defineNuxtModule<TOptions extends ModuleOptions> (): {
|
||||||
const module: ModuleDefinition<OptionsT> & Required<Pick<ModuleDefinition<OptionsT>, 'meta'>> = defu(definition, { meta: {} })
|
with: <TOptionsDefaults extends Partial<TOptions>> (
|
||||||
if (module.meta.configKey === undefined) {
|
definition: ModuleDefinition<TOptions, TOptionsDefaults, true> | NuxtModule<TOptions, TOptionsDefaults, true>
|
||||||
module.meta.configKey = module.meta.name
|
) => NuxtModule<TOptions, TOptionsDefaults, true>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function defineNuxtModule<TOptions extends ModuleOptions> (
|
||||||
|
definition?: ModuleDefinition<TOptions, Partial<TOptions>, false> | NuxtModule<TOptions, Partial<TOptions>, false>,
|
||||||
|
) {
|
||||||
|
if (definition) {
|
||||||
|
return _defineNuxtModule(definition)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
with: <TOptionsDefaults extends Partial<TOptions>>(
|
||||||
|
definition: ModuleDefinition<TOptions, TOptionsDefaults, true> | NuxtModule<TOptions, TOptionsDefaults, true>,
|
||||||
|
) => _defineNuxtModule(definition),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _defineNuxtModule<
|
||||||
|
TOptions extends ModuleOptions,
|
||||||
|
TOptionsDefaults extends Partial<TOptions>,
|
||||||
|
TWith extends boolean,
|
||||||
|
> (
|
||||||
|
definition: ModuleDefinition<TOptions, TOptionsDefaults, TWith> | NuxtModule<TOptions, TOptionsDefaults, TWith>,
|
||||||
|
): NuxtModule<TOptions, TOptionsDefaults, TWith> {
|
||||||
|
if (typeof definition === 'function') {
|
||||||
|
return _defineNuxtModule<TOptions, TOptionsDefaults, TWith>({ setup: definition })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize definition and meta
|
||||||
|
const module: ModuleDefinition<TOptions, TOptionsDefaults, TWith> & Required<Pick<ModuleDefinition<TOptions, TOptionsDefaults, TWith>, 'meta'>> = defu(definition, { meta: {} })
|
||||||
|
|
||||||
|
module.meta.configKey ||= module.meta.name
|
||||||
|
|
||||||
// Resolves module options from inline options, [configKey] in nuxt.config, defaults and schema
|
// Resolves module options from inline options, [configKey] in nuxt.config, defaults and schema
|
||||||
async function getOptions (inlineOptions?: OptionsT, nuxt: Nuxt = useNuxt()) {
|
async function getOptions (
|
||||||
const configKey = module.meta.configKey || module.meta.name!
|
inlineOptions?: Partial<TOptions>,
|
||||||
const _defaults = module.defaults instanceof Function ? module.defaults(nuxt) : module.defaults
|
nuxt: Nuxt = useNuxt(),
|
||||||
let _options = defu(inlineOptions, nuxt.options[configKey as keyof NuxtOptions], _defaults) as OptionsT
|
): Promise<
|
||||||
|
TWith extends true
|
||||||
|
? ResolvedModuleOptions<TOptions, TOptionsDefaults>
|
||||||
|
: TOptions
|
||||||
|
> {
|
||||||
|
const nuxtConfigOptionsKey = module.meta.configKey || module.meta.name
|
||||||
|
|
||||||
|
const nuxtConfigOptions: Partial<TOptions> = nuxtConfigOptionsKey && nuxtConfigOptionsKey in nuxt.options ? nuxt.options[<keyof NuxtOptions> nuxtConfigOptionsKey] : {}
|
||||||
|
|
||||||
|
const optionsDefaults: TOptionsDefaults =
|
||||||
|
module.defaults instanceof Function
|
||||||
|
? module.defaults(nuxt)
|
||||||
|
: module.defaults ?? <TOptionsDefaults> {}
|
||||||
|
|
||||||
|
let options = defu(inlineOptions, nuxtConfigOptions, optionsDefaults)
|
||||||
|
|
||||||
if (module.schema) {
|
if (module.schema) {
|
||||||
_options = await applyDefaults(module.schema, _options) as OptionsT
|
options = await applyDefaults(module.schema, options) as any
|
||||||
}
|
}
|
||||||
return Promise.resolve(_options)
|
|
||||||
|
// @ts-expect-error ignore type mismatch when calling `defineNuxtModule` without `.with()`
|
||||||
|
return Promise.resolve(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Module format is always a simple function
|
// Module format is always a simple function
|
||||||
async function normalizedModule (this: any, inlineOptions: OptionsT, nuxt: Nuxt) {
|
async function normalizedModule (this: any, inlineOptions: Partial<TOptions>, nuxt: Nuxt): Promise<ModuleSetupReturn> {
|
||||||
if (!nuxt) {
|
if (!nuxt) {
|
||||||
nuxt = tryUseNuxt() || this.nuxt /* invoked by nuxt 2 */
|
nuxt = tryUseNuxt() || this.nuxt /* invoked by nuxt 2 */
|
||||||
}
|
}
|
||||||
@ -81,7 +129,7 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
|||||||
if (res === false) { return false }
|
if (res === false) { return false }
|
||||||
|
|
||||||
// Return module install result
|
// Return module install result
|
||||||
return defu(res, <ModuleSetupReturn> {
|
return defu(res, <ModuleSetupInstallResult> {
|
||||||
timings: {
|
timings: {
|
||||||
setup: setupTime,
|
setup: setupTime,
|
||||||
},
|
},
|
||||||
@ -92,5 +140,5 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
|
|||||||
normalizedModule.getMeta = () => Promise.resolve(module.meta)
|
normalizedModule.getMeta = () => Promise.resolve(module.meta)
|
||||||
normalizedModule.getOptions = getOptions
|
normalizedModule.getOptions = getOptions
|
||||||
|
|
||||||
return normalizedModule as NuxtModule<OptionsT>
|
return <NuxtModule<TOptions, TOptionsDefaults, TWith>> normalizedModule
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ export async function installModule<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call module
|
// Call module
|
||||||
const res = await nuxtModule(inlineOptions, nuxt) ?? {}
|
const res = await nuxtModule(inlineOptions || {}, nuxt) ?? {}
|
||||||
if (res === false /* setup aborted */) {
|
if (res === false /* setup aborted */) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -65,9 +65,9 @@
|
|||||||
"@nuxt/schema": "workspace:*",
|
"@nuxt/schema": "workspace:*",
|
||||||
"@nuxt/telemetry": "^2.5.4",
|
"@nuxt/telemetry": "^2.5.4",
|
||||||
"@nuxt/vite-builder": "workspace:*",
|
"@nuxt/vite-builder": "workspace:*",
|
||||||
"@unhead/dom": "^1.9.13",
|
"@unhead/dom": "^1.9.14",
|
||||||
"@unhead/ssr": "^1.9.13",
|
"@unhead/ssr": "^1.9.14",
|
||||||
"@unhead/vue": "^1.9.13",
|
"@unhead/vue": "^1.9.14",
|
||||||
"@vue/shared": "^3.4.29",
|
"@vue/shared": "^3.4.29",
|
||||||
"acorn": "8.12.0",
|
"acorn": "8.12.0",
|
||||||
"c12": "^1.11.1",
|
"c12": "^1.11.1",
|
||||||
@ -81,7 +81,7 @@
|
|||||||
"estree-walker": "^3.0.3",
|
"estree-walker": "^3.0.3",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"globby": "^14.0.1",
|
"globby": "^14.0.1",
|
||||||
"h3": "^1.11.1",
|
"h3": "^1.12.0",
|
||||||
"hookable": "^5.5.3",
|
"hookable": "^5.5.3",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"jiti": "^1.21.6",
|
"jiti": "^1.21.6",
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
// TODO: remove in 4.x
|
|
||||||
export { default } from './nuxt-layout'
|
|
@ -8,10 +8,10 @@ import type {
|
|||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, provide, ref, resolveComponent } from 'vue'
|
import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, provide, ref, resolveComponent } from 'vue'
|
||||||
import type { RouteLocation, RouteLocationRaw, Router, RouterLink, RouterLinkProps, useLink } from '#vue-router'
|
import type { RouteLocation, RouteLocationRaw, Router, RouterLink, RouterLinkProps, useLink } from '#vue-router'
|
||||||
import { hasProtocol, joinURL, parseQuery, withQuery, withTrailingSlash, withoutTrailingSlash } from 'ufo'
|
import { hasProtocol, joinURL, parseQuery, withTrailingSlash, withoutTrailingSlash } from 'ufo'
|
||||||
import { preloadRouteComponents } from '../composables/preload'
|
import { preloadRouteComponents } from '../composables/preload'
|
||||||
import { onNuxtReady } from '../composables/ready'
|
import { onNuxtReady } from '../composables/ready'
|
||||||
import { navigateTo, useRouter } from '../composables/router'
|
import { navigateTo, resolveRouteObject, useRouter } from '../composables/router'
|
||||||
import { useNuxtApp, useRuntimeConfig } from '../nuxt'
|
import { useNuxtApp, useRuntimeConfig } from '../nuxt'
|
||||||
import { cancelIdleCallback, requestIdleCallback } from '../compat/idle-callback'
|
import { cancelIdleCallback, requestIdleCallback } from '../compat/idle-callback'
|
||||||
import { useIntersectionObserver } from '../utils'
|
import { useIntersectionObserver } from '../utils'
|
||||||
@ -453,7 +453,3 @@ function isSlowConnection () {
|
|||||||
if (cn && (cn.saveData || /2g/.test(cn.effectiveType))) { return true }
|
if (cn && (cn.saveData || /2g/.test(cn.effectiveType))) { return true }
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveRouteObject (to: Exclude<RouteLocationRaw, string>) {
|
|
||||||
return withQuery(to.path || '', to.query || {}) + (to.hash ? '#' + to.hash : '')
|
|
||||||
}
|
|
||||||
|
@ -8,10 +8,7 @@ import { createError } from './error'
|
|||||||
import { onNuxtReady } from './ready'
|
import { onNuxtReady } from './ready'
|
||||||
|
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { asyncDataDefaults, resetAsyncDataToUndefined } from '#build/nuxt.config.mjs'
|
import { asyncDataDefaults } from '#build/nuxt.config.mjs'
|
||||||
|
|
||||||
// TODO: temporary module for backwards compatibility
|
|
||||||
import type { DedupeOption, DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults'
|
|
||||||
|
|
||||||
export type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
|
export type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
|
||||||
|
|
||||||
@ -45,7 +42,7 @@ export interface AsyncDataOptions<
|
|||||||
ResT,
|
ResT,
|
||||||
DataT = ResT,
|
DataT = ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> {
|
> {
|
||||||
/**
|
/**
|
||||||
* Whether to fetch on the server side.
|
* Whether to fetch on the server side.
|
||||||
@ -107,7 +104,7 @@ export interface AsyncDataExecuteOptions {
|
|||||||
* Instead of using `boolean` values, use `cancel` for `true` and `defer` for `false`.
|
* Instead of using `boolean` values, use `cancel` for `true` and `defer` for `false`.
|
||||||
* Boolean values will be removed in a future release.
|
* Boolean values will be removed in a future release.
|
||||||
*/
|
*/
|
||||||
dedupe?: DedupeOption
|
dedupe?: 'cancel' | 'defer'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface _AsyncData<DataT, ErrorT> {
|
export interface _AsyncData<DataT, ErrorT> {
|
||||||
@ -119,7 +116,7 @@ export interface _AsyncData<DataT, ErrorT> {
|
|||||||
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
||||||
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
|
||||||
clear: () => void
|
clear: () => void
|
||||||
error: Ref<ErrorT | DefaultAsyncDataErrorValue>
|
error: Ref<ErrorT | undefined>
|
||||||
status: Ref<AsyncDataRequestStatus>
|
status: Ref<AsyncDataRequestStatus>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,11 +137,11 @@ export function useAsyncData<
|
|||||||
NuxtErrorDataT = unknown,
|
NuxtErrorDataT = unknown,
|
||||||
DataT = ResT,
|
DataT = ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (
|
> (
|
||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined>
|
||||||
/**
|
/**
|
||||||
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
||||||
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
||||||
@ -160,7 +157,7 @@ export function useAsyncData<
|
|||||||
> (
|
> (
|
||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined>
|
||||||
/**
|
/**
|
||||||
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
||||||
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
||||||
@ -173,12 +170,12 @@ export function useAsyncData<
|
|||||||
NuxtErrorDataT = unknown,
|
NuxtErrorDataT = unknown,
|
||||||
DataT = ResT,
|
DataT = ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (
|
> (
|
||||||
key: string,
|
key: string,
|
||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined>
|
||||||
/**
|
/**
|
||||||
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
* Provides access to data that resolves asynchronously in an SSR-friendly composable.
|
||||||
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
* See {@link https://nuxt.com/docs/api/composables/use-async-data}
|
||||||
@ -196,14 +193,14 @@ export function useAsyncData<
|
|||||||
key: string,
|
key: string,
|
||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
options?: AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined>
|
||||||
export function useAsyncData<
|
export function useAsyncData<
|
||||||
ResT,
|
ResT,
|
||||||
NuxtErrorDataT = unknown,
|
NuxtErrorDataT = unknown,
|
||||||
DataT = ResT,
|
DataT = ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys>, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | DefaultAsyncDataErrorValue> {
|
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys>, (NuxtErrorDataT extends Error | NuxtError ? NuxtErrorDataT : NuxtError<NuxtErrorDataT>) | undefined> {
|
||||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||||
|
|
||||||
@ -235,7 +232,7 @@ export function useAsyncData<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used to get default values
|
// Used to get default values
|
||||||
const getDefault = () => asyncDataDefaults.value
|
const getDefault = () => undefined
|
||||||
const getDefaultCachedData = () => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key]
|
const getDefaultCachedData = () => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key]
|
||||||
|
|
||||||
// Apply defaults
|
// Apply defaults
|
||||||
@ -257,7 +254,7 @@ export function useAsyncData<
|
|||||||
|
|
||||||
// Create or use a shared asyncData entity
|
// Create or use a shared asyncData entity
|
||||||
if (!nuxtApp._asyncData[key] || !options.immediate) {
|
if (!nuxtApp._asyncData[key] || !options.immediate) {
|
||||||
nuxtApp.payload._errors[key] ??= asyncDataDefaults.errorValue
|
nuxtApp.payload._errors[key] ??= undefined
|
||||||
|
|
||||||
const _ref = options.deep ? ref : shallowRef
|
const _ref = options.deep ? ref : shallowRef
|
||||||
|
|
||||||
@ -319,7 +316,7 @@ export function useAsyncData<
|
|||||||
nuxtApp.payload.data[key] = result
|
nuxtApp.payload.data[key] = result
|
||||||
|
|
||||||
asyncData.data.value = result
|
asyncData.data.value = result
|
||||||
asyncData.error.value = asyncDataDefaults.errorValue
|
asyncData.error.value = undefined
|
||||||
asyncData.status.value = 'success'
|
asyncData.status.value = 'success'
|
||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error: any) => {
|
||||||
@ -416,11 +413,11 @@ export function useLazyAsyncData<
|
|||||||
DataE = Error,
|
DataE = Error,
|
||||||
DataT = ResT,
|
DataT = ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (
|
> (
|
||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined>
|
||||||
export function useLazyAsyncData<
|
export function useLazyAsyncData<
|
||||||
ResT,
|
ResT,
|
||||||
DataE = Error,
|
DataE = Error,
|
||||||
@ -430,18 +427,18 @@ export function useLazyAsyncData<
|
|||||||
> (
|
> (
|
||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined>
|
||||||
export function useLazyAsyncData<
|
export function useLazyAsyncData<
|
||||||
ResT,
|
ResT,
|
||||||
DataE = Error,
|
DataE = Error,
|
||||||
DataT = ResT,
|
DataT = ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (
|
> (
|
||||||
key: string,
|
key: string,
|
||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined>
|
||||||
export function useLazyAsyncData<
|
export function useLazyAsyncData<
|
||||||
ResT,
|
ResT,
|
||||||
DataE = Error,
|
DataE = Error,
|
||||||
@ -452,15 +449,15 @@ export function useLazyAsyncData<
|
|||||||
key: string,
|
key: string,
|
||||||
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
handler: (ctx?: NuxtApp) => Promise<ResT>,
|
||||||
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
options?: Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'lazy'>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined>
|
||||||
|
|
||||||
export function useLazyAsyncData<
|
export function useLazyAsyncData<
|
||||||
ResT,
|
ResT,
|
||||||
DataE = Error,
|
DataE = Error,
|
||||||
DataT = ResT,
|
DataT = ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | DefaultAsyncDataValue> {
|
> (...args: any[]): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, DataE | undefined> {
|
||||||
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
const autoKey = typeof args[args.length - 1] === 'string' ? args.pop() : undefined
|
||||||
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
if (typeof args[0] !== 'string') { args.unshift(autoKey) }
|
||||||
const [key, handler, options = {}] = args as [string, (ctx?: NuxtApp) => Promise<ResT>, AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>]
|
const [key, handler, options = {}] = args as [string, (ctx?: NuxtApp) => Promise<ResT>, AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>]
|
||||||
@ -475,12 +472,12 @@ export function useLazyAsyncData<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @since 3.1.0 */
|
/** @since 3.1.0 */
|
||||||
export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | DefaultAsyncDataValue> } {
|
export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | undefined> } {
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
|
|
||||||
// Initialize value when key is not already set
|
// Initialize value when key is not already set
|
||||||
if (!(key in nuxtApp.payload.data)) {
|
if (!(key in nuxtApp.payload.data)) {
|
||||||
nuxtApp.payload.data[key] = asyncDataDefaults.value
|
nuxtApp.payload.data[key] = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -532,12 +529,12 @@ function clearNuxtDataByKey (nuxtApp: NuxtApp, key: string): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (key in nuxtApp.payload._errors) {
|
if (key in nuxtApp.payload._errors) {
|
||||||
nuxtApp.payload._errors[key] = asyncDataDefaults.errorValue
|
nuxtApp.payload._errors[key] = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nuxtApp._asyncData[key]) {
|
if (nuxtApp._asyncData[key]) {
|
||||||
nuxtApp._asyncData[key]!.data.value = resetAsyncDataToUndefined ? undefined : nuxtApp._asyncData[key]!._default()
|
nuxtApp._asyncData[key]!.data.value = nuxtApp._asyncData[key]!._default()
|
||||||
nuxtApp._asyncData[key]!.error.value = asyncDataDefaults.errorValue
|
nuxtApp._asyncData[key]!.error.value = undefined
|
||||||
nuxtApp._asyncData[key]!.pending.value = false
|
nuxtApp._asyncData[key]!.pending.value = false
|
||||||
nuxtApp._asyncData[key]!.status.value = 'idle'
|
nuxtApp._asyncData[key]!.status.value = 'idle'
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,6 @@ import { toRef } from 'vue'
|
|||||||
import { useNuxtApp } from '../nuxt'
|
import { useNuxtApp } from '../nuxt'
|
||||||
import { useRouter } from './router'
|
import { useRouter } from './router'
|
||||||
|
|
||||||
// @ts-expect-error virtual file
|
|
||||||
import { nuxtDefaultErrorValue } from '#build/nuxt.config.mjs'
|
|
||||||
|
|
||||||
export const NUXT_ERROR_SIGNATURE = '__nuxt_error'
|
export const NUXT_ERROR_SIGNATURE = '__nuxt_error'
|
||||||
|
|
||||||
/** @since 3.0.0 */
|
/** @since 3.0.0 */
|
||||||
@ -50,7 +47,7 @@ export const clearError = async (options: { redirect?: string } = {}) => {
|
|||||||
await useRouter().replace(options.redirect)
|
await useRouter().replace(options.redirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
error.value = nuxtDefaultErrorValue
|
error.value = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @since 3.0.0 */
|
/** @since 3.0.0 */
|
||||||
|
@ -8,9 +8,6 @@ import { useRequestFetch } from './ssr'
|
|||||||
import type { AsyncData, AsyncDataOptions, KeysOf, MultiWatchSources, PickFrom } from './asyncData'
|
import type { AsyncData, AsyncDataOptions, KeysOf, MultiWatchSources, PickFrom } from './asyncData'
|
||||||
import { useAsyncData } from './asyncData'
|
import { useAsyncData } from './asyncData'
|
||||||
|
|
||||||
// TODO: temporary module for backwards compatibility
|
|
||||||
import type { DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults'
|
|
||||||
|
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { fetchDefaults } from '#build/nuxt.config.mjs'
|
import { fetchDefaults } from '#build/nuxt.config.mjs'
|
||||||
|
|
||||||
@ -33,7 +30,7 @@ export interface UseFetchOptions<
|
|||||||
ResT,
|
ResT,
|
||||||
DataT = ResT,
|
DataT = ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
R extends NitroFetchRequest = string & {},
|
R extends NitroFetchRequest = string & {},
|
||||||
M extends AvailableRouterMethod<R> = AvailableRouterMethod<R>,
|
M extends AvailableRouterMethod<R> = AvailableRouterMethod<R>,
|
||||||
> extends Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'watch'>, ComputedFetchOptions<R, M> {
|
> extends Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'watch'>, ComputedFetchOptions<R, M> {
|
||||||
@ -57,11 +54,11 @@ export function useFetch<
|
|||||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||||
DataT = _ResT,
|
DataT = _ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (
|
> (
|
||||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||||
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
||||||
/**
|
/**
|
||||||
* Fetch data from an API endpoint with an SSR-friendly composable.
|
* Fetch data from an API endpoint with an SSR-friendly composable.
|
||||||
* See {@link https://nuxt.com/docs/api/composables/use-fetch}
|
* See {@link https://nuxt.com/docs/api/composables/use-fetch}
|
||||||
@ -80,7 +77,7 @@ export function useFetch<
|
|||||||
> (
|
> (
|
||||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||||
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
opts?: UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
||||||
export function useFetch<
|
export function useFetch<
|
||||||
ResT = void,
|
ResT = void,
|
||||||
ErrorT = FetchError,
|
ErrorT = FetchError,
|
||||||
@ -89,7 +86,7 @@ export function useFetch<
|
|||||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||||
DataT = _ResT,
|
DataT = _ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (
|
> (
|
||||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||||
arg1?: string | UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>,
|
arg1?: string | UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>,
|
||||||
@ -195,11 +192,11 @@ export function useLazyFetch<
|
|||||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||||
DataT = _ResT,
|
DataT = _ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (
|
> (
|
||||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||||
opts?: Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>
|
opts?: Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
||||||
export function useLazyFetch<
|
export function useLazyFetch<
|
||||||
ResT = void,
|
ResT = void,
|
||||||
ErrorT = FetchError,
|
ErrorT = FetchError,
|
||||||
@ -212,7 +209,7 @@ export function useLazyFetch<
|
|||||||
> (
|
> (
|
||||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||||
opts?: Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>
|
opts?: Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>
|
||||||
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | DefaultAsyncDataErrorValue>
|
): AsyncData<PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
||||||
export function useLazyFetch<
|
export function useLazyFetch<
|
||||||
ResT = void,
|
ResT = void,
|
||||||
ErrorT = FetchError,
|
ErrorT = FetchError,
|
||||||
@ -221,7 +218,7 @@ export function useLazyFetch<
|
|||||||
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
_ResT = ResT extends void ? FetchResult<ReqT, Method> : ResT,
|
||||||
DataT = _ResT,
|
DataT = _ResT,
|
||||||
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
|
||||||
DefaultT = DefaultAsyncDataValue,
|
DefaultT = undefined,
|
||||||
> (
|
> (
|
||||||
request: Ref<ReqT> | ReqT | (() => ReqT),
|
request: Ref<ReqT> | ReqT | (() => ReqT),
|
||||||
arg1?: string | Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>,
|
arg1?: string | Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { getCurrentInstance, hasInjectionContext, inject, onScopeDispose } from 'vue'
|
import { getCurrentInstance, hasInjectionContext, inject, onScopeDispose } from 'vue'
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
import type { NavigationFailure, NavigationGuard, RouteLocationNormalized, RouteLocationPathRaw, RouteLocationRaw, Router, useRoute as _useRoute, useRouter as _useRouter } from '#vue-router'
|
import type { NavigationFailure, NavigationGuard, RouteLocationNormalized, RouteLocationRaw, Router, useRoute as _useRoute, useRouter as _useRouter } from '#vue-router'
|
||||||
import { sanitizeStatusCode } from 'h3'
|
import { sanitizeStatusCode } from 'h3'
|
||||||
import { hasProtocol, isScriptProtocol, joinURL, withQuery } from 'ufo'
|
import { hasProtocol, isScriptProtocol, joinURL, withQuery } from 'ufo'
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ export const navigateTo = (to: RouteLocationRaw | undefined | null, options?: Na
|
|||||||
to = '/'
|
to = '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
const toPath = typeof to === 'string' ? to : (withQuery((to as RouteLocationPathRaw).path || '/', to.query || {}) + (to.hash || ''))
|
const toPath = typeof to === 'string' ? to : 'path' in to ? resolveRouteObject(to) : useRouter().resolve(to).href
|
||||||
|
|
||||||
// Early open handler
|
// Early open handler
|
||||||
if (import.meta.client && options?.open) {
|
if (import.meta.client && options?.open) {
|
||||||
@ -252,3 +252,10 @@ export const setPageLayout = (layout: unknown extends PageMeta['layout'] ? strin
|
|||||||
useRoute().meta.layout = layout as Exclude<PageMeta['layout'], Ref | false>
|
useRoute().meta.layout = layout as Exclude<PageMeta['layout'], Ref | false>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function resolveRouteObject (to: Exclude<RouteLocationRaw, string>) {
|
||||||
|
return withQuery(to.path || '', to.query || {}) + (to.hash || '')
|
||||||
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
// TODO: temporary module for backwards compatibility
|
|
||||||
|
|
||||||
export type DefaultAsyncDataErrorValue = null
|
|
||||||
export type DefaultAsyncDataValue = null
|
|
||||||
export type DefaultErrorValue = null
|
|
||||||
export type DedupeOption = boolean | 'cancel' | 'defer'
|
|
||||||
|
|
||||||
export {}
|
|
@ -23,8 +23,6 @@ import type { ViewTransition } from './plugins/view-transitions.client'
|
|||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { appId } from '#build/nuxt.config.mjs'
|
import { appId } from '#build/nuxt.config.mjs'
|
||||||
|
|
||||||
// TODO: temporary module for backwards compatibility
|
|
||||||
import type { DefaultAsyncDataErrorValue, DefaultErrorValue } from '#app/defaults'
|
|
||||||
import type { NuxtAppLiterals } from '#app'
|
import type { NuxtAppLiterals } from '#app'
|
||||||
|
|
||||||
function getNuxtAppCtx (appName = appId || 'nuxt-app') {
|
function getNuxtAppCtx (appName = appId || 'nuxt-app') {
|
||||||
@ -94,8 +92,8 @@ export interface NuxtPayload {
|
|||||||
state: Record<string, any>
|
state: Record<string, any>
|
||||||
once: Set<string>
|
once: Set<string>
|
||||||
config?: Pick<RuntimeConfig, 'public' | 'app'>
|
config?: Pick<RuntimeConfig, 'public' | 'app'>
|
||||||
error?: NuxtError | DefaultErrorValue
|
error?: NuxtError | undefined
|
||||||
_errors: Record<string, NuxtError | DefaultAsyncDataErrorValue>
|
_errors: Record<string, NuxtError | undefined>
|
||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +122,7 @@ interface _NuxtApp {
|
|||||||
_asyncData: Record<string, {
|
_asyncData: Record<string, {
|
||||||
data: Ref<unknown>
|
data: Ref<unknown>
|
||||||
pending: Ref<boolean>
|
pending: Ref<boolean>
|
||||||
error: Ref<Error | DefaultAsyncDataErrorValue>
|
error: Ref<Error | undefined>
|
||||||
status: Ref<AsyncDataRequestStatus>
|
status: Ref<AsyncDataRequestStatus>
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_default: () => unknown
|
_default: () => unknown
|
||||||
|
23
packages/nuxt/src/app/plugins/navigation-repaint.client.ts
Normal file
23
packages/nuxt/src/app/plugins/navigation-repaint.client.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { defineNuxtPlugin } from '../nuxt'
|
||||||
|
import { onNuxtReady } from '../composables/ready'
|
||||||
|
import { useRouter } from '../composables/router'
|
||||||
|
|
||||||
|
export default defineNuxtPlugin(() => {
|
||||||
|
const router = useRouter()
|
||||||
|
onNuxtReady(() => {
|
||||||
|
router.beforeResolve(async () => {
|
||||||
|
/**
|
||||||
|
* This gives an opportunity for the browser to repaint, acknowledging user interaction.
|
||||||
|
* It can reduce INP when navigating on prerendered routes.
|
||||||
|
*
|
||||||
|
* @see https://github.com/nuxt/nuxt/issues/26271#issuecomment-2178582037
|
||||||
|
* @see https://vercel.com/blog/demystifying-inp-new-tools-and-actionable-insights
|
||||||
|
*/
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
// Ensure we always resolve, even if the animation frame never fires
|
||||||
|
setTimeout(resolve, 100)
|
||||||
|
requestAnimationFrame(() => { setTimeout(resolve, 0) })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -216,7 +216,7 @@ export default defineNuxtModule<ComponentsOptions>({
|
|||||||
const mode = isClient ? 'client' : 'server'
|
const mode = isClient ? 'client' : 'server'
|
||||||
|
|
||||||
config.plugins = config.plugins || []
|
config.plugins = config.plugins || []
|
||||||
if (nuxt.options.experimental.treeshakeClientOnly && isServer) {
|
if (isServer) {
|
||||||
config.plugins.push(TreeShakeTemplatePlugin.vite({
|
config.plugins.push(TreeShakeTemplatePlugin.vite({
|
||||||
sourcemap: !!nuxt.options.sourcemap[mode],
|
sourcemap: !!nuxt.options.sourcemap[mode],
|
||||||
getComponents,
|
getComponents,
|
||||||
@ -285,7 +285,7 @@ export default defineNuxtModule<ComponentsOptions>({
|
|||||||
configs.forEach((config) => {
|
configs.forEach((config) => {
|
||||||
const mode = config.name === 'client' ? 'client' : 'server'
|
const mode = config.name === 'client' ? 'client' : 'server'
|
||||||
config.plugins = config.plugins || []
|
config.plugins = config.plugins || []
|
||||||
if (nuxt.options.experimental.treeshakeClientOnly && mode === 'server') {
|
if (mode === 'server') {
|
||||||
config.plugins.push(TreeShakeTemplatePlugin.webpack({
|
config.plugins.push(TreeShakeTemplatePlugin.webpack({
|
||||||
sourcemap: !!nuxt.options.sourcemap[mode],
|
sourcemap: !!nuxt.options.sourcemap[mode],
|
||||||
getComponents,
|
getComponents,
|
||||||
|
@ -86,8 +86,7 @@ function createWatcher () {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: consider moving to emit absolute path in 3.8 or 4.0
|
watcher.on('all', (event, path) => nuxt.callHook('builder:watch', event, normalize(path)))
|
||||||
watcher.on('all', (event, path) => nuxt.callHook('builder:watch', event, nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, path)) : normalize(path)))
|
|
||||||
nuxt.hook('close', () => watcher?.close())
|
nuxt.hook('close', () => watcher?.close())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,8 +116,7 @@ function createGranularWatcher () {
|
|||||||
watcher.on('all', (event, path) => {
|
watcher.on('all', (event, path) => {
|
||||||
path = normalize(path)
|
path = normalize(path)
|
||||||
if (!pending) {
|
if (!pending) {
|
||||||
// TODO: consider moving to emit absolute path in 3.8 or 4.0
|
nuxt.callHook('builder:watch', event, path)
|
||||||
nuxt.callHook('builder:watch', event, nuxt.options.experimental.relativeWatchPaths ? relative(nuxt.options.srcDir, path) : path)
|
|
||||||
}
|
}
|
||||||
if (event === 'unlinkDir' && path in watchers) {
|
if (event === 'unlinkDir' && path in watchers) {
|
||||||
watchers[path]?.close()
|
watchers[path]?.close()
|
||||||
@ -126,8 +124,7 @@ function createGranularWatcher () {
|
|||||||
}
|
}
|
||||||
if (event === 'addDir' && path !== dir && !ignoredDirs.has(path) && !pathsToWatch.includes(path) && !(path in watchers) && !isIgnored(path)) {
|
if (event === 'addDir' && path !== dir && !ignoredDirs.has(path) && !pathsToWatch.includes(path) && !(path in watchers) && !isIgnored(path)) {
|
||||||
watchers[path] = chokidar.watch(path, { ...nuxt.options.watchers.chokidar, ignored: [isIgnored] })
|
watchers[path] = chokidar.watch(path, { ...nuxt.options.watchers.chokidar, ignored: [isIgnored] })
|
||||||
// TODO: consider moving to emit absolute path in 3.8 or 4.0
|
watchers[path].on('all', (event, p) => nuxt.callHook('builder:watch', event, normalize(p)))
|
||||||
watchers[path].on('all', (event, p) => nuxt.callHook('builder:watch', event, nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, p)) : normalize(p)))
|
|
||||||
nuxt.hook('close', () => watchers[path]?.close())
|
nuxt.hook('close', () => watchers[path]?.close())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -161,8 +158,7 @@ async function createParcelWatcher () {
|
|||||||
if (err) { return }
|
if (err) { return }
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
if (isIgnored(event.path)) { continue }
|
if (isIgnored(event.path)) { continue }
|
||||||
// TODO: consider moving to emit absolute path in 3.8 or 4.0
|
nuxt.callHook('builder:watch', watchEvents[event.type], normalize(event.path))
|
||||||
nuxt.callHook('builder:watch', watchEvents[event.type], nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, event.path)) : normalize(event.path))
|
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
ignore: [
|
ignore: [
|
||||||
|
@ -6,7 +6,7 @@ import { createRouter as createRadixRouter, exportMatcher, toRouteMatcher } from
|
|||||||
import { joinURL, withTrailingSlash } from 'ufo'
|
import { joinURL, withTrailingSlash } from 'ufo'
|
||||||
import { build, copyPublicAssets, createDevServer, createNitro, prepare, prerender, scanHandlers, writeTypes } from 'nitropack'
|
import { build, copyPublicAssets, createDevServer, createNitro, prepare, prerender, scanHandlers, writeTypes } from 'nitropack'
|
||||||
import type { Nitro, NitroConfig, NitroOptions } from 'nitropack'
|
import type { Nitro, NitroConfig, NitroOptions } from 'nitropack'
|
||||||
import { findPath, logger, resolveIgnorePatterns, resolveNuxtModule, resolvePath } from '@nuxt/kit'
|
import { findPath, logger, resolveAlias, resolveIgnorePatterns, resolveNuxtModule, resolvePath } from '@nuxt/kit'
|
||||||
import escapeRE from 'escape-string-regexp'
|
import escapeRE from 'escape-string-regexp'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
import fsExtra from 'fs-extra'
|
import fsExtra from 'fs-extra'
|
||||||
@ -218,6 +218,9 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
nitroConfig.srcDir = resolve(nuxt.options.rootDir, nuxt.options.srcDir, nitroConfig.srcDir!)
|
nitroConfig.srcDir = resolve(nuxt.options.rootDir, nuxt.options.srcDir, nitroConfig.srcDir!)
|
||||||
nitroConfig.ignore = [...(nitroConfig.ignore || []), ...resolveIgnorePatterns(nitroConfig.srcDir), `!${join(nuxt.options.buildDir, 'dist/client', nuxt.options.app.buildAssetsDir, '**/*')}`]
|
nitroConfig.ignore = [...(nitroConfig.ignore || []), ...resolveIgnorePatterns(nitroConfig.srcDir), `!${join(nuxt.options.buildDir, 'dist/client', nuxt.options.app.buildAssetsDir, '**/*')}`]
|
||||||
|
|
||||||
|
// Resolve aliases in user-provided input - so `~/server/test` will work
|
||||||
|
nitroConfig.plugins = nitroConfig.plugins?.map(plugin => plugin ? resolveAlias(plugin, nuxt.options.alias) : plugin)
|
||||||
|
|
||||||
// Add app manifest handler and prerender configuration
|
// Add app manifest handler and prerender configuration
|
||||||
if (nuxt.options.experimental.appManifest) {
|
if (nuxt.options.experimental.appManifest) {
|
||||||
const buildId = nuxt.options.runtimeConfig.app.buildId ||= nuxt.options.buildId
|
const buildId = nuxt.options.runtimeConfig.app.buildId ||= nuxt.options.buildId
|
||||||
@ -340,15 +343,6 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add backward-compatible middleware to respect `x-nuxt-no-ssr` header
|
|
||||||
if (nuxt.options.experimental.respectNoSSRHeader) {
|
|
||||||
nitroConfig.handlers = nitroConfig.handlers || []
|
|
||||||
nitroConfig.handlers.push({
|
|
||||||
handler: resolve(distDir, 'core/runtime/nitro/no-ssr'),
|
|
||||||
middleware: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register nuxt protection patterns
|
// Register nuxt protection patterns
|
||||||
nitroConfig.rollupConfig!.plugins = await nitroConfig.rollupConfig!.plugins || []
|
nitroConfig.rollupConfig!.plugins = await nitroConfig.rollupConfig!.plugins || []
|
||||||
nitroConfig.rollupConfig!.plugins = toArray(nitroConfig.rollupConfig!.plugins)
|
nitroConfig.rollupConfig!.plugins = toArray(nitroConfig.rollupConfig!.plugins)
|
||||||
|
@ -99,21 +99,37 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
const packageJSON = await readPackageJSON(nuxt.options.rootDir).catch(() => ({}) as PackageJson)
|
const packageJSON = await readPackageJSON(nuxt.options.rootDir).catch(() => ({}) as PackageJson)
|
||||||
const dependencies = new Set([...Object.keys(packageJSON.dependencies || {}), ...Object.keys(packageJSON.devDependencies || {})])
|
const dependencies = new Set([...Object.keys(packageJSON.dependencies || {}), ...Object.keys(packageJSON.devDependencies || {})])
|
||||||
const paths = Object.fromEntries(await Promise.all(coreTypePackages.map(async (pkg) => {
|
const paths = Object.fromEntries(await Promise.all(coreTypePackages.map(async (pkg) => {
|
||||||
// ignore packages that exist in `package.json` as these can be resolved by TypeScript
|
const [_pkg = pkg, _subpath] = /^[^@]+\//.test(pkg) ? pkg.split('/') : [pkg]
|
||||||
if (dependencies.has(pkg) && !(pkg in nightlies)) { return [] }
|
const subpath = _subpath ? '/' + _subpath : ''
|
||||||
|
|
||||||
// deduplicate types for nightly releases
|
// ignore packages that exist in `package.json` as these can be resolved by TypeScript
|
||||||
if (pkg in nightlies) {
|
if (dependencies.has(_pkg) && !(_pkg in nightlies)) { return [] }
|
||||||
const nightly = nightlies[pkg as keyof typeof nightlies]
|
|
||||||
const path = await _resolvePath(nightly, { url: nuxt.options.modulesDir }).then(r => resolvePackageJSON(r)).catch(() => null)
|
async function resolveTypePath (path: string) {
|
||||||
if (path) {
|
try {
|
||||||
return [[pkg, [dirname(path)]], [nightly, [dirname(path)]]]
|
const r = await _resolvePath(path, { url: nuxt.options.modulesDir, conditions: ['types', 'import', 'require'] })
|
||||||
|
if (subpath) {
|
||||||
|
return r.replace(/(?:\.d)?\.[mc]?[jt]s$/, '')
|
||||||
|
}
|
||||||
|
const rootPath = await resolvePackageJSON(r)
|
||||||
|
return dirname(rootPath)
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = await _resolvePath(pkg, { url: nuxt.options.modulesDir }).then(r => resolvePackageJSON(r)).catch(() => null)
|
// deduplicate types for nightly releases
|
||||||
|
if (_pkg in nightlies) {
|
||||||
|
const nightly = nightlies[_pkg as keyof typeof nightlies]
|
||||||
|
const path = await resolveTypePath(nightly + subpath)
|
||||||
|
if (path) {
|
||||||
|
return [[pkg, [path]], [nightly + subpath, [path]]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = await resolveTypePath(_pkg + subpath)
|
||||||
if (path) {
|
if (path) {
|
||||||
return [[pkg, [dirname(path)]]]
|
return [[pkg, [path]]]
|
||||||
}
|
}
|
||||||
|
|
||||||
return []
|
return []
|
||||||
@ -127,7 +143,6 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
// Add nuxt types
|
// Add nuxt types
|
||||||
nuxt.hook('prepare:types', (opts) => {
|
nuxt.hook('prepare:types', (opts) => {
|
||||||
opts.references.push({ types: 'nuxt' })
|
opts.references.push({ types: 'nuxt' })
|
||||||
opts.references.push({ path: resolve(nuxt.options.buildDir, 'types/app-defaults.d.ts') })
|
|
||||||
opts.references.push({ path: resolve(nuxt.options.buildDir, 'types/plugins.d.ts') })
|
opts.references.push({ path: resolve(nuxt.options.buildDir, 'types/plugins.d.ts') })
|
||||||
// Add vue shim
|
// Add vue shim
|
||||||
if (nuxt.options.typescript.shim) {
|
if (nuxt.options.typescript.shim) {
|
||||||
@ -517,6 +532,12 @@ async function initNuxt (nuxt: Nuxt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nuxt.options.experimental.navigationRepaint) {
|
||||||
|
addPlugin({
|
||||||
|
src: resolve(nuxt.options.appDir, 'plugins/navigation-repaint.client'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -20,9 +20,6 @@ export default defineNuxtModule({
|
|||||||
name: 'nuxt-config-schema',
|
name: 'nuxt-config-schema',
|
||||||
},
|
},
|
||||||
async setup (_, nuxt) {
|
async setup (_, nuxt) {
|
||||||
if (!nuxt.options.experimental.configSchema) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const resolver = createResolver(import.meta.url)
|
const resolver = createResolver(import.meta.url)
|
||||||
|
|
||||||
// Initialize untyped/jiti loader
|
// Initialize untyped/jiti loader
|
||||||
|
@ -7,7 +7,7 @@ import escapeRE from 'escape-string-regexp'
|
|||||||
import { hash } from 'ohash'
|
import { hash } from 'ohash'
|
||||||
import { camelCase } from 'scule'
|
import { camelCase } from 'scule'
|
||||||
import { filename } from 'pathe/utils'
|
import { filename } from 'pathe/utils'
|
||||||
import type { NuxtTemplate, NuxtTypeTemplate } from 'nuxt/schema'
|
import type { NuxtTemplate } from 'nuxt/schema'
|
||||||
|
|
||||||
import { annotatePlugins, checkForCircularDependencies } from './app'
|
import { annotatePlugins, checkForCircularDependencies } from './app'
|
||||||
|
|
||||||
@ -96,20 +96,6 @@ export const serverPluginTemplate: NuxtTemplate = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const appDefaults: NuxtTypeTemplate = {
|
|
||||||
filename: 'types/app-defaults.d.ts',
|
|
||||||
getContents: (ctx) => {
|
|
||||||
const isV4 = ctx.nuxt.options.future.compatibilityVersion === 4
|
|
||||||
return `
|
|
||||||
declare module '#app/defaults' {
|
|
||||||
type DefaultAsyncDataErrorValue = ${isV4 ? 'undefined' : 'null'}
|
|
||||||
type DefaultAsyncDataValue = ${isV4 ? 'undefined' : 'null'}
|
|
||||||
type DefaultErrorValue = ${isV4 ? 'undefined' : 'null'}
|
|
||||||
type DedupeOption = ${isV4 ? '\'cancel\' | \'defer\'' : 'boolean | \'cancel\' | \'defer\''}
|
|
||||||
}`
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const pluginsDeclaration: NuxtTemplate = {
|
export const pluginsDeclaration: NuxtTemplate = {
|
||||||
filename: 'types/plugins.d.ts',
|
filename: 'types/plugins.d.ts',
|
||||||
getContents: async (ctx) => {
|
getContents: async (ctx) => {
|
||||||
@ -418,13 +404,7 @@ export const nuxtConfigTemplate: NuxtTemplate = {
|
|||||||
`export const devRootDir = ${ctx.nuxt.options.dev ? JSON.stringify(ctx.nuxt.options.rootDir) : 'null'}`,
|
`export const devRootDir = ${ctx.nuxt.options.dev ? JSON.stringify(ctx.nuxt.options.rootDir) : 'null'}`,
|
||||||
`export const devLogs = ${JSON.stringify(ctx.nuxt.options.features.devLogs)}`,
|
`export const devLogs = ${JSON.stringify(ctx.nuxt.options.features.devLogs)}`,
|
||||||
`export const nuxtLinkDefaults = ${JSON.stringify(ctx.nuxt.options.experimental.defaults.nuxtLink)}`,
|
`export const nuxtLinkDefaults = ${JSON.stringify(ctx.nuxt.options.experimental.defaults.nuxtLink)}`,
|
||||||
`export const asyncDataDefaults = ${JSON.stringify({
|
`export const asyncDataDefaults = ${JSON.stringify(ctx.nuxt.options.experimental.defaults.useAsyncData)}`,
|
||||||
...ctx.nuxt.options.experimental.defaults.useAsyncData,
|
|
||||||
value: ctx.nuxt.options.experimental.defaults.useAsyncData.value === 'null' ? null : undefined,
|
|
||||||
errorValue: ctx.nuxt.options.experimental.defaults.useAsyncData.errorValue === 'null' ? null : undefined,
|
|
||||||
})}`,
|
|
||||||
`export const resetAsyncDataToUndefined = ${ctx.nuxt.options.experimental.resetAsyncDataToUndefined}`,
|
|
||||||
`export const nuxtDefaultErrorValue = ${ctx.nuxt.options.future.compatibilityVersion === 4 ? 'undefined' : 'null'}`,
|
|
||||||
`export const fetchDefaults = ${JSON.stringify(fetchDefaults)}`,
|
`export const fetchDefaults = ${JSON.stringify(fetchDefaults)}`,
|
||||||
`export const vueAppRootContainer = ${ctx.nuxt.options.app.rootAttrs.id ? `'#${ctx.nuxt.options.app.rootAttrs.id}'` : `'body > ${ctx.nuxt.options.app.rootTag}'`}`,
|
`export const vueAppRootContainer = ${ctx.nuxt.options.app.rootAttrs.id ? `'#${ctx.nuxt.options.app.rootAttrs.id}'` : `'body > ${ctx.nuxt.options.app.rootTag}'`}`,
|
||||||
`export const viewTransition = ${ctx.nuxt.options.experimental.viewTransition}`,
|
`export const viewTransition = ${ctx.nuxt.options.experimental.viewTransition}`,
|
||||||
|
@ -52,11 +52,6 @@ export default defineNuxtModule<NuxtOptions['unhead']>({
|
|||||||
|
|
||||||
// Opt-out feature allowing dependencies using @vueuse/head to work
|
// Opt-out feature allowing dependencies using @vueuse/head to work
|
||||||
const unheadVue = await tryResolveModule('@unhead/vue', nuxt.options.modulesDir) || '@unhead/vue'
|
const unheadVue = await tryResolveModule('@unhead/vue', nuxt.options.modulesDir) || '@unhead/vue'
|
||||||
if (nuxt.options.experimental.polyfillVueUseHead) {
|
|
||||||
// backwards compatibility
|
|
||||||
nuxt.options.alias['@vueuse/head'] = unheadVue
|
|
||||||
addPlugin({ src: resolve(runtimeDir, 'plugins/vueuse-head-polyfill') })
|
|
||||||
}
|
|
||||||
|
|
||||||
addTemplate({
|
addTemplate({
|
||||||
filename: 'unhead-plugins.mjs',
|
filename: 'unhead-plugins.mjs',
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
import { polyfillAsVueUseHead } from '@unhead/vue/polyfill'
|
|
||||||
import { defineNuxtPlugin } from '#app/nuxt'
|
|
||||||
|
|
||||||
export default defineNuxtPlugin({
|
|
||||||
name: 'nuxt:vueuse-head-polyfill',
|
|
||||||
setup (nuxtApp) {
|
|
||||||
// avoid breaking ecosystem dependencies using low-level @vueuse/head APIs
|
|
||||||
polyfillAsVueUseHead(nuxtApp.vueApp._context.provides.usehead)
|
|
||||||
},
|
|
||||||
})
|
|
6
packages/nuxt/src/pages/build.d.ts
vendored
Normal file
6
packages/nuxt/src/pages/build.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
declare module '#build/router.options' {
|
||||||
|
import type { RouterOptions } from '@nuxt/schema'
|
||||||
|
|
||||||
|
const _default: RouterOptions
|
||||||
|
export default _default
|
||||||
|
}
|
@ -5,7 +5,6 @@ import { defineNuxtPlugin } from '#app/nuxt'
|
|||||||
import { prerenderRoutes } from '#app/composables/ssr'
|
import { prerenderRoutes } from '#app/composables/ssr'
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import _routes from '#build/routes'
|
import _routes from '#build/routes'
|
||||||
// @ts-expect-error virtual file
|
|
||||||
import routerOptions from '#build/router.options'
|
import routerOptions from '#build/router.options'
|
||||||
|
|
||||||
let routes: string[]
|
let routes: string[]
|
||||||
|
@ -24,7 +24,6 @@ import { navigateTo } from '#app/composables/router'
|
|||||||
import { appManifest as isAppManifestEnabled } from '#build/nuxt.config.mjs'
|
import { appManifest as isAppManifestEnabled } from '#build/nuxt.config.mjs'
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import _routes from '#build/routes'
|
import _routes from '#build/routes'
|
||||||
// @ts-expect-error virtual file
|
|
||||||
import routerOptions from '#build/router.options'
|
import routerOptions from '#build/router.options'
|
||||||
// @ts-expect-error virtual file
|
// @ts-expect-error virtual file
|
||||||
import { globalMiddleware, namedMiddleware } from '#build/middleware'
|
import { globalMiddleware, namedMiddleware } from '#build/middleware'
|
||||||
@ -67,7 +66,7 @@ const plugin: Plugin<{ router: Router }> = defineNuxtPlugin({
|
|||||||
: createMemoryHistory(routerBase)
|
: createMemoryHistory(routerBase)
|
||||||
)
|
)
|
||||||
|
|
||||||
const routes = routerOptions.routes?.(_routes) ?? _routes
|
const routes = routerOptions.routes ? await routerOptions.routes(_routes) ?? _routes : _routes
|
||||||
|
|
||||||
let startPosition: Parameters<RouterScrollBehavior>[2] | null
|
let startPosition: Parameters<RouterScrollBehavior>[2] | null
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ describe('resolveApp', () => {
|
|||||||
{
|
{
|
||||||
"components": [],
|
"components": [],
|
||||||
"configs": [],
|
"configs": [],
|
||||||
"dir": "<rootDir>",
|
"dir": "<rootDir>/app",
|
||||||
"errorComponent": "<repoRoot>/packages/nuxt/src/app/components/nuxt-error-page.vue",
|
"errorComponent": "<repoRoot>/packages/nuxt/src/app/components/nuxt-error-page.vue",
|
||||||
"extensions": [
|
"extensions": [
|
||||||
".js",
|
".js",
|
||||||
@ -43,6 +43,10 @@ describe('resolveApp', () => {
|
|||||||
"mode": "client",
|
"mode": "client",
|
||||||
"src": "<repoRoot>/packages/nuxt/src/app/plugins/payload.client.ts",
|
"src": "<repoRoot>/packages/nuxt/src/app/plugins/payload.client.ts",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"mode": "client",
|
||||||
|
"src": "<repoRoot>/packages/nuxt/src/app/plugins/navigation-repaint.client.ts",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"mode": "client",
|
"mode": "client",
|
||||||
"src": "<repoRoot>/packages/nuxt/src/app/plugins/check-outdated-build.client.ts",
|
"src": "<repoRoot>/packages/nuxt/src/app/plugins/check-outdated-build.client.ts",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
import type { RouteLocation } from 'vue-router'
|
import type { RouteLocation, RouteLocationRaw } from 'vue-router'
|
||||||
|
import { withQuery } from 'ufo'
|
||||||
import type { NuxtLinkOptions, NuxtLinkProps } from '../src/app/components/nuxt-link'
|
import type { NuxtLinkOptions, NuxtLinkProps } from '../src/app/components/nuxt-link'
|
||||||
import { defineNuxtLink } from '../src/app/components/nuxt-link'
|
import { defineNuxtLink } from '../src/app/components/nuxt-link'
|
||||||
import { useRuntimeConfig } from '../src/app/nuxt'
|
import { useRuntimeConfig } from '../src/app/nuxt'
|
||||||
@ -25,6 +26,9 @@ vi.mock('vue', async () => {
|
|||||||
|
|
||||||
// Mocks Nuxt `useRouter()`
|
// Mocks Nuxt `useRouter()`
|
||||||
vi.mock('../src/app/composables/router', () => ({
|
vi.mock('../src/app/composables/router', () => ({
|
||||||
|
resolveRouteObject (to: Exclude<RouteLocationRaw, string>) {
|
||||||
|
return withQuery(to.path || '', to.query || {}) + (to.hash || '')
|
||||||
|
},
|
||||||
useRouter: () => ({
|
useRouter: () => ({
|
||||||
resolve: (route: string | RouteLocation & { to?: string }): Partial<RouteLocation> & { href?: string } => {
|
resolve: (route: string | RouteLocation & { to?: string }): Partial<RouteLocation> & { href?: string } => {
|
||||||
if (typeof route === 'string') {
|
if (typeof route === 'string') {
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
"@types/file-loader": "5.0.4",
|
"@types/file-loader": "5.0.4",
|
||||||
"@types/pug": "2.0.10",
|
"@types/pug": "2.0.10",
|
||||||
"@types/sass-loader": "8.0.8",
|
"@types/sass-loader": "8.0.8",
|
||||||
"@unhead/schema": "1.9.13",
|
"@unhead/schema": "1.9.14",
|
||||||
"@vitejs/plugin-vue": "5.0.4",
|
"@vitejs/plugin-vue": "5.0.4",
|
||||||
"@vitejs/plugin-vue-jsx": "4.0.0",
|
"@vitejs/plugin-vue-jsx": "4.0.0",
|
||||||
"@vue/compiler-core": "3.4.29",
|
"@vue/compiler-core": "3.4.29",
|
||||||
@ -47,7 +47,7 @@
|
|||||||
"@vue/language-core": "2.0.21",
|
"@vue/language-core": "2.0.21",
|
||||||
"c12": "1.11.1",
|
"c12": "1.11.1",
|
||||||
"esbuild-loader": "4.2.0",
|
"esbuild-loader": "4.2.0",
|
||||||
"h3": "1.11.1",
|
"h3": "1.12.0",
|
||||||
"ignore": "5.3.1",
|
"ignore": "5.3.1",
|
||||||
"nitropack": "2.9.6",
|
"nitropack": "2.9.6",
|
||||||
"ofetch": "1.3.4",
|
"ofetch": "1.3.4",
|
||||||
@ -59,7 +59,7 @@
|
|||||||
"vue-bundle-renderer": "2.1.0",
|
"vue-bundle-renderer": "2.1.0",
|
||||||
"vue-loader": "17.4.2",
|
"vue-loader": "17.4.2",
|
||||||
"vue-router": "4.3.3",
|
"vue-router": "4.3.3",
|
||||||
"webpack": "5.92.0",
|
"webpack": "5.92.1",
|
||||||
"webpack-dev-middleware": "7.2.1"
|
"webpack-dev-middleware": "7.2.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { existsSync } from 'node:fs'
|
import { existsSync } from 'node:fs'
|
||||||
import { readdir } from 'node:fs/promises'
|
import { readdir } from 'node:fs/promises'
|
||||||
import { defineUntypedSchema } from 'untyped'
|
import { defineUntypedSchema } from 'untyped'
|
||||||
import { join, relative, resolve } from 'pathe'
|
import { basename, join, relative, resolve } from 'pathe'
|
||||||
import { isDebug, isDevelopment, isTest } from 'std-env'
|
import { isDebug, isDevelopment, isTest } from 'std-env'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
import { findWorkspaceDir } from 'pkg-types'
|
import { findWorkspaceDir } from 'pkg-types'
|
||||||
@ -301,7 +301,8 @@ export default defineUntypedSchema({
|
|||||||
$resolve: async (val: string | undefined, get) => {
|
$resolve: async (val: string | undefined, get) => {
|
||||||
const isV4 = (await get('future') as Record<string, unknown>).compatibilityVersion === 4
|
const isV4 = (await get('future') as Record<string, unknown>).compatibilityVersion === 4
|
||||||
if (isV4) {
|
if (isV4) {
|
||||||
return resolve(await get('srcDir') as string, val || '.')
|
const [srcDir, rootDir] = await Promise.all([get('srcDir') as Promise<string>, get('rootDir') as Promise<string>])
|
||||||
|
return resolve(await get('srcDir') as string, val || (srcDir === rootDir ? 'app' : '.'))
|
||||||
}
|
}
|
||||||
return val || 'app'
|
return val || 'app'
|
||||||
},
|
},
|
||||||
@ -419,8 +420,8 @@ export default defineUntypedSchema({
|
|||||||
'@': srcDir,
|
'@': srcDir,
|
||||||
'~~': rootDir,
|
'~~': rootDir,
|
||||||
'@@': rootDir,
|
'@@': rootDir,
|
||||||
[assetsDir]: join(srcDir, assetsDir),
|
[basename(assetsDir)]: join(srcDir, assetsDir),
|
||||||
[publicDir]: join(srcDir, publicDir),
|
[basename(publicDir)]: join(srcDir, publicDir),
|
||||||
...val,
|
...val,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -7,43 +7,12 @@ export default defineUntypedSchema({
|
|||||||
*/
|
*/
|
||||||
future: {
|
future: {
|
||||||
/**
|
/**
|
||||||
* Enable early access to Nuxt v4 features or flags.
|
* Enable early access to future features or flags.
|
||||||
*
|
*
|
||||||
* Setting `compatibilityVersion` to `4` changes defaults throughout your
|
* It is currently not configurable but may be in future.
|
||||||
* Nuxt configuration, but you can granularly re-enable Nuxt v3 behaviour
|
* @type {4}
|
||||||
* when testing (see example). Please file issues if so, so that we can
|
|
||||||
* address in Nuxt or in the ecosystem.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* export default defineNuxtConfig({
|
|
||||||
* future: {
|
|
||||||
* compatibilityVersion: 4,
|
|
||||||
* },
|
|
||||||
* // To re-enable _all_ Nuxt v3 behaviour, set the following options:
|
|
||||||
* srcDir: '.',
|
|
||||||
* dir: {
|
|
||||||
* app: 'app'
|
|
||||||
* },
|
|
||||||
* experimental: {
|
|
||||||
* relativeWatchPaths: true,
|
|
||||||
* resetAsyncDataToUndefined: true,
|
|
||||||
* defaults: {
|
|
||||||
* useAsyncData: {
|
|
||||||
* deep: true
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* },
|
|
||||||
* unhead: {
|
|
||||||
* renderSSRHeadOptions: {
|
|
||||||
* omitLineBreaks: false
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* })
|
|
||||||
* ```
|
|
||||||
* @type {3 | 4}
|
|
||||||
*/
|
*/
|
||||||
compatibilityVersion: 3,
|
compatibilityVersion: 4,
|
||||||
/**
|
/**
|
||||||
* This enables early access to the experimental multi-app support.
|
* This enables early access to the experimental multi-app support.
|
||||||
* @see [Nuxt Issue #21635](https://github.com/nuxt/nuxt/issues/21635)
|
* @see [Nuxt Issue #21635](https://github.com/nuxt/nuxt/issues/21635)
|
||||||
@ -137,22 +106,6 @@ export default defineUntypedSchema({
|
|||||||
*/
|
*/
|
||||||
externalVue: true,
|
externalVue: true,
|
||||||
|
|
||||||
/**
|
|
||||||
* Tree shakes contents of client-only components from server bundle.
|
|
||||||
* @see [Nuxt PR #5750](https://github.com/nuxt/framework/pull/5750)
|
|
||||||
* @deprecated This option will no longer be configurable in Nuxt v4
|
|
||||||
*/
|
|
||||||
treeshakeClientOnly: {
|
|
||||||
async $resolve (val, get) {
|
|
||||||
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
|
||||||
if (isV4 && val === false) {
|
|
||||||
console.warn('Enabling `experimental.treeshakeClientOnly` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return val ?? true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit `app:chunkError` hook when there is an error loading vite/webpack
|
* Emit `app:chunkError` hook when there is an error loading vite/webpack
|
||||||
* chunks.
|
* chunks.
|
||||||
@ -265,55 +218,6 @@ export default defineUntypedSchema({
|
|||||||
*/
|
*/
|
||||||
delayedHydration: false,
|
delayedHydration: false,
|
||||||
|
|
||||||
/**
|
|
||||||
* Config schema support
|
|
||||||
* @see [Nuxt Issue #15592](https://github.com/nuxt/nuxt/issues/15592)
|
|
||||||
* @deprecated This option will no longer be configurable in Nuxt v4
|
|
||||||
*/
|
|
||||||
configSchema: {
|
|
||||||
async $resolve (val, get) {
|
|
||||||
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
|
||||||
if (isV4 && val === false) {
|
|
||||||
console.warn('Enabling `experimental.configSchema` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.')
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return val ?? true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not to add a compatibility layer for modules, plugins or user code relying on the old
|
|
||||||
* `@vueuse/head` API.
|
|
||||||
*
|
|
||||||
* This is disabled to reduce the client-side bundle by ~0.5kb.
|
|
||||||
* @deprecated This feature will be removed in Nuxt v4.
|
|
||||||
*/
|
|
||||||
polyfillVueUseHead: {
|
|
||||||
async $resolve (val, get) {
|
|
||||||
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
|
||||||
if (isV4 && val === true) {
|
|
||||||
console.warn('Disabling `experimental.polyfillVueUseHead` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return val ?? false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header.
|
|
||||||
* @deprecated This feature will be removed in Nuxt v4.
|
|
||||||
*/
|
|
||||||
respectNoSSRHeader: {
|
|
||||||
async $resolve (val, get) {
|
|
||||||
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
|
||||||
if (isV4 && val === true) {
|
|
||||||
console.warn('Disabling `experimental.respectNoSSRHeader` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return val ?? false
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/** Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. */
|
/** Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. */
|
||||||
localLayerAliases: true,
|
localLayerAliases: true,
|
||||||
|
|
||||||
@ -436,23 +340,7 @@ export default defineUntypedSchema({
|
|||||||
* Options that apply to `useAsyncData` (and also therefore `useFetch`)
|
* Options that apply to `useAsyncData` (and also therefore `useFetch`)
|
||||||
*/
|
*/
|
||||||
useAsyncData: {
|
useAsyncData: {
|
||||||
/** @type {'undefined' | 'null'} */
|
deep: false,
|
||||||
value: {
|
|
||||||
async $resolve (val, get) {
|
|
||||||
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion === 4 ? 'undefined' : 'null')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/** @type {'undefined' | 'null'} */
|
|
||||||
errorValue: {
|
|
||||||
async $resolve (val, get) {
|
|
||||||
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion === 4 ? 'undefined' : 'null')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
deep: {
|
|
||||||
async $resolve (val, get) {
|
|
||||||
return val ?? !((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
/** @type {Pick<typeof import('ofetch')['FetchOptions'], 'timeout' | 'retry' | 'retryDelay' | 'retryStatusCodes'>} */
|
/** @type {Pick<typeof import('ofetch')['FetchOptions'], 'timeout' | 'retry' | 'retryDelay' | 'retryStatusCodes'>} */
|
||||||
useFetch: {},
|
useFetch: {},
|
||||||
@ -474,25 +362,11 @@ export default defineUntypedSchema({
|
|||||||
clientNodeCompat: false,
|
clientNodeCompat: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to provide relative paths in the `builder:watch` hook.
|
* Wait for a single animation frame before navigation, which gives an opportunity
|
||||||
|
* for the browser to repaint, acknowledging user interaction.
|
||||||
*
|
*
|
||||||
* This flag will be removed with the release of v4 and exists only for
|
* It can reduce INP when navigating on prerendered routes.
|
||||||
* advance testing within Nuxt v3.12+ or in [the nightly release channel](/docs/guide/going-further/nightly-release-channel).
|
|
||||||
*/
|
*/
|
||||||
relativeWatchPaths: {
|
navigationRepaint: true,
|
||||||
async $resolve (val, get) {
|
|
||||||
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion !== 4)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether `clear` and `clearNuxtData` should reset async data to its _default_ value or update
|
|
||||||
* it to `null`/`undefined`.
|
|
||||||
*/
|
|
||||||
resetAsyncDataToUndefined: {
|
|
||||||
async $resolve (val, get) {
|
|
||||||
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion !== 4)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -47,6 +47,7 @@ export default defineUntypedSchema({
|
|||||||
'@vue/compiler-sfc',
|
'@vue/compiler-sfc',
|
||||||
'@vue/runtime-dom',
|
'@vue/runtime-dom',
|
||||||
'vue-router',
|
'vue-router',
|
||||||
|
'vue-router/auto',
|
||||||
'@nuxt/schema',
|
'@nuxt/schema',
|
||||||
'nuxt',
|
'nuxt',
|
||||||
]
|
]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import type { Defu } from 'defu'
|
||||||
import type { NuxtHooks } from './hooks'
|
import type { NuxtHooks } from './hooks'
|
||||||
import type { Nuxt } from './nuxt'
|
import type { Nuxt } from './nuxt'
|
||||||
import type { NuxtCompatibility } from './compatibility'
|
import type { NuxtCompatibility } from './compatibility'
|
||||||
@ -26,8 +27,7 @@ export interface ModuleMeta {
|
|||||||
/** The options received. */
|
/** The options received. */
|
||||||
export type ModuleOptions = Record<string, any>
|
export type ModuleOptions = Record<string, any>
|
||||||
|
|
||||||
/** Optional result for nuxt modules */
|
export type ModuleSetupInstallResult = {
|
||||||
export interface ModuleSetupReturn {
|
|
||||||
/**
|
/**
|
||||||
* Timing information for the initial setup
|
* Timing information for the initial setup
|
||||||
*/
|
*/
|
||||||
@ -39,19 +39,62 @@ export interface ModuleSetupReturn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Awaitable<T> = T | Promise<T>
|
type Awaitable<T> = T | Promise<T>
|
||||||
type _ModuleSetupReturn = Awaitable<void | false | ModuleSetupReturn>
|
|
||||||
|
|
||||||
/** Input module passed to defineNuxtModule. */
|
type Prettify<T> = {
|
||||||
export interface ModuleDefinition<T extends ModuleOptions = ModuleOptions> {
|
[K in keyof T]: T[K];
|
||||||
|
} & {}
|
||||||
|
|
||||||
|
export type ModuleSetupReturn = Awaitable<false | void | ModuleSetupInstallResult>
|
||||||
|
|
||||||
|
export type ResolvedModuleOptions<
|
||||||
|
TOptions extends ModuleOptions,
|
||||||
|
TOptionsDefaults extends Partial<TOptions>,
|
||||||
|
> =
|
||||||
|
Prettify<
|
||||||
|
Defu<
|
||||||
|
Partial<TOptions>,
|
||||||
|
[Partial<TOptions>, TOptionsDefaults]
|
||||||
|
>
|
||||||
|
>
|
||||||
|
|
||||||
|
/** Module definition passed to 'defineNuxtModule(...)' or 'defineNuxtModule().with(...)'. */
|
||||||
|
export interface ModuleDefinition<
|
||||||
|
TOptions extends ModuleOptions,
|
||||||
|
TOptionsDefaults extends Partial<TOptions>,
|
||||||
|
TWith extends boolean,
|
||||||
|
> {
|
||||||
meta?: ModuleMeta
|
meta?: ModuleMeta
|
||||||
defaults?: T | ((nuxt: Nuxt) => T)
|
defaults?: TOptionsDefaults | ((nuxt: Nuxt) => TOptionsDefaults)
|
||||||
schema?: T
|
schema?: TOptions
|
||||||
hooks?: Partial<NuxtHooks>
|
hooks?: Partial<NuxtHooks>
|
||||||
setup?: (this: void, resolvedOptions: T, nuxt: Nuxt) => _ModuleSetupReturn
|
setup?: (
|
||||||
|
this: void,
|
||||||
|
resolvedOptions: TWith extends true
|
||||||
|
? ResolvedModuleOptions<TOptions, TOptionsDefaults>
|
||||||
|
: TOptions,
|
||||||
|
nuxt: Nuxt
|
||||||
|
) => ModuleSetupReturn
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NuxtModule<T extends ModuleOptions = ModuleOptions> {
|
export interface NuxtModule<
|
||||||
(this: void, inlineOptions: T, nuxt: Nuxt): _ModuleSetupReturn
|
TOptions extends ModuleOptions = ModuleOptions,
|
||||||
getOptions?: (inlineOptions?: T, nuxt?: Nuxt) => Promise<T>
|
TOptionsDefaults extends Partial<TOptions> = Partial<TOptions>,
|
||||||
|
TWith extends boolean = false,
|
||||||
|
> {
|
||||||
|
(
|
||||||
|
this: void,
|
||||||
|
resolvedOptions: TWith extends true
|
||||||
|
? ResolvedModuleOptions<TOptions, TOptionsDefaults>
|
||||||
|
: TOptions,
|
||||||
|
nuxt: Nuxt
|
||||||
|
): ModuleSetupReturn
|
||||||
|
getOptions?: (
|
||||||
|
inlineOptions?: Partial<TOptions>,
|
||||||
|
nuxt?: Nuxt
|
||||||
|
) => Promise<
|
||||||
|
TWith extends true
|
||||||
|
? ResolvedModuleOptions<TOptions, TOptionsDefaults>
|
||||||
|
: TOptions
|
||||||
|
>
|
||||||
getMeta?: () => Promise<ModuleMeta>
|
getMeta?: () => Promise<ModuleMeta>
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import type { RouterHistory, RouterOptions as _RouterOptions } from 'vue-router'
|
|||||||
|
|
||||||
export type RouterOptions = Partial<Omit<_RouterOptions, 'history' | 'routes'>> & {
|
export type RouterOptions = Partial<Omit<_RouterOptions, 'history' | 'routes'>> & {
|
||||||
history?: (baseURL?: string) => RouterHistory
|
history?: (baseURL?: string) => RouterHistory
|
||||||
routes?: (_routes: _RouterOptions['routes']) => _RouterOptions['routes']
|
routes?: (_routes: _RouterOptions['routes']) => _RouterOptions['routes'] | Promise<_RouterOptions['routes']>
|
||||||
hashMode?: boolean
|
hashMode?: boolean
|
||||||
scrollBehaviorType?: 'smooth' | 'auto'
|
scrollBehaviorType?: 'smooth' | 'auto'
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,13 @@ describe('nuxt folder structure', () => {
|
|||||||
expect(getDirs(result as unknown as NuxtOptions)).toMatchInlineSnapshot(`
|
expect(getDirs(result as unknown as NuxtOptions)).toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"dir": {
|
"dir": {
|
||||||
"app": "app",
|
"app": "<cwd>/app",
|
||||||
"modules": "modules",
|
"modules": "<cwd>/modules",
|
||||||
"public": "public",
|
"public": "<cwd>/public",
|
||||||
},
|
},
|
||||||
"rootDir": "<cwd>",
|
"rootDir": "<cwd>",
|
||||||
"serverDir": "<cwd>/server",
|
"serverDir": "<cwd>/server",
|
||||||
"srcDir": "<cwd>",
|
"srcDir": "<cwd>/app",
|
||||||
"workspaceDir": "<cwd>",
|
"workspaceDir": "<cwd>",
|
||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
@ -28,12 +28,12 @@ describe('nuxt folder structure', () => {
|
|||||||
expect(getDirs(result as unknown as NuxtOptions)).toMatchInlineSnapshot(`
|
expect(getDirs(result as unknown as NuxtOptions)).toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"dir": {
|
"dir": {
|
||||||
"app": "app",
|
"app": "/test/src",
|
||||||
"modules": "modules",
|
"modules": "/test/modules",
|
||||||
"public": "public",
|
"public": "/test/public",
|
||||||
},
|
},
|
||||||
"rootDir": "/test",
|
"rootDir": "/test",
|
||||||
"serverDir": "/test/src/server",
|
"serverDir": "/test/server",
|
||||||
"srcDir": "/test/src",
|
"srcDir": "/test/src",
|
||||||
"workspaceDir": "/test",
|
"workspaceDir": "/test",
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"clear": "^0.1.0",
|
"clear": "^0.1.0",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"cssnano": "^7.0.2",
|
"cssnano": "^7.0.3",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"esbuild": "^0.21.5",
|
"esbuild": "^0.21.5",
|
||||||
"escape-string-regexp": "^5.0.0",
|
"escape-string-regexp": "^5.0.0",
|
||||||
@ -48,7 +48,7 @@
|
|||||||
"externality": "^1.0.2",
|
"externality": "^1.0.2",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"get-port-please": "^3.1.2",
|
"get-port-please": "^3.1.2",
|
||||||
"h3": "^1.11.1",
|
"h3": "^1.12.0",
|
||||||
"knitwork": "^1.1.0",
|
"knitwork": "^1.1.0",
|
||||||
"magic-string": "^0.30.10",
|
"magic-string": "^0.30.10",
|
||||||
"mlly": "^1.7.1",
|
"mlly": "^1.7.1",
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"css-minimizer-webpack-plugin": "^7.0.0",
|
"css-minimizer-webpack-plugin": "^7.0.0",
|
||||||
"cssnano": "^7.0.2",
|
"cssnano": "^7.0.3",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"esbuild-loader": "^4.2.0",
|
"esbuild-loader": "^4.2.0",
|
||||||
"escape-string-regexp": "^5.0.0",
|
"escape-string-regexp": "^5.0.0",
|
||||||
@ -38,7 +38,7 @@
|
|||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
||||||
"fs-extra": "^11.2.0",
|
"fs-extra": "^11.2.0",
|
||||||
"h3": "^1.11.1",
|
"h3": "^1.12.0",
|
||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
"magic-string": "^0.30.10",
|
"magic-string": "^0.30.10",
|
||||||
@ -62,7 +62,7 @@
|
|||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"vue-bundle-renderer": "^2.1.0",
|
"vue-bundle-renderer": "^2.1.0",
|
||||||
"vue-loader": "^17.4.2",
|
"vue-loader": "^17.4.2",
|
||||||
"webpack": "^5.92.0",
|
"webpack": "^5.92.1",
|
||||||
"webpack-bundle-analyzer": "^4.10.2",
|
"webpack-bundle-analyzer": "^4.10.2",
|
||||||
"webpack-dev-middleware": "^7.2.1",
|
"webpack-dev-middleware": "^7.2.1",
|
||||||
"webpack-hot-middleware": "^2.26.1",
|
"webpack-hot-middleware": "^2.26.1",
|
||||||
|
1272
pnpm-lock.yaml
1272
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -103,9 +103,7 @@ export async function determineBumpType () {
|
|||||||
const config = await loadChangelogConfig(process.cwd())
|
const config = await loadChangelogConfig(process.cwd())
|
||||||
const commits = await getLatestCommits()
|
const commits = await getLatestCommits()
|
||||||
|
|
||||||
const bumpType = determineSemverChange(commits, config)
|
return determineSemverChange(commits, config)
|
||||||
|
|
||||||
return bumpType === 'major' ? 'minor' : bumpType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLatestCommits () {
|
export async function getLatestCommits () {
|
||||||
|
@ -13,7 +13,6 @@ import type { NuxtIslandResponse } from '#app'
|
|||||||
|
|
||||||
const isWebpack = process.env.TEST_BUILDER === 'webpack'
|
const isWebpack = process.env.TEST_BUILDER === 'webpack'
|
||||||
const isTestingAppManifest = process.env.TEST_MANIFEST !== 'manifest-off'
|
const isTestingAppManifest = process.env.TEST_MANIFEST !== 'manifest-off'
|
||||||
const isV4 = process.env.TEST_V4 === 'true'
|
|
||||||
|
|
||||||
await setup({
|
await setup({
|
||||||
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
|
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
|
||||||
@ -918,19 +917,14 @@ describe('head tags', () => {
|
|||||||
expect(headHtml).toContain('<meta content="0;javascript:alert(1)">')
|
expect(headHtml).toContain('<meta content="0;javascript:alert(1)">')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skipIf(isV4)('SPA should render appHead tags', async () => {
|
it('SPA should render appHead tags', async () => {
|
||||||
const headHtml = await $fetch<string>('/head', { headers: { 'x-nuxt-no-ssr': '1' } })
|
const headHtml = await $fetch<string>('/head-spa')
|
||||||
|
|
||||||
expect(headHtml).toContain('<meta name="description" content="Nuxt Fixture">')
|
expect(headHtml).toContain('<meta name="description" content="Nuxt Fixture">')
|
||||||
expect(headHtml).toContain('<meta charset="utf-8">')
|
expect(headHtml).toContain('<meta charset="utf-8">')
|
||||||
expect(headHtml).toContain('<meta name="viewport" content="width=1024, initial-scale=1">')
|
expect(headHtml).toContain('<meta name="viewport" content="width=1024, initial-scale=1">')
|
||||||
})
|
})
|
||||||
|
|
||||||
it.skipIf(isV4)('legacy vueuse/head works', async () => {
|
|
||||||
const headHtml = await $fetch<string>('/vueuse-head')
|
|
||||||
expect(headHtml).toContain('<title>using provides usehead and updateDOM - VueUse head polyfill test</title>')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should render http-equiv correctly', async () => {
|
it('should render http-equiv correctly', async () => {
|
||||||
const html = await $fetch<string>('/head')
|
const html = await $fetch<string>('/head')
|
||||||
// http-equiv should be rendered kebab case
|
// http-equiv should be rendered kebab case
|
||||||
@ -2463,7 +2457,7 @@ describe.skipIf(isWindows)('useAsyncData', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('data is null after navigation when immediate false', async () => {
|
it('data is null after navigation when immediate false', async () => {
|
||||||
const defaultValue = isV4 ? 'undefined' : 'null'
|
const defaultValue = 'undefined'
|
||||||
|
|
||||||
const { page } = await renderPage('/useAsyncData/immediate-remove-unmounted')
|
const { page } = await renderPage('/useAsyncData/immediate-remove-unmounted')
|
||||||
expect(await page.locator('#immediate-data').getByText(defaultValue).textContent()).toBe(defaultValue)
|
expect(await page.locator('#immediate-data').getByText(defaultValue).textContent()).toBe(defaultValue)
|
||||||
|
@ -32,7 +32,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
const serverDir = join(rootDir, '.output/server')
|
const serverDir = join(rootDir, '.output/server')
|
||||||
|
|
||||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"209k"`)
|
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"210k"`)
|
||||||
|
|
||||||
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
||||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1340k"`)
|
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1340k"`)
|
||||||
@ -72,7 +72,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
const serverDir = join(rootDir, '.output-inline/server')
|
const serverDir = join(rootDir, '.output-inline/server')
|
||||||
|
|
||||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"530k"`)
|
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"531k"`)
|
||||||
|
|
||||||
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
||||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"76.2k"`)
|
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"76.2k"`)
|
||||||
|
1
test/fixtures/basic-types/nuxt.config.ts
vendored
1
test/fixtures/basic-types/nuxt.config.ts
vendored
@ -7,7 +7,6 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
future: {
|
future: {
|
||||||
typescriptBundlerResolution: process.env.MODULE_RESOLUTION === 'bundler',
|
typescriptBundlerResolution: process.env.MODULE_RESOLUTION === 'bundler',
|
||||||
compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3,
|
|
||||||
},
|
},
|
||||||
buildDir: process.env.NITRO_BUILD_DIR,
|
buildDir: process.env.NITRO_BUILD_DIR,
|
||||||
builder: process.env.TEST_BUILDER as 'webpack' | 'vite' ?? 'vite',
|
builder: process.env.TEST_BUILDER as 'webpack' | 'vite' ?? 'vite',
|
||||||
|
21
test/fixtures/basic-types/types.ts
vendored
21
test/fixtures/basic-types/types.ts
vendored
@ -12,8 +12,8 @@ import type { NavigateToOptions } from '#app/composables/router'
|
|||||||
import { NuxtLayout, NuxtLink, NuxtPage, ServerComponent, WithTypes } from '#components'
|
import { NuxtLayout, NuxtLink, NuxtPage, ServerComponent, WithTypes } from '#components'
|
||||||
import { useRouter } from '#imports'
|
import { useRouter } from '#imports'
|
||||||
|
|
||||||
// TODO: temporary module for backwards compatibility
|
type DefaultAsyncDataErrorValue = undefined
|
||||||
import type { DefaultAsyncDataErrorValue, DefaultAsyncDataValue } from '#app/defaults'
|
type DefaultAsyncDataValue = undefined
|
||||||
|
|
||||||
interface TestResponse { message: string }
|
interface TestResponse { message: string }
|
||||||
|
|
||||||
@ -254,6 +254,23 @@ describe('modules', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('correctly typed resolved options in defineNuxtModule setup using `.with()`', () => {
|
||||||
|
defineNuxtModule<{
|
||||||
|
foo?: string
|
||||||
|
baz: number
|
||||||
|
}>().with({
|
||||||
|
defaults: {
|
||||||
|
foo: 'bar',
|
||||||
|
},
|
||||||
|
setup: (resolvedOptions) => {
|
||||||
|
expectTypeOf(resolvedOptions).toEqualTypeOf<{
|
||||||
|
foo: string
|
||||||
|
baz?: number | undefined
|
||||||
|
}>()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('nuxtApp', () => {
|
describe('nuxtApp', () => {
|
||||||
|
2
test/fixtures/basic/nuxt.config.ts
vendored
2
test/fixtures/basic/nuxt.config.ts
vendored
@ -12,7 +12,6 @@ declare module 'nitropack' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
|
||||||
app: {
|
app: {
|
||||||
pageTransition: true,
|
pageTransition: true,
|
||||||
layoutTransition: true,
|
layoutTransition: true,
|
||||||
@ -63,6 +62,7 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
routeRules: {
|
routeRules: {
|
||||||
'/route-rules/spa': { ssr: false },
|
'/route-rules/spa': { ssr: false },
|
||||||
|
'/head-spa': { ssr: false },
|
||||||
'/route-rules/middleware': { appMiddleware: 'route-rules-middleware' },
|
'/route-rules/middleware': { appMiddleware: 'route-rules-middleware' },
|
||||||
'/hydration/spa-redirection/**': { ssr: false },
|
'/hydration/spa-redirection/**': { ssr: false },
|
||||||
'/no-scripts': { experimentalNoScripts: true },
|
'/no-scripts': { experimentalNoScripts: true },
|
||||||
|
@ -20,11 +20,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { asyncDataDefaults } from '#build/nuxt.config.mjs'
|
|
||||||
|
|
||||||
const { data, execute } = await useAsyncData('immediateFalse', () => $fetch('/api/random'), { immediate: false })
|
const { data, execute } = await useAsyncData('immediateFalse', () => $fetch('/api/random'), { immediate: false })
|
||||||
|
|
||||||
if (data.value !== asyncDataDefaults.errorValue) {
|
if (data.value !== undefined) {
|
||||||
throw new Error(`Initial data should be ${asyncDataDefaults.errorValue}: ` + data.value)
|
throw new Error(`Initial data should be undefined: ` + data.value)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
1
test/fixtures/minimal-types/nuxt.config.ts
vendored
1
test/fixtures/minimal-types/nuxt.config.ts
vendored
@ -1,4 +1,3 @@
|
|||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
|
||||||
experimental: { appManifest: true },
|
experimental: { appManifest: true },
|
||||||
})
|
})
|
||||||
|
1
test/fixtures/minimal/nuxt.config.ts
vendored
1
test/fixtures/minimal/nuxt.config.ts
vendored
@ -3,7 +3,6 @@ import { fileURLToPath } from 'node:url'
|
|||||||
const testWithInlineVue = process.env.EXTERNAL_VUE === 'false'
|
const testWithInlineVue = process.env.EXTERNAL_VUE === 'false'
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
|
||||||
pages: false,
|
pages: false,
|
||||||
experimental: {
|
experimental: {
|
||||||
externalVue: !testWithInlineVue,
|
externalVue: !testWithInlineVue,
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// https://nuxt.com/docs/api/nuxt-config
|
// https://nuxt.com/docs/api/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
|
||||||
experimental: {
|
experimental: {
|
||||||
externalVue: false,
|
externalVue: false,
|
||||||
},
|
},
|
||||||
|
1
test/fixtures/suspense/nuxt.config.ts
vendored
1
test/fixtures/suspense/nuxt.config.ts
vendored
@ -3,7 +3,6 @@ import { fileURLToPath } from 'node:url'
|
|||||||
const testWithInlineVue = process.env.EXTERNAL_VUE === 'false'
|
const testWithInlineVue = process.env.EXTERNAL_VUE === 'false'
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
|
||||||
experimental: {
|
experimental: {
|
||||||
externalVue: !testWithInlineVue,
|
externalVue: !testWithInlineVue,
|
||||||
},
|
},
|
||||||
|
@ -20,8 +20,6 @@ import { callOnce } from '#app/composables/once'
|
|||||||
import { useLoadingIndicator } from '#app/composables/loading-indicator'
|
import { useLoadingIndicator } from '#app/composables/loading-indicator'
|
||||||
import { useRouteAnnouncer } from '#app/composables/route-announcer'
|
import { useRouteAnnouncer } from '#app/composables/route-announcer'
|
||||||
|
|
||||||
import { asyncDataDefaults, nuxtDefaultErrorValue } from '#build/nuxt.config.mjs'
|
|
||||||
|
|
||||||
registerEndpoint('/api/test', defineEventHandler(event => ({
|
registerEndpoint('/api/test', defineEventHandler(event => ({
|
||||||
method: event.method,
|
method: event.method,
|
||||||
headers: Object.fromEntries(event.headers.entries()),
|
headers: Object.fromEntries(event.headers.entries()),
|
||||||
@ -128,7 +126,7 @@ describe('useAsyncData', () => {
|
|||||||
]
|
]
|
||||||
`)
|
`)
|
||||||
expect(res instanceof Promise).toBeTruthy()
|
expect(res instanceof Promise).toBeTruthy()
|
||||||
expect(res.data.value).toBe(asyncDataDefaults.value)
|
expect(res.data.value).toBe(undefined)
|
||||||
await res
|
await res
|
||||||
expect(res.data.value).toBe('test')
|
expect(res.data.value).toBe('test')
|
||||||
})
|
})
|
||||||
@ -140,7 +138,7 @@ describe('useAsyncData', () => {
|
|||||||
expect(immediate.pending.value).toBe(false)
|
expect(immediate.pending.value).toBe(false)
|
||||||
|
|
||||||
const nonimmediate = await useAsyncData(() => Promise.resolve('test'), { immediate: false })
|
const nonimmediate = await useAsyncData(() => Promise.resolve('test'), { immediate: false })
|
||||||
expect(nonimmediate.data.value).toBe(asyncDataDefaults.value)
|
expect(nonimmediate.data.value).toBe(undefined)
|
||||||
expect(nonimmediate.status.value).toBe('idle')
|
expect(nonimmediate.status.value).toBe('idle')
|
||||||
expect(nonimmediate.pending.value).toBe(true)
|
expect(nonimmediate.pending.value).toBe(true)
|
||||||
})
|
})
|
||||||
@ -165,9 +163,9 @@ describe('useAsyncData', () => {
|
|||||||
// https://github.com/nuxt/nuxt/issues/23411
|
// https://github.com/nuxt/nuxt/issues/23411
|
||||||
it('should initialize with error set to null when immediate: false', async () => {
|
it('should initialize with error set to null when immediate: false', async () => {
|
||||||
const { error, execute } = useAsyncData(() => Promise.resolve({}), { immediate: false })
|
const { error, execute } = useAsyncData(() => Promise.resolve({}), { immediate: false })
|
||||||
expect(error.value).toBe(asyncDataDefaults.errorValue)
|
expect(error.value).toBe(undefined)
|
||||||
await execute()
|
await execute()
|
||||||
expect(error.value).toBe(asyncDataDefaults.errorValue)
|
expect(error.value).toBe(undefined)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should be accessible with useNuxtData', async () => {
|
it('should be accessible with useNuxtData', async () => {
|
||||||
@ -208,9 +206,8 @@ describe('useAsyncData', () => {
|
|||||||
|
|
||||||
clear()
|
clear()
|
||||||
|
|
||||||
// TODO: update to asyncDataDefaults.value in v4
|
|
||||||
expect(data.value).toBeUndefined()
|
expect(data.value).toBeUndefined()
|
||||||
expect(error.value).toBe(asyncDataDefaults.errorValue)
|
expect(error.value).toBe(undefined)
|
||||||
expect(pending.value).toBe(false)
|
expect(pending.value).toBe(false)
|
||||||
expect(status.value).toBe('idle')
|
expect(status.value).toBe('idle')
|
||||||
})
|
})
|
||||||
@ -354,7 +351,7 @@ describe('errors', () => {
|
|||||||
showError('new error')
|
showError('new error')
|
||||||
expect(error.value).toMatchInlineSnapshot('[Error: new error]')
|
expect(error.value).toMatchInlineSnapshot('[Error: new error]')
|
||||||
clearError()
|
clearError()
|
||||||
expect(error.value).toBe(nuxtDefaultErrorValue)
|
expect(error.value).toBe(undefined)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -620,7 +617,7 @@ describe('routing utilities: `abortNavigation`', () => {
|
|||||||
it('should throw an error if one is provided', () => {
|
it('should throw an error if one is provided', () => {
|
||||||
const error = useError()
|
const error = useError()
|
||||||
expect(() => abortNavigation({ message: 'Page not found' })).toThrowErrorMatchingInlineSnapshot('[Error: Page not found]')
|
expect(() => abortNavigation({ message: 'Page not found' })).toThrowErrorMatchingInlineSnapshot('[Error: Page not found]')
|
||||||
expect(error.value).toBe(nuxtDefaultErrorValue)
|
expect(error.value).toBe(undefined)
|
||||||
})
|
})
|
||||||
it('should block navigation if no error is provided', () => {
|
it('should block navigation if no error is provided', () => {
|
||||||
expect(abortNavigation()).toMatchInlineSnapshot('false')
|
expect(abortNavigation()).toMatchInlineSnapshot('false')
|
||||||
|
Loading…
Reference in New Issue
Block a user