mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-23 22:25:12 +00:00
Merge branch 'main' into feat/islands-use-cache
This commit is contained in:
commit
0861bdb7ba
2
.github/workflows/autofix-docs.yml
vendored
2
.github/workflows/autofix-docs.yml
vendored
@ -33,4 +33,4 @@ jobs:
|
|||||||
- name: Lint (docs)
|
- name: Lint (docs)
|
||||||
run: pnpm lint:docs:fix
|
run: pnpm lint:docs:fix
|
||||||
|
|
||||||
- uses: autofix-ci/action@2891949f3779a1cafafae1523058501de3d4e944
|
- uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c
|
||||||
|
2
.github/workflows/autofix.yml
vendored
2
.github/workflows/autofix.yml
vendored
@ -52,4 +52,4 @@ jobs:
|
|||||||
- name: Lint (code)
|
- name: Lint (code)
|
||||||
run: pnpm lint:fix
|
run: pnpm lint:fix
|
||||||
|
|
||||||
- uses: autofix-ci/action@2891949f3779a1cafafae1523058501de3d4e944
|
- uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c
|
||||||
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -85,7 +85,7 @@ jobs:
|
|||||||
run: pnpm install
|
run: pnpm install
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@4fa2a7953630fd2f3fb380f21be14ede0169dd4f # v3.25.12
|
uses: github/codeql-action/init@5cf07d8b700b67e235fbb65cbc84f69c0cf10464 # v3.25.14
|
||||||
with:
|
with:
|
||||||
languages: javascript
|
languages: javascript
|
||||||
queries: +security-and-quality
|
queries: +security-and-quality
|
||||||
@ -97,7 +97,7 @@ jobs:
|
|||||||
path: packages
|
path: packages
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@4fa2a7953630fd2f3fb380f21be14ede0169dd4f # v3.25.12
|
uses: github/codeql-action/analyze@5cf07d8b700b67e235fbb65cbc84f69c0cf10464 # v3.25.14
|
||||||
with:
|
with:
|
||||||
category: "/language:javascript"
|
category: "/language:javascript"
|
||||||
|
|
||||||
|
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
|||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@4fa2a7953630fd2f3fb380f21be14ede0169dd4f # v3.25.12
|
uses: github/codeql-action/upload-sarif@5cf07d8b700b67e235fbb65cbc84f69c0cf10464 # v3.25.14
|
||||||
if: github.repository == 'nuxt/nuxt' && success()
|
if: github.repository == 'nuxt/nuxt' && success()
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
@ -26,7 +26,7 @@ pnpm dlx nuxi upgrade
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash [bun]
|
```bash [bun]
|
||||||
bunx nuxi upgrade
|
bun x nuxi upgrade
|
||||||
```
|
```
|
||||||
|
|
||||||
::
|
::
|
||||||
@ -97,6 +97,24 @@ Breaking or significant changes will be noted here along with migration steps fo
|
|||||||
This section is subject to change until the final release, so please check back here regularly if you are testing Nuxt 4 using `compatibilityVersion: 4`.
|
This section is subject to change until the final release, so please check back here regularly if you are testing Nuxt 4 using `compatibilityVersion: 4`.
|
||||||
::
|
::
|
||||||
|
|
||||||
|
#### Migrating Using Codemods
|
||||||
|
|
||||||
|
To facilitate the upgrade process, we have collaborated with the [Codemod](https://github.com/codemod-com/codemod) team to automate many migration steps with some open-source codemods.
|
||||||
|
|
||||||
|
::note
|
||||||
|
If you encounter any issues, please report them to the Codemod team with `npx codemod feedback` 🙏
|
||||||
|
::
|
||||||
|
|
||||||
|
For a complete list of Nuxt 4 codemods, detailed information on each, their source, and various ways to run them, visit the [Codemod Registry](https://go.codemod.com/codemod-registry).
|
||||||
|
|
||||||
|
You can run all the codemods mentioned in this guide using the following `codemod` recipe:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx codemod@latest nuxt/4/migration-recipe
|
||||||
|
```
|
||||||
|
|
||||||
|
This command will execute all codemods in sequence, with the option to deselect any that you do not wish to run. Each codemod is also listed below alongside its respective change and can be executed independently.
|
||||||
|
|
||||||
#### New Directory Structure
|
#### New Directory Structure
|
||||||
|
|
||||||
🚦 **Impact Level**: Significant
|
🚦 **Impact Level**: Significant
|
||||||
@ -161,6 +179,10 @@ nuxt.config.ts
|
|||||||
1. Move your `assets/`, `components/`, `composables/`, `layouts/`, `middleware/`, `pages/`, `plugins/` and `utils/` folders under it, as well as `app.vue`, `error.vue`, `app.config.ts`. If you have an `app/router-options.ts` or `app/spa-loading-template.html`, these paths remain the same.
|
1. Move your `assets/`, `components/`, `composables/`, `layouts/`, `middleware/`, `pages/`, `plugins/` and `utils/` folders under it, as well as `app.vue`, `error.vue`, `app.config.ts`. If you have an `app/router-options.ts` or `app/spa-loading-template.html`, these paths remain the same.
|
||||||
1. Make sure your `nuxt.config.ts`, `content/`, `layers/`, `modules/`, `public/` and `server/` folders remain outside the `app/` folder, in the root of your project.
|
1. Make sure your `nuxt.config.ts`, `content/`, `layers/`, `modules/`, `public/` and `server/` folders remain outside the `app/` folder, in the root of your project.
|
||||||
|
|
||||||
|
::tip
|
||||||
|
You can automate this migration by running `npx codemod@latest nuxt/4/file-structure`
|
||||||
|
::
|
||||||
|
|
||||||
However, migration is _not required_. If you wish to keep your current folder structure, Nuxt should auto-detect it. (If it does not, please raise an issue.) The one exception is that if you _already_ have a custom `srcDir`. In this case, you should be aware that your `modules/`, `public/` and `server/` folders will be resolved from your `rootDir` rather than from your custom `srcDir`. You can override this by configuring `dir.modules`, `dir.public` and `serverDir` if you need to.
|
However, migration is _not required_. If you wish to keep your current folder structure, Nuxt should auto-detect it. (If it does not, please raise an issue.) The one exception is that if you _already_ have a custom `srcDir`. In this case, you should be aware that your `modules/`, `public/` and `server/` folders will be resolved from your `rootDir` rather than from your custom `srcDir`. You can override this by configuring `dir.modules`, `dir.public` and `serverDir` if you need to.
|
||||||
|
|
||||||
You can also force a v3 folder structure with the following configuration:
|
You can also force a v3 folder structure with the following configuration:
|
||||||
@ -231,6 +253,12 @@ Previously `data` was initialized to `null` but reset in `clearNuxtData` to `und
|
|||||||
|
|
||||||
##### Migration Steps
|
##### Migration Steps
|
||||||
|
|
||||||
|
If you were checking if `data.value` or `error.value` were `null`, you can update these checks to check for `undefined` instead.
|
||||||
|
|
||||||
|
::tip
|
||||||
|
You can automate this step by running `npx codemod@latest nuxt/4/default-data-error-value`
|
||||||
|
::
|
||||||
|
|
||||||
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]
|
||||||
@ -290,6 +318,10 @@ The migration should be straightforward:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::tip
|
||||||
|
You can automate this step by running `npx codemod@latest nuxt/4/deprecated-dedupe-value`
|
||||||
|
::
|
||||||
|
|
||||||
#### Respect defaults when clearing `data` in `useAsyncData` and `useFetch`
|
#### Respect defaults when clearing `data` in `useAsyncData` and `useFetch`
|
||||||
|
|
||||||
🚦 **Impact Level**: Minimal
|
🚦 **Impact Level**: Minimal
|
||||||
@ -353,6 +385,10 @@ In most cases, no migration steps are required, but if you rely on the reactivit
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::tip
|
||||||
|
If you need to, you can automate this step by running `npx codemod@latest nuxt/4/shallow-function-reactivity`
|
||||||
|
::
|
||||||
|
|
||||||
#### Absolute Watch Paths in `builder:watch`
|
#### Absolute Watch Paths in `builder:watch`
|
||||||
|
|
||||||
🚦 **Impact Level**: Minimal
|
🚦 **Impact Level**: Minimal
|
||||||
@ -380,6 +416,10 @@ However, if you are a module author using the `builder:watch` hook and wishing t
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::tip
|
||||||
|
You can automate this step by running `npx codemod@latest nuxt/4/absolute-watch-path`
|
||||||
|
::
|
||||||
|
|
||||||
#### Removal of `window.__NUXT__` object
|
#### Removal of `window.__NUXT__` object
|
||||||
|
|
||||||
##### What Changed
|
##### What Changed
|
||||||
@ -487,6 +527,10 @@ const importSources = (sources: string | string[], { lazy = false } = {}) => {
|
|||||||
const importName = genSafeVariableName
|
const importName = genSafeVariableName
|
||||||
```
|
```
|
||||||
|
|
||||||
|
::tip
|
||||||
|
You can automate this step by running `npx codemod@latest nuxt/4/template-compilation-changes`
|
||||||
|
::
|
||||||
|
|
||||||
#### Removal of Experimental Features
|
#### Removal of Experimental Features
|
||||||
|
|
||||||
🚦 **Impact Level**: Minimal
|
🚦 **Impact Level**: Minimal
|
||||||
|
@ -50,7 +50,7 @@ pnpm dlx nuxi@latest init <project-name>
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash [bun]
|
```bash [bun]
|
||||||
bunx nuxi@latest init <project-name>
|
bun x nuxi@latest init <project-name>
|
||||||
```
|
```
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -466,13 +466,14 @@ Be very careful before proxying headers to an external API and just include head
|
|||||||
If you want to pass on/proxy cookies in the other direction, from an internal request back to the client, you will need to handle this yourself.
|
If you want to pass on/proxy cookies in the other direction, from an internal request back to the client, you will need to handle this yourself.
|
||||||
|
|
||||||
```ts [composables/fetch.ts]
|
```ts [composables/fetch.ts]
|
||||||
import { appendResponseHeader, H3Event } from 'h3'
|
import { appendResponseHeader } from 'h3'
|
||||||
|
import type { H3Event } from 'h3'
|
||||||
|
|
||||||
export const fetchWithCookie = async (event: H3Event, url: string) => {
|
export const fetchWithCookie = async (event: H3Event, url: string) => {
|
||||||
/* Get the response from the server endpoint */
|
/* Get the response from the server endpoint */
|
||||||
const res = await $fetch.raw(url)
|
const res = await $fetch.raw(url)
|
||||||
/* Get the cookies from the response */
|
/* Get the cookies from the response */
|
||||||
const cookies = (res.headers.get('set-cookie') || '').split(',')
|
const cookies = res.headers.getSetCookie()
|
||||||
/* Attach each cookie to our incoming Request */
|
/* Attach each cookie to our incoming Request */
|
||||||
for (const cookie of cookies) {
|
for (const cookie of cookies) {
|
||||||
appendResponseHeader(event, 'set-cookie', cookie)
|
appendResponseHeader(event, 'set-cookie', cookie)
|
||||||
|
@ -20,7 +20,9 @@ One of the core features of Nuxt is the layers and extending support. You can ex
|
|||||||
|
|
||||||
By default, any layers within your project in the `~/layers` directory will be automatically registered as layers in your project
|
By default, any layers within your project in the `~/layers` directory will be automatically registered as layers in your project
|
||||||
|
|
||||||
::note Layer auto-registration was introduced in Nuxt v3.12.0 ::
|
::note
|
||||||
|
Layer auto-registration was introduced in Nuxt v3.12.0
|
||||||
|
::
|
||||||
|
|
||||||
In addition, you can extend from a layer by adding the [extends](/docs/api/nuxt-config#extends) property to your [`nuxt.config`](/docs/guide/directory-structure/nuxt-config) file.
|
In addition, you can extend from a layer by adding the [extends](/docs/api/nuxt-config#extends) property to your [`nuxt.config`](/docs/guide/directory-structure/nuxt-config) file.
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ pnpm dlx nuxi generate
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash [bun]
|
```bash [bun]
|
||||||
bunx nuxi generate
|
bun x nuxi generate
|
||||||
```
|
```
|
||||||
|
|
||||||
::
|
::
|
||||||
|
@ -28,7 +28,7 @@ pnpm dlx nuxi init -t module my-module
|
|||||||
```
|
```
|
||||||
|
|
||||||
```bash [bun]
|
```bash [bun]
|
||||||
bunx nuxi init -t module my-module
|
bun x nuxi init -t module my-module
|
||||||
```
|
```
|
||||||
::
|
::
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ Sets the message with `politeness = "assertive"`
|
|||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
```ts
|
```vue [pages/index.vue]
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { message, politeness, set, polite, assertive } = useRouteAnnouncer({
|
const { message, politeness, set, polite, assertive } = useRouteAnnouncer({
|
||||||
politeness: 'assertive'
|
politeness: 'assertive'
|
||||||
|
@ -3,7 +3,6 @@ import { createConfigForNuxt } from '@nuxt/eslint-config/flat'
|
|||||||
// @ts-expect-error missing types
|
// @ts-expect-error missing types
|
||||||
import noOnlyTests from 'eslint-plugin-no-only-tests'
|
import noOnlyTests from 'eslint-plugin-no-only-tests'
|
||||||
import typegen from 'eslint-typegen'
|
import typegen from 'eslint-typegen'
|
||||||
// @ts-expect-error missing types
|
|
||||||
import perfectionist from 'eslint-plugin-perfectionist'
|
import perfectionist from 'eslint-plugin-perfectionist'
|
||||||
|
|
||||||
export default createConfigForNuxt({
|
export default createConfigForNuxt({
|
||||||
@ -189,6 +188,7 @@ export default createConfigForNuxt({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Sort rule keys in eslint config
|
// Sort rule keys in eslint config
|
||||||
|
// @ts-expect-error incorrect types 🤔
|
||||||
{
|
{
|
||||||
files: ['**/eslint.config.mjs'],
|
files: ['**/eslint.config.mjs'],
|
||||||
name: 'local/sort-eslint-config',
|
name: 'local/sort-eslint-config',
|
||||||
|
34
package.json
34
package.json
@ -45,11 +45,11 @@
|
|||||||
"magic-string": "^0.30.10",
|
"magic-string": "^0.30.10",
|
||||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28665895.e727afda",
|
"nitro": "npm:nitro-nightly@3.0.0-beta-28665895.e727afda",
|
||||||
"nuxt": "workspace:*",
|
"nuxt": "workspace:*",
|
||||||
"rollup": "^4.18.1",
|
"rollup": "^4.19.0",
|
||||||
"typescript": "5.5.3",
|
"typescript": "5.5.4",
|
||||||
"unbuild": "3.0.0-rc.6",
|
"unbuild": "3.0.0-rc.7",
|
||||||
"vite": "5.3.4",
|
"vite": "5.3.5",
|
||||||
"vue": "3.4.31"
|
"vue": "3.4.34"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.7.0",
|
"@eslint/js": "9.7.0",
|
||||||
@ -59,11 +59,11 @@
|
|||||||
"@nuxt/webpack-builder": "workspace:*",
|
"@nuxt/webpack-builder": "workspace:*",
|
||||||
"@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/node": "20.14.10",
|
"@types/node": "20.14.12",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.5.8",
|
||||||
"@unhead/schema": "1.9.16",
|
"@unhead/schema": "1.9.16",
|
||||||
"@vitejs/plugin-vue": "5.0.5",
|
"@vitejs/plugin-vue": "5.1.0",
|
||||||
"@vitest/coverage-v8": "2.0.3",
|
"@vitest/coverage-v8": "2.0.4",
|
||||||
"@vue/test-utils": "2.4.6",
|
"@vue/test-utils": "2.4.6",
|
||||||
"autoprefixer": "10.4.19",
|
"autoprefixer": "10.4.19",
|
||||||
"case-police": "0.6.1",
|
"case-police": "0.6.1",
|
||||||
@ -73,7 +73,7 @@
|
|||||||
"devalue": "5.0.0",
|
"devalue": "5.0.0",
|
||||||
"eslint": "9.7.0",
|
"eslint": "9.7.0",
|
||||||
"eslint-plugin-no-only-tests": "3.1.0",
|
"eslint-plugin-no-only-tests": "3.1.0",
|
||||||
"eslint-plugin-perfectionist": "2.11.0",
|
"eslint-plugin-perfectionist": "3.0.0",
|
||||||
"eslint-typegen": "0.2.4",
|
"eslint-typegen": "0.2.4",
|
||||||
"execa": "9.3.0",
|
"execa": "9.3.0",
|
||||||
"globby": "14.0.2",
|
"globby": "14.0.2",
|
||||||
@ -87,19 +87,19 @@
|
|||||||
"nuxt-content-twoslash": "0.1.0",
|
"nuxt-content-twoslash": "0.1.0",
|
||||||
"ofetch": "1.3.4",
|
"ofetch": "1.3.4",
|
||||||
"pathe": "1.1.2",
|
"pathe": "1.1.2",
|
||||||
"playwright-core": "1.45.2",
|
"playwright-core": "1.45.3",
|
||||||
"rimraf": "6.0.1",
|
"rimraf": "6.0.1",
|
||||||
"semver": "7.6.2",
|
"semver": "7.6.3",
|
||||||
"std-env": "3.7.0",
|
"std-env": "3.7.0",
|
||||||
"typescript": "5.5.3",
|
"typescript": "5.5.4",
|
||||||
"ufo": "1.5.3",
|
"ufo": "1.5.4",
|
||||||
"vitest": "2.0.3",
|
"vitest": "2.0.4",
|
||||||
"vitest-environment-nuxt": "1.0.0",
|
"vitest-environment-nuxt": "1.0.0",
|
||||||
"vue": "3.4.31",
|
"vue": "3.4.34",
|
||||||
"vue-router": "4.4.0",
|
"vue-router": "4.4.0",
|
||||||
"vue-tsc": "2.0.26"
|
"vue-tsc": "2.0.29"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@9.5.0",
|
"packageManager": "pnpm@9.6.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.10.0 || >=18.0.0"
|
"node": "^16.10.0 || >=18.0.0"
|
||||||
},
|
},
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"destr": "^2.0.3",
|
"destr": "^2.0.3",
|
||||||
|
"errx": "^0.1.0",
|
||||||
"globby": "^14.0.2",
|
"globby": "^14.0.2",
|
||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
@ -40,19 +41,19 @@
|
|||||||
"pathe": "^1.1.2",
|
"pathe": "^1.1.2",
|
||||||
"pkg-types": "^1.1.3",
|
"pkg-types": "^1.1.3",
|
||||||
"scule": "^1.3.0",
|
"scule": "^1.3.0",
|
||||||
"semver": "^7.6.2",
|
"semver": "^7.6.3",
|
||||||
"ufo": "^1.5.3",
|
"ufo": "^1.5.4",
|
||||||
"unctx": "^2.3.1",
|
"unctx": "^2.3.1",
|
||||||
"unimport": "^3.8.0",
|
"unimport": "^3.9.0",
|
||||||
"untyped": "^1.4.2"
|
"untyped": "^1.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/hash-sum": "1.0.2",
|
"@types/hash-sum": "1.0.2",
|
||||||
"@types/semver": "7.5.8",
|
"@types/semver": "7.5.8",
|
||||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28665895.e727afda",
|
"nitro": "npm:nitro-nightly@3.0.0-beta-28665895.e727afda",
|
||||||
"unbuild": "3.0.0-rc.6",
|
"unbuild": "3.0.0-rc.7",
|
||||||
"vite": "5.3.4",
|
"vite": "5.3.5",
|
||||||
"vitest": "2.0.3",
|
"vitest": "2.0.4",
|
||||||
"webpack": "5.93.0"
|
"webpack": "5.93.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { pathToFileURL } from 'node:url'
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||||
import { interopDefault, resolvePath, resolvePathSync } from 'mlly'
|
import { interopDefault, resolvePath, resolvePathSync } from 'mlly'
|
||||||
import { createJiti } from 'jiti'
|
import { createJiti } from 'jiti'
|
||||||
|
import { captureStackTrace } from 'errx'
|
||||||
|
|
||||||
export interface ResolveModuleOptions {
|
export interface ResolveModuleOptions {
|
||||||
paths?: string | string[]
|
paths?: string | string[]
|
||||||
@ -48,10 +49,12 @@ const warnings = new Set<string>()
|
|||||||
* @deprecated Please use `importModule` instead.
|
* @deprecated Please use `importModule` instead.
|
||||||
*/
|
*/
|
||||||
export function requireModule<T = unknown> (id: string, opts?: ImportModuleOptions) {
|
export function requireModule<T = unknown> (id: string, opts?: ImportModuleOptions) {
|
||||||
if (!warnings.has(id)) {
|
const { source, line, column } = captureStackTrace().find(entry => entry.source !== import.meta.url) ?? {}
|
||||||
// TODO: add more information on stack trace
|
const explanation = source ? ` (used at \`${fileURLToPath(source)}:${line}:${column}\`)` : ''
|
||||||
console.warn('[@nuxt/kit] `requireModule` is deprecated. Please use `importModule` instead.')
|
const warning = `[@nuxt/kit] \`requireModule\` is deprecated${explanation}. Please use \`importModule\` instead.`
|
||||||
warnings.add(id)
|
if (!warnings.has(warning)) {
|
||||||
|
console.warn(warning)
|
||||||
|
warnings.add(warning)
|
||||||
}
|
}
|
||||||
const resolvedPath = resolveModule(id, opts)
|
const resolvedPath = resolveModule(id, opts)
|
||||||
const jiti = createJiti(import.meta.url, {
|
const jiti = createJiti(import.meta.url, {
|
||||||
|
@ -158,6 +158,8 @@ export async function _generateTypes (nuxt: Nuxt) {
|
|||||||
const relative = relativeWithDot(nuxt.options.buildDir, path)
|
const relative = relativeWithDot(nuxt.options.buildDir, path)
|
||||||
include.add(join(relative, 'runtime'))
|
include.add(join(relative, 'runtime'))
|
||||||
exclude.add(join(relative, 'runtime/server'))
|
exclude.add(join(relative, 'runtime/server'))
|
||||||
|
include.add(join(relative, 'dist/runtime'))
|
||||||
|
exclude.add(join(relative, 'dist/runtime/server'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const isV4 = nuxt.options.future?.compatibilityVersion === 4
|
const isV4 = nuxt.options.future?.compatibilityVersion === 4
|
||||||
|
3
packages/nuxt/index.d.ts
vendored
3
packages/nuxt/index.d.ts
vendored
@ -12,7 +12,8 @@ declare global {
|
|||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
cookieStore?: {
|
cookieStore?: {
|
||||||
onchange: (event: any) => void
|
addEventListener: (type: 'change', listener: (event: any) => void) => void
|
||||||
|
removeEventListener: (type: 'change', listener: (event: any) => void) => void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,16 +68,17 @@
|
|||||||
"@unhead/dom": "^1.9.16",
|
"@unhead/dom": "^1.9.16",
|
||||||
"@unhead/ssr": "^1.9.16",
|
"@unhead/ssr": "^1.9.16",
|
||||||
"@unhead/vue": "^1.9.16",
|
"@unhead/vue": "^1.9.16",
|
||||||
"@vue/shared": "^3.4.31",
|
"@vue/shared": "^3.4.34",
|
||||||
"acorn": "8.12.1",
|
"acorn": "8.12.1",
|
||||||
"c12": "^2.0.0-beta.1",
|
"c12": "^2.0.0-beta.1",
|
||||||
"chokidar": "^3.6.0",
|
"chokidar": "^3.6.0",
|
||||||
"compatx": "^0.1.8",
|
"compatx": "^0.1.8",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"cookie-es": "^1.1.0",
|
"cookie-es": "^1.2.2",
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
"destr": "^2.0.3",
|
"destr": "^2.0.3",
|
||||||
"devalue": "^5.0.0",
|
"devalue": "^5.0.0",
|
||||||
|
"errx": "^0.1.0",
|
||||||
"esbuild": "^0.23.0",
|
"esbuild": "^0.23.0",
|
||||||
"escape-string-regexp": "^5.0.0",
|
"escape-string-regexp": "^5.0.0",
|
||||||
"estree-walker": "^3.0.3",
|
"estree-walker": "^3.0.3",
|
||||||
@ -100,20 +101,20 @@
|
|||||||
"pkg-types": "^1.1.3",
|
"pkg-types": "^1.1.3",
|
||||||
"radix3": "^1.1.2",
|
"radix3": "^1.1.2",
|
||||||
"scule": "^1.3.0",
|
"scule": "^1.3.0",
|
||||||
"semver": "^7.6.2",
|
"semver": "^7.6.3",
|
||||||
"std-env": "^3.7.0",
|
"std-env": "^3.7.0",
|
||||||
"strip-literal": "^2.1.0",
|
"strip-literal": "^2.1.0",
|
||||||
"ufo": "^1.5.3",
|
"ufo": "^1.5.4",
|
||||||
"ultrahtml": "^1.5.3",
|
"ultrahtml": "^1.5.3",
|
||||||
"uncrypto": "^0.1.3",
|
"uncrypto": "^0.1.3",
|
||||||
"unctx": "^2.3.1",
|
"unctx": "^2.3.1",
|
||||||
"unenv": "^1.9.0",
|
"unenv": "^1.10.0",
|
||||||
"unimport": "^3.8.0",
|
"unimport": "^3.9.0",
|
||||||
"unplugin": "^1.11.0",
|
"unplugin": "^1.12.0",
|
||||||
"unplugin-vue-router": "^0.10.0",
|
"unplugin-vue-router": "^0.10.1",
|
||||||
"unstorage": "^1.10.2",
|
"unstorage": "^1.10.2",
|
||||||
"untyped": "^1.4.2",
|
"untyped": "^1.4.2",
|
||||||
"vue": "^3.4.31",
|
"vue": "^3.4.34",
|
||||||
"vue-bundle-renderer": "^2.1.0",
|
"vue-bundle-renderer": "^2.1.0",
|
||||||
"vue-devtools-stub": "^0.1.0",
|
"vue-devtools-stub": "^0.1.0",
|
||||||
"vue-router": "^4.4.0"
|
"vue-router": "^4.4.0"
|
||||||
@ -123,11 +124,11 @@
|
|||||||
"@nuxt/ui-templates": "1.3.4",
|
"@nuxt/ui-templates": "1.3.4",
|
||||||
"@parcel/watcher": "2.4.1",
|
"@parcel/watcher": "2.4.1",
|
||||||
"@types/estree": "1.0.5",
|
"@types/estree": "1.0.5",
|
||||||
"@vitejs/plugin-vue": "5.0.5",
|
"@vitejs/plugin-vue": "5.1.0",
|
||||||
"@vue/compiler-sfc": "3.4.31",
|
"@vue/compiler-sfc": "3.4.34",
|
||||||
"unbuild": "3.0.0-rc.6",
|
"unbuild": "3.0.0-rc.7",
|
||||||
"vite": "5.3.4",
|
"vite": "5.3.5",
|
||||||
"vitest": "2.0.3"
|
"vitest": "2.0.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@parcel/watcher": "^2.1.0",
|
"@parcel/watcher": "^2.1.0",
|
||||||
|
@ -60,10 +60,10 @@ export interface AsyncDataOptions<
|
|||||||
default?: () => DefaultT | Ref<DefaultT>
|
default?: () => DefaultT | Ref<DefaultT>
|
||||||
/**
|
/**
|
||||||
* Provide a function which returns cached data.
|
* Provide a function which returns cached data.
|
||||||
* A `null` or `undefined` return value will trigger a fetch.
|
* An `undefined` return value will trigger a fetch.
|
||||||
* Default is `key => nuxt.isHydrating ? nuxt.payload.data[key] : nuxt.static.data[key]` which only caches data when payloadExtraction is enabled.
|
* Default is `key => nuxt.isHydrating ? nuxt.payload.data[key] : nuxt.static.data[key]` which only caches data when payloadExtraction is enabled.
|
||||||
*/
|
*/
|
||||||
getCachedData?: (key: string, nuxtApp: NuxtApp) => NoInfer<DataT>
|
getCachedData?: (key: string, nuxtApp: NuxtApp) => NoInfer<DataT> | undefined
|
||||||
/**
|
/**
|
||||||
* A function that can be used to alter handler function result after resolving.
|
* A function that can be used to alter handler function result after resolving.
|
||||||
* Do not use it along with the `pick` option.
|
* Do not use it along with the `pick` option.
|
||||||
@ -174,7 +174,7 @@ export function useAsyncData<
|
|||||||
* 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}
|
||||||
* @param key A unique key to ensure that data fetching can be properly de-duplicated across requests.
|
* @param key A unique key to ensure that data fetching can be properly de-duplicated across requests.
|
||||||
* @param handler An asynchronous function that must return a truthy value (for example, it should not be `undefined` or `null`) or the request may be duplicated on the client side.
|
* @param handler An asynchronous function that must return a value (it should not be `undefined`) or the request may be duplicated on the client side.
|
||||||
* @param options customize the behavior of useAsyncData
|
* @param options customize the behavior of useAsyncData
|
||||||
*/
|
*/
|
||||||
export function useAsyncData<
|
export function useAsyncData<
|
||||||
|
@ -83,13 +83,16 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
|||||||
const handleChange = (data: { value?: any, refresh?: boolean }) => {
|
const handleChange = (data: { value?: any, refresh?: boolean }) => {
|
||||||
const value = data.refresh ? readRawCookies(opts)?.[name] : opts.decode(data.value)
|
const value = data.refresh ? readRawCookies(opts)?.[name] : opts.decode(data.value)
|
||||||
watchPaused = true
|
watchPaused = true
|
||||||
cookies[name] = cookie.value = value
|
cookie.value = value
|
||||||
|
cookies[name] = klona(value)
|
||||||
nextTick(() => { watchPaused = false })
|
nextTick(() => { watchPaused = false })
|
||||||
}
|
}
|
||||||
|
|
||||||
let watchPaused = false
|
let watchPaused = false
|
||||||
|
|
||||||
if (getCurrentScope()) {
|
const hasScope = !!getCurrentScope()
|
||||||
|
|
||||||
|
if (hasScope) {
|
||||||
onScopeDispose(() => {
|
onScopeDispose(() => {
|
||||||
watchPaused = true
|
watchPaused = true
|
||||||
callback()
|
callback()
|
||||||
@ -98,10 +101,14 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (store) {
|
if (store) {
|
||||||
store.onchange = (event) => {
|
const changeHandler = (event: any) => {
|
||||||
const cookie = event.changed.find((c: any) => c.name === name)
|
const cookie = event.changed.find((c: any) => c.name === name)
|
||||||
if (cookie) { handleChange({ value: cookie.value }) }
|
if (cookie) { handleChange({ value: cookie.value }) }
|
||||||
}
|
}
|
||||||
|
store.addEventListener('change', changeHandler)
|
||||||
|
if (hasScope) {
|
||||||
|
onScopeDispose(() => store.removeEventListener('change', changeHandler))
|
||||||
|
}
|
||||||
} else if (channel) {
|
} else if (channel) {
|
||||||
channel.onmessage = ({ data }) => handleChange(data)
|
channel.onmessage = ({ data }) => handleChange(data)
|
||||||
}
|
}
|
||||||
@ -119,6 +126,16 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
|||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
const writeFinalCookieValue = () => {
|
const writeFinalCookieValue = () => {
|
||||||
if (opts.readonly || isEqual(cookie.value, cookies[name])) { return }
|
if (opts.readonly || isEqual(cookie.value, cookies[name])) { return }
|
||||||
|
nuxtApp._cookies ||= {}
|
||||||
|
if (name in nuxtApp._cookies) {
|
||||||
|
// do not append a second `set-cookie` header
|
||||||
|
if (isEqual(cookie.value, nuxtApp._cookies[name])) { return }
|
||||||
|
// warn in dev mode
|
||||||
|
if (import.meta.dev) {
|
||||||
|
console.warn(`[nuxt] cookie \`${name}\` was previously set to \`${opts.encode(nuxtApp._cookies[name] as any)}\` and is being overridden to \`${opts.encode(cookie.value as any)}\`. This may cause unexpected issues.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nuxtApp._cookies[name] = cookie.value
|
||||||
writeServerCookie(useRequestEvent(nuxtApp)!, name, cookie.value, opts as CookieOptions<any>)
|
writeServerCookie(useRequestEvent(nuxtApp)!, name, cookie.value, opts as CookieOptions<any>)
|
||||||
}
|
}
|
||||||
const unhook = nuxtApp.hooks.hookOnce('app:rendered', writeFinalCookieValue)
|
const unhook = nuxtApp.hooks.hookOnce('app:rendered', writeFinalCookieValue)
|
||||||
|
@ -45,6 +45,10 @@ export function useScriptCloudflareWebAnalytics (...args: unknown[]) {
|
|||||||
renderStubMessage('useScriptCloudflareWebAnalytics')
|
renderStubMessage('useScriptCloudflareWebAnalytics')
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
export function useScriptCrisp (...args: unknown[]) {
|
||||||
|
renderStubMessage('useScriptCrisp')
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
export function useScriptFathomAnalytics (...args: unknown[]) {
|
export function useScriptFathomAnalytics (...args: unknown[]) {
|
||||||
renderStubMessage('useScriptFathomAnalytics')
|
renderStubMessage('useScriptFathomAnalytics')
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,8 @@ interface _NuxtApp {
|
|||||||
|
|
||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_cookies?: Record<string, unknown>
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_id?: number
|
_id?: number
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { createConsola } from 'consola'
|
import { createConsola } from 'consola'
|
||||||
import type { LogObject } from 'consola'
|
import type { LogObject } from 'consola'
|
||||||
import { parse } from 'devalue'
|
import { parse } from 'devalue'
|
||||||
|
import type { ParsedTrace } from 'errx'
|
||||||
|
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
import { defineNuxtPlugin } from '../nuxt'
|
import { defineNuxtPlugin } from '../nuxt'
|
||||||
@ -45,15 +46,24 @@ export default defineNuxtPlugin(async (nuxtApp) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function normalizeFilenames (stack?: string) {
|
function normalizeFilenames (stack?: ParsedTrace[]) {
|
||||||
stack = stack?.split('\n')[0] || ''
|
if (!stack) {
|
||||||
stack = stack.replace(`${devRootDir}/`, '')
|
return ''
|
||||||
stack = stack.replace(/:\d+:\d+\)?$/, '')
|
}
|
||||||
return stack
|
let message = ''
|
||||||
|
for (const item of stack) {
|
||||||
|
const source = item.source.replace(`${devRootDir}/`, '')
|
||||||
|
if (item.function) {
|
||||||
|
message += ` at ${item.function} (${source})\n`
|
||||||
|
} else {
|
||||||
|
message += ` at ${source}\n`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return message
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeServerLog (log: LogObject) {
|
function normalizeServerLog (log: LogObject) {
|
||||||
log.additional = normalizeFilenames(log.stack as string)
|
log.additional = normalizeFilenames(log.stack as ParsedTrace[])
|
||||||
log.tag = 'ssr'
|
log.tag = 'ssr'
|
||||||
delete log.stack
|
delete log.stack
|
||||||
return log
|
return log
|
||||||
|
@ -4,7 +4,13 @@ import ClientOnly from '#app/components/client-only'
|
|||||||
|
|
||||||
/* @__NO_SIDE_EFFECTS__ */
|
/* @__NO_SIDE_EFFECTS__ */
|
||||||
export const createClientPage = (loader: AsyncComponentLoader) => {
|
export const createClientPage = (loader: AsyncComponentLoader) => {
|
||||||
const page = defineAsyncComponent(loader)
|
const page = defineAsyncComponent(import.meta.dev
|
||||||
|
? () => loader().then((m) => {
|
||||||
|
// mark component as client-only for `definePageMeta`
|
||||||
|
(m.default || m).__clientOnlyPage = true
|
||||||
|
return m.default || m
|
||||||
|
})
|
||||||
|
: loader)
|
||||||
|
|
||||||
return defineComponent({
|
return defineComponent({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
|
@ -5,6 +5,8 @@ import { stringify } from 'devalue'
|
|||||||
import type { H3Event } from 'h3'
|
import type { H3Event } from 'h3'
|
||||||
import { withTrailingSlash } from 'ufo'
|
import { withTrailingSlash } from 'ufo'
|
||||||
import { getContext } from 'unctx'
|
import { getContext } from 'unctx'
|
||||||
|
import { captureRawStackTrace, parseRawStackTrace } from 'errx'
|
||||||
|
import type { ParsedTrace } from 'errx'
|
||||||
|
|
||||||
import { isVNode } from 'vue'
|
import { isVNode } from 'vue'
|
||||||
import type { NitroApp } from 'nitro/types'
|
import type { NitroApp } from 'nitro/types'
|
||||||
@ -34,15 +36,28 @@ export default (nitroApp: NitroApp) => {
|
|||||||
const ctx = asyncContext.tryUse()
|
const ctx = asyncContext.tryUse()
|
||||||
if (!ctx) { return }
|
if (!ctx) { return }
|
||||||
|
|
||||||
const stack = getStack()
|
const rawStack = captureRawStackTrace()
|
||||||
if (stack.includes('runtime/vite-node.mjs')) { return }
|
if (!rawStack || rawStack.includes('runtime/vite-node.mjs')) { return }
|
||||||
|
|
||||||
|
const trace: ParsedTrace[] = []
|
||||||
|
let filename = ''
|
||||||
|
for (const entry of parseRawStackTrace(rawStack)) {
|
||||||
|
if (entry.source === import.meta.url) { continue }
|
||||||
|
if (EXCLUDE_TRACE_RE.test(entry.source)) { continue }
|
||||||
|
|
||||||
|
filename ||= entry.source.replace(withTrailingSlash(rootDir), '')
|
||||||
|
trace.push({
|
||||||
|
...entry,
|
||||||
|
source: entry.source.startsWith('file://') ? entry.source.replace('file://', '') : entry.source,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const log = {
|
const log = {
|
||||||
..._log,
|
..._log,
|
||||||
// Pass along filename to allow the client to display more info about where log comes from
|
// Pass along filename to allow the client to display more info about where log comes from
|
||||||
filename: extractFilenameFromStack(stack),
|
filename,
|
||||||
// Clean up file names in stack trace
|
// Clean up file names in stack trace
|
||||||
stack: normalizeFilenames(stack),
|
stack: trace,
|
||||||
}
|
}
|
||||||
|
|
||||||
// retain log to be include in the next render
|
// retain log to be include in the next render
|
||||||
@ -68,24 +83,7 @@ export default (nitroApp: NitroApp) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const EXCLUDE_TRACE_RE = /^.*at.*(\/node_modules\/(.*\/)?(nuxt|nuxt-nightly|nuxt-edge|nuxt3|consola|@vue)\/.*|core\/runtime\/nitro.*)$\n?/gm
|
const EXCLUDE_TRACE_RE = /\/node_modules\/(?:.*\/)?(?:nuxt|nuxt-nightly|nuxt-edge|nuxt3|consola|@vue)\/|core\/runtime\/nitro/
|
||||||
function getStack () {
|
|
||||||
// Pass along stack traces if needed (for error and warns)
|
|
||||||
// eslint-disable-next-line unicorn/error-message
|
|
||||||
const stack = new Error()
|
|
||||||
Error.captureStackTrace(stack)
|
|
||||||
return stack.stack?.replace(EXCLUDE_TRACE_RE, '').replace(/^Error.*\n/, '') || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
const FILENAME_RE = /at[^(]*\(([^:)]+)[):]/
|
|
||||||
const FILENAME_RE_GLOBAL = /at[^(]*\(([^)]+)\)/g
|
|
||||||
function extractFilenameFromStack (stacktrace: string) {
|
|
||||||
return stacktrace.match(FILENAME_RE)?.[1].replace(withTrailingSlash(rootDir), '')
|
|
||||||
}
|
|
||||||
function normalizeFilenames (stacktrace: string) {
|
|
||||||
// remove line numbers and file: protocol - TODO: sourcemap support for line numbers
|
|
||||||
return stacktrace.replace(FILENAME_RE_GLOBAL, (match, filename) => match.replace(filename, filename.replace('file:///', '/').replace(/:.*$/, '')))
|
|
||||||
}
|
|
||||||
|
|
||||||
function onConsoleLog (callback: (log: LogObject) => void) {
|
function onConsoleLog (callback: (log: LogObject) => void) {
|
||||||
consola.addReporter({
|
consola.addReporter({
|
||||||
|
@ -115,29 +115,34 @@ function normalizeError (error: any) {
|
|||||||
// temp fix for https://github.com/unjs/nitro/issues/759
|
// temp fix for https://github.com/unjs/nitro/issues/759
|
||||||
// TODO: investigate vercel-edge not using unenv pollyfill
|
// TODO: investigate vercel-edge not using unenv pollyfill
|
||||||
const cwd = typeof process.cwd === 'function' ? process.cwd() : '/'
|
const cwd = typeof process.cwd === 'function' ? process.cwd() : '/'
|
||||||
const stack = ((error.stack as string) || '')
|
|
||||||
.split('\n')
|
// Hide details of unhandled/fatal errors in production
|
||||||
.splice(1)
|
const hideDetails = !import.meta.dev && error.unhandled
|
||||||
.filter(line => line.includes('at '))
|
|
||||||
.map((line) => {
|
const stack = hideDetails
|
||||||
const text = line
|
? []
|
||||||
.replace(cwd + '/', './')
|
: ((error.stack as string) || '')
|
||||||
.replace('webpack:/', '')
|
.split('\n')
|
||||||
.replace('file://', '')
|
.splice(1)
|
||||||
.trim()
|
.filter(line => line.includes('at '))
|
||||||
return {
|
.map((line) => {
|
||||||
text,
|
const text = line
|
||||||
internal:
|
.replace(cwd + '/', './')
|
||||||
(line.includes('node_modules') && !line.includes('.cache')) ||
|
.replace('webpack:/', '')
|
||||||
line.includes('internal') ||
|
.replace('file://', '')
|
||||||
line.includes('new Promise'),
|
.trim()
|
||||||
}
|
return {
|
||||||
})
|
text,
|
||||||
|
internal:
|
||||||
|
(line.includes('node_modules') && !line.includes('.cache')) ||
|
||||||
|
line.includes('internal') ||
|
||||||
|
line.includes('new Promise'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const statusCode = error.statusCode || 500
|
const statusCode = error.statusCode || 500
|
||||||
const statusMessage =
|
const statusMessage = error.statusMessage ?? (statusCode === 404 ? 'Not Found' : '')
|
||||||
error.statusMessage ?? (statusCode === 404 ? 'Not Found' : '')
|
const message = hideDetails ? 'internal server error' : (error.message || error.toString())
|
||||||
const message = error.message || error.toString()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stack,
|
stack,
|
||||||
|
@ -60,7 +60,7 @@ export const definePageMeta = (meta: PageMeta): void => {
|
|||||||
try {
|
try {
|
||||||
const isRouteComponent = component && useRoute().matched.some(p => Object.values(p.components || {}).includes(component))
|
const isRouteComponent = component && useRoute().matched.some(p => Object.values(p.components || {}).includes(component))
|
||||||
const isRenderingServerPage = import.meta.server && useNuxtApp().ssrContext?.islandContext
|
const isRenderingServerPage = import.meta.server && useNuxtApp().ssrContext?.islandContext
|
||||||
if (isRouteComponent || isRenderingServerPage) {
|
if (isRouteComponent || isRenderingServerPage || ((component as any)?.__clientOnlyPage)) {
|
||||||
// don't warn if it's being used in a route component (or server page)
|
// don't warn if it's being used in a route component (or server page)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,12 @@ export async function augmentPages (routes: NuxtPage[], vfs: Record<string, stri
|
|||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
if (route.file && !augmentedPages.has(route.file)) {
|
if (route.file && !augmentedPages.has(route.file)) {
|
||||||
const fileContent = route.file in vfs ? vfs[route.file] : fs.readFileSync(await resolvePath(route.file), 'utf-8')
|
const fileContent = route.file in vfs ? vfs[route.file] : fs.readFileSync(await resolvePath(route.file), 'utf-8')
|
||||||
Object.assign(route, await getRouteMeta(fileContent, route.file))
|
const routeMeta = await getRouteMeta(fileContent, route.file)
|
||||||
|
if (route.meta) {
|
||||||
|
routeMeta.meta = { ...routeMeta.meta, ...route.meta }
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(route, routeMeta)
|
||||||
augmentedPages.add(route.file)
|
augmentedPages.add(route.file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,16 @@
|
|||||||
"path": ""/"",
|
"path": ""/"",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
"route.meta generated from file": [
|
||||||
|
{
|
||||||
|
"alias": "mockMeta?.alias || []",
|
||||||
|
"component": "() => import("pages/page-with-meta.vue").then(m => m.default || m)",
|
||||||
|
"meta": "{ ...(mockMeta || {}), ...{"test":1} }",
|
||||||
|
"name": "mockMeta?.name ?? "page-with-meta"",
|
||||||
|
"path": "mockMeta?.path ?? "/page-with-meta"",
|
||||||
|
"redirect": "mockMeta?.redirect",
|
||||||
|
},
|
||||||
|
],
|
||||||
"should allow pages with `:` in their path": [
|
"should allow pages with `:` in their path": [
|
||||||
{
|
{
|
||||||
"alias": "mockMeta?.alias || []",
|
"alias": "mockMeta?.alias || []",
|
||||||
@ -349,6 +359,16 @@
|
|||||||
"redirect": "mockMeta?.redirect",
|
"redirect": "mockMeta?.redirect",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
"should merge route.meta with meta from file": [
|
||||||
|
{
|
||||||
|
"alias": "mockMeta?.alias || []",
|
||||||
|
"component": "() => import("pages/page-with-meta.vue").then(m => m.default || m)",
|
||||||
|
"meta": "{ ...(mockMeta || {}), ...{"test":1} }",
|
||||||
|
"name": "mockMeta?.name ?? "page-with-meta"",
|
||||||
|
"path": "mockMeta?.path ?? "/page-with-meta"",
|
||||||
|
"redirect": "mockMeta?.redirect",
|
||||||
|
},
|
||||||
|
],
|
||||||
"should not generate colliding route names when hyphens are in file name": [
|
"should not generate colliding route names when hyphens are in file name": [
|
||||||
{
|
{
|
||||||
"alias": "mockMeta?.alias || []",
|
"alias": "mockMeta?.alias || []",
|
||||||
|
@ -16,6 +16,14 @@
|
|||||||
"path": ""/"",
|
"path": ""/"",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
"route.meta generated from file": [
|
||||||
|
{
|
||||||
|
"component": "() => import("pages/page-with-meta.vue").then(m => m.default || m)",
|
||||||
|
"meta": "{"test":1}",
|
||||||
|
"name": ""page-with-meta"",
|
||||||
|
"path": ""/page-with-meta"",
|
||||||
|
},
|
||||||
|
],
|
||||||
"should allow pages with `:` in their path": [
|
"should allow pages with `:` in their path": [
|
||||||
{
|
{
|
||||||
"component": "() => import("pages/test:name.vue").then(m => m.default || m)",
|
"component": "() => import("pages/test:name.vue").then(m => m.default || m)",
|
||||||
@ -240,6 +248,14 @@
|
|||||||
"path": ""/"",
|
"path": ""/"",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
"should merge route.meta with meta from file": [
|
||||||
|
{
|
||||||
|
"component": "() => import("pages/page-with-meta.vue").then(m => m.default || m)",
|
||||||
|
"meta": "{ ...(mockMeta || {}), ...{"test":1} }",
|
||||||
|
"name": ""page-with-meta"",
|
||||||
|
"path": ""/page-with-meta"",
|
||||||
|
},
|
||||||
|
],
|
||||||
"should not generate colliding route names when hyphens are in file name": [
|
"should not generate colliding route names when hyphens are in file name": [
|
||||||
{
|
{
|
||||||
"component": "() => import("pages/parent/[child].vue").then(m => m.default || m)",
|
"component": "() => import("pages/parent/[child].vue").then(m => m.default || m)",
|
||||||
|
@ -20,7 +20,7 @@ describe('pages:generateRoutesFromFiles', () => {
|
|||||||
|
|
||||||
const tests: Array<{
|
const tests: Array<{
|
||||||
description: string
|
description: string
|
||||||
files?: Array<{ path: string, template?: string }>
|
files?: Array<{ path: string, template?: string, meta?: Record<string, any> }>
|
||||||
output?: NuxtPage[]
|
output?: NuxtPage[]
|
||||||
normalized?: Record<string, any>[]
|
normalized?: Record<string, any>[]
|
||||||
error?: string
|
error?: string
|
||||||
@ -554,6 +554,53 @@ describe('pages:generateRoutesFromFiles', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: 'route.meta generated from file',
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
path: `${pagesDir}/page-with-meta.vue`,
|
||||||
|
meta: {
|
||||||
|
test: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
name: 'page-with-meta',
|
||||||
|
path: '/page-with-meta',
|
||||||
|
file: `${pagesDir}/page-with-meta.vue`,
|
||||||
|
children: [],
|
||||||
|
meta: { test: 1 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'should merge route.meta with meta from file',
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
path: `${pagesDir}/page-with-meta.vue`,
|
||||||
|
meta: {
|
||||||
|
test: 1,
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<script setup lang="ts">
|
||||||
|
definePageMeta({
|
||||||
|
hello: 'world'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
name: 'page-with-meta',
|
||||||
|
path: '/page-with-meta',
|
||||||
|
file: `${pagesDir}/page-with-meta.vue`,
|
||||||
|
children: [],
|
||||||
|
meta: { [DYNAMIC_META_KEY]: new Set(['meta']), test: 1 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const normalizedResults: Record<string, any> = {}
|
const normalizedResults: Record<string, any> = {}
|
||||||
@ -572,7 +619,13 @@ describe('pages:generateRoutesFromFiles', () => {
|
|||||||
shouldUseServerComponents: true,
|
shouldUseServerComponents: true,
|
||||||
absolutePath: file.path,
|
absolutePath: file.path,
|
||||||
relativePath: file.path.replace(/^(pages|layer\/pages)\//, ''),
|
relativePath: file.path.replace(/^(pages|layer\/pages)\//, ''),
|
||||||
})))
|
}))).map((route, index) => {
|
||||||
|
return {
|
||||||
|
...route,
|
||||||
|
meta: test.files![index].meta,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
await augmentPages(result, vfs)
|
await augmentPages(result, vfs)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
expect(error.message).toEqual(test.error)
|
expect(error.message).toEqual(test.error)
|
||||||
|
@ -40,27 +40,27 @@
|
|||||||
"@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.16",
|
"@unhead/schema": "1.9.16",
|
||||||
"@vitejs/plugin-vue": "5.0.5",
|
"@vitejs/plugin-vue": "5.1.0",
|
||||||
"@vitejs/plugin-vue-jsx": "4.0.0",
|
"@vitejs/plugin-vue-jsx": "4.0.0",
|
||||||
"@vue/compiler-core": "3.4.31",
|
"@vue/compiler-core": "3.4.34",
|
||||||
"@vue/compiler-sfc": "3.4.31",
|
"@vue/compiler-sfc": "3.4.34",
|
||||||
"@vue/language-core": "2.0.26",
|
"@vue/language-core": "2.0.29",
|
||||||
"c12": "2.0.0-beta.1",
|
"c12": "2.0.0-beta.1",
|
||||||
"esbuild-loader": "4.2.2",
|
"esbuild-loader": "4.2.2",
|
||||||
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
|
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
|
||||||
"ignore": "5.3.1",
|
"ignore": "5.3.1",
|
||||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28665895.e727afda",
|
"nitro": "npm:nitro-nightly@3.0.0-beta-28665895.e727afda",
|
||||||
"ofetch": "1.3.4",
|
"ofetch": "1.3.4",
|
||||||
"unbuild": "3.0.0-rc.6",
|
"unbuild": "3.0.0-rc.7",
|
||||||
"unctx": "2.3.1",
|
"unctx": "2.3.1",
|
||||||
"unenv": "1.9.0",
|
"unenv": "1.10.0",
|
||||||
"vite": "5.3.4",
|
"vite": "5.3.5",
|
||||||
"vue": "3.4.31",
|
"vue": "3.4.34",
|
||||||
"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.4.0",
|
"vue-router": "4.4.0",
|
||||||
"webpack": "5.93.0",
|
"webpack": "5.93.0",
|
||||||
"webpack-dev-middleware": "7.2.1"
|
"webpack-dev-middleware": "7.3.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"compatx": "^0.1.8",
|
"compatx": "^0.1.8",
|
||||||
@ -71,9 +71,9 @@
|
|||||||
"pkg-types": "^1.1.3",
|
"pkg-types": "^1.1.3",
|
||||||
"scule": "^1.3.0",
|
"scule": "^1.3.0",
|
||||||
"std-env": "^3.7.0",
|
"std-env": "^3.7.0",
|
||||||
"ufo": "^1.5.3",
|
"ufo": "^1.5.4",
|
||||||
"uncrypto": "^0.1.3",
|
"uncrypto": "^0.1.3",
|
||||||
"unimport": "^3.8.0",
|
"unimport": "^3.9.0",
|
||||||
"untyped": "^1.4.2"
|
"untyped": "^1.4.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -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 { basename, join, relative, resolve } from 'pathe'
|
import { basename, 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'
|
||||||
@ -158,7 +158,7 @@ export default defineUntypedSchema({
|
|||||||
$resolve: async (val: string | undefined, get): Promise<string> => {
|
$resolve: async (val: string | undefined, get): Promise<string> => {
|
||||||
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
||||||
|
|
||||||
return resolve(await get('rootDir') as string, (val || isV4) ? 'server' : resolve(await get('srcDir') as string, 'server'))
|
return resolve(isV4 ? await get('rootDir') as string : await get('srcDir') as string, val ?? 'server')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ export default defineUntypedSchema({
|
|||||||
'@': srcDir,
|
'@': srcDir,
|
||||||
'~~': rootDir,
|
'~~': rootDir,
|
||||||
'@@': rootDir,
|
'@@': rootDir,
|
||||||
[basename(assetsDir)]: join(srcDir, assetsDir),
|
[basename(assetsDir)]: resolve(srcDir, assetsDir),
|
||||||
[basename(publicDir)]: resolve(srcDir, publicDir),
|
[basename(publicDir)]: resolve(srcDir, publicDir),
|
||||||
...val,
|
...val,
|
||||||
}
|
}
|
||||||
@ -554,7 +554,7 @@ export default defineUntypedSchema({
|
|||||||
* ```js
|
* ```js
|
||||||
* export default {
|
* export default {
|
||||||
* runtimeConfig: {
|
* runtimeConfig: {
|
||||||
* apiKey: '' // Default to an empty string, automatically set at runtime using process.env.NUXT_API_KEY
|
* apiKey: '', // Default to an empty string, automatically set at runtime using process.env.NUXT_API_KEY
|
||||||
* public: {
|
* public: {
|
||||||
* baseURL: '' // Exposed to the frontend as well.
|
* baseURL: '' // Exposed to the frontend as well.
|
||||||
* }
|
* }
|
||||||
|
@ -6,7 +6,7 @@ export default defineUntypedSchema({
|
|||||||
/**
|
/**
|
||||||
* Whether to enable HTTPS.
|
* Whether to enable HTTPS.
|
||||||
* @example
|
* @example
|
||||||
* ```
|
* ```ts
|
||||||
* export default defineNuxtConfig({
|
* export default defineNuxtConfig({
|
||||||
* devServer: {
|
* devServer: {
|
||||||
* https: {
|
* https: {
|
||||||
|
@ -77,6 +77,23 @@ describe('nuxt folder structure', () => {
|
|||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not override value from user for serverDir', async () => {
|
||||||
|
const result = await applyDefaults(NuxtConfigSchema, { future: { compatibilityVersion: 4 }, serverDir: '/myServer' })
|
||||||
|
expect(getDirs(result as unknown as NuxtOptions)).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"dir": {
|
||||||
|
"app": "<cwd>/app",
|
||||||
|
"modules": "<cwd>/modules",
|
||||||
|
"public": "<cwd>/public",
|
||||||
|
},
|
||||||
|
"rootDir": "<cwd>",
|
||||||
|
"serverDir": "/myServer",
|
||||||
|
"srcDir": "<cwd>/app",
|
||||||
|
"workspaceDir": "<cwd>",
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function getDirs (options: NuxtOptions) {
|
function getDirs (options: NuxtOptions) {
|
||||||
|
@ -19,18 +19,18 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/html-minifier": "4.0.5",
|
"@types/html-minifier": "4.0.5",
|
||||||
"@unocss/reset": "0.61.4",
|
"@unocss/reset": "0.61.5",
|
||||||
"critters": "0.0.24",
|
"critters": "0.0.24",
|
||||||
"execa": "9.3.0",
|
"execa": "9.3.0",
|
||||||
"globby": "14.0.2",
|
"globby": "14.0.2",
|
||||||
"html-minifier": "4.0.0",
|
"html-minifier": "4.0.0",
|
||||||
"html-validate": "8.20.1",
|
"html-validate": "8.21.0",
|
||||||
"jiti": "2.0.0-beta.3",
|
"jiti": "2.0.0-beta.3",
|
||||||
"knitwork": "1.1.0",
|
"knitwork": "1.1.0",
|
||||||
"pathe": "1.1.2",
|
"pathe": "1.1.2",
|
||||||
"prettier": "3.3.3",
|
"prettier": "3.3.3",
|
||||||
"scule": "1.3.0",
|
"scule": "1.3.0",
|
||||||
"unocss": "0.61.4",
|
"unocss": "0.61.5",
|
||||||
"vite": "5.3.4"
|
"vite": "5.3.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,14 +27,14 @@
|
|||||||
"@nuxt/schema": "workspace:*",
|
"@nuxt/schema": "workspace:*",
|
||||||
"@types/clear": "0.1.4",
|
"@types/clear": "0.1.4",
|
||||||
"@types/estree": "1.0.5",
|
"@types/estree": "1.0.5",
|
||||||
"rollup": "4.18.1",
|
"rollup": "4.19.0",
|
||||||
"unbuild": "3.0.0-rc.6",
|
"unbuild": "3.0.0-rc.7",
|
||||||
"vue": "3.4.31"
|
"vue": "3.4.34"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/kit": "workspace:*",
|
"@nuxt/kit": "workspace:*",
|
||||||
"@rollup/plugin-replace": "^5.0.7",
|
"@rollup/plugin-replace": "^5.0.7",
|
||||||
"@vitejs/plugin-vue": "^5.0.5",
|
"@vitejs/plugin-vue": "^5.1.0",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.0.0",
|
"@vitejs/plugin-vue-jsx": "^4.0.0",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"clear": "^0.1.0",
|
"clear": "^0.1.0",
|
||||||
@ -55,15 +55,15 @@
|
|||||||
"pathe": "^1.1.2",
|
"pathe": "^1.1.2",
|
||||||
"perfect-debounce": "^1.0.0",
|
"perfect-debounce": "^1.0.0",
|
||||||
"pkg-types": "^1.1.3",
|
"pkg-types": "^1.1.3",
|
||||||
"postcss": "^8.4.39",
|
"postcss": "^8.4.40",
|
||||||
"rollup-plugin-visualizer": "^5.12.0",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"std-env": "^3.7.0",
|
"std-env": "^3.7.0",
|
||||||
"strip-literal": "^2.1.0",
|
"strip-literal": "^2.1.0",
|
||||||
"ufo": "^1.5.3",
|
"ufo": "^1.5.4",
|
||||||
"unenv": "^1.9.0",
|
"unenv": "^1.10.0",
|
||||||
"unplugin": "^1.11.0",
|
"unplugin": "^1.12.0",
|
||||||
"vite": "^5.3.4",
|
"vite": "^5.3.5",
|
||||||
"vite-node": "^2.0.3",
|
"vite-node": "^2.0.4",
|
||||||
"vite-plugin-checker": "^0.7.2",
|
"vite-plugin-checker": "^0.7.2",
|
||||||
"vue-bundle-renderer": "^2.1.0"
|
"vue-bundle-renderer": "^2.1.0"
|
||||||
},
|
},
|
||||||
|
@ -44,13 +44,13 @@
|
|||||||
"knitwork": "^1.1.0",
|
"knitwork": "^1.1.0",
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
"magic-string": "^0.30.10",
|
"magic-string": "^0.30.10",
|
||||||
"memfs": "^4.9.3",
|
"memfs": "^4.9.4",
|
||||||
"mini-css-extract-plugin": "^2.9.0",
|
"mini-css-extract-plugin": "^2.9.0",
|
||||||
"mlly": "^1.7.1",
|
"mlly": "^1.7.1",
|
||||||
"ohash": "^1.1.3",
|
"ohash": "^1.1.3",
|
||||||
"pathe": "^1.1.2",
|
"pathe": "^1.1.2",
|
||||||
"pify": "^6.1.0",
|
"pify": "^6.1.0",
|
||||||
"postcss": "^8.4.39",
|
"postcss": "^8.4.40",
|
||||||
"postcss-import": "^16.1.0",
|
"postcss-import": "^16.1.0",
|
||||||
"postcss-import-resolver": "^2.0.0",
|
"postcss-import-resolver": "^2.0.0",
|
||||||
"postcss-loader": "^8.1.1",
|
"postcss-loader": "^8.1.1",
|
||||||
@ -58,15 +58,15 @@
|
|||||||
"pug-plain-loader": "^1.1.0",
|
"pug-plain-loader": "^1.1.0",
|
||||||
"std-env": "^3.7.0",
|
"std-env": "^3.7.0",
|
||||||
"time-fix-plugin": "^2.0.7",
|
"time-fix-plugin": "^2.0.7",
|
||||||
"ufo": "^1.5.3",
|
"ufo": "^1.5.4",
|
||||||
"unenv": "^1.9.0",
|
"unenv": "^1.10.0",
|
||||||
"unplugin": "^1.11.0",
|
"unplugin": "^1.12.0",
|
||||||
"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.93.0",
|
"webpack": "^5.93.0",
|
||||||
"webpack-bundle-analyzer": "^4.10.2",
|
"webpack-bundle-analyzer": "^4.10.2",
|
||||||
"webpack-dev-middleware": "^7.2.1",
|
"webpack-dev-middleware": "^7.3.0",
|
||||||
"webpack-hot-middleware": "^2.26.1",
|
"webpack-hot-middleware": "^2.26.1",
|
||||||
"webpack-virtual-modules": "^0.6.2",
|
"webpack-virtual-modules": "^0.6.2",
|
||||||
"webpackbar": "^6.0.1"
|
"webpackbar": "^6.0.1"
|
||||||
@ -78,9 +78,9 @@
|
|||||||
"@types/pify": "5.0.4",
|
"@types/pify": "5.0.4",
|
||||||
"@types/webpack-bundle-analyzer": "4.7.0",
|
"@types/webpack-bundle-analyzer": "4.7.0",
|
||||||
"@types/webpack-hot-middleware": "2.25.9",
|
"@types/webpack-hot-middleware": "2.25.9",
|
||||||
"rollup": "4.18.1",
|
"rollup": "4.19.0",
|
||||||
"unbuild": "3.0.0-rc.6",
|
"unbuild": "3.0.0-rc.7",
|
||||||
"vue": "3.4.31"
|
"vue": "3.4.34"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": "^3.3.4"
|
"vue": "^3.3.4"
|
||||||
|
2714
pnpm-lock.yaml
2714
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -533,8 +533,7 @@ describe('pages', () => {
|
|||||||
await clientInitialPage.waitForFunction(() => window.useNuxtApp?.()._route.fullPath === '/client-only-page/normal')
|
await clientInitialPage.waitForFunction(() => window.useNuxtApp?.()._route.fullPath === '/client-only-page/normal')
|
||||||
|
|
||||||
// that page should be client rendered
|
// that page should be client rendered
|
||||||
// TODO: investigate why multiple elements are appearing on page
|
expect(await clientInitialPage.locator('#server-rendered').textContent()).toMatchInlineSnapshot('"false"')
|
||||||
expect(await clientInitialPage.locator('#server-rendered').first().textContent()).toMatchInlineSnapshot('"false"')
|
|
||||||
// and not contain any errors or warnings
|
// and not contain any errors or warnings
|
||||||
expect(errors.length).toBe(0)
|
expect(errors.length).toBe(0)
|
||||||
|
|
||||||
@ -591,7 +590,7 @@ describe('nuxt composables', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
const cookies = res.headers.get('set-cookie')
|
const cookies = res.headers.get('set-cookie')
|
||||||
expect(cookies).toMatchInlineSnapshot('"set-in-plugin=true; Path=/, set=set; Path=/, browser-set=set; Path=/, browser-set-to-null=; Max-Age=0; Path=/, browser-set-to-null-with-default=; Max-Age=0; Path=/, browser-object-default=%7B%22foo%22%3A%22bar%22%7D; Path=/"')
|
expect(cookies).toMatchInlineSnapshot('"set-in-plugin=true; Path=/, accessed-with-default-value=default; Path=/, set=set; Path=/, browser-set=set; Path=/, browser-set-to-null=; Max-Age=0; Path=/, browser-set-to-null-with-default=; Max-Age=0; Path=/, browser-object-default=%7B%22foo%22%3A%22bar%22%7D; Path=/"')
|
||||||
})
|
})
|
||||||
it('updates cookies when they are changed', async () => {
|
it('updates cookies when they are changed', async () => {
|
||||||
const { page } = await renderPage('/cookies')
|
const { page } = await renderPage('/cookies')
|
||||||
|
@ -19,7 +19,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
for (const outputDir of ['.output', '.output-inline']) {
|
for (const outputDir of ['.output', '.output-inline']) {
|
||||||
it('default client bundle size', async () => {
|
it('default client bundle size', async () => {
|
||||||
const clientStats = await analyzeSizes('**/*.js', join(rootDir, outputDir, 'public'))
|
const clientStats = await analyzeSizes('**/*.js', join(rootDir, outputDir, 'public'))
|
||||||
expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot(`"106k"`)
|
expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot(`"107k"`)
|
||||||
expect(clientStats.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
|
expect(clientStats.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
|
||||||
[
|
[
|
||||||
"_nuxt/entry.js",
|
"_nuxt/entry.js",
|
||||||
@ -32,10 +32,10 @@ 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(`"205k"`)
|
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"211k"`)
|
||||||
|
|
||||||
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
||||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1344k"`)
|
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1347k"`)
|
||||||
|
|
||||||
const packages = modules.files
|
const packages = modules.files
|
||||||
.filter(m => m.endsWith('package.json'))
|
.filter(m => m.endsWith('package.json'))
|
||||||
@ -73,7 +73,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(`"526k"`)
|
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"534k"`)
|
||||||
|
|
||||||
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
||||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"80.3k"`)
|
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"80.3k"`)
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
definePageMeta({
|
||||||
|
// Disable page transition for this page to avoid having multiple time the same page during transition
|
||||||
|
pageTransition: false,
|
||||||
|
layoutTransition: false,
|
||||||
|
})
|
||||||
|
|
||||||
const state = useState('test', () => {
|
const state = useState('test', () => {
|
||||||
let hasAccessToWindow = null as null | boolean
|
let hasAccessToWindow = null as null | boolean
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const renderedOnServer = useState(() => import.meta.server)
|
const renderedOnServer = useState(() => import.meta.server)
|
||||||
|
definePageMeta({
|
||||||
|
// Disable page transition for this page to avoid having multiple time the same page during transition
|
||||||
|
pageTransition: false,
|
||||||
|
layoutTransition: false,
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
24
test/fixtures/basic/pages/cookies.vue
vendored
24
test/fixtures/basic/pages/cookies.vue
vendored
@ -1,28 +1,38 @@
|
|||||||
<script setup>
|
<script setup lang="ts">
|
||||||
useCookie('accessed-but-not-used')
|
useCookie('accessed-but-not-used')
|
||||||
useCookie('accessed-with-default-value', () => 'default')
|
useCookie('accessed-with-default-value', { default: () => 'default' })
|
||||||
useCookie('set').value = 'set'
|
useCookie('set').value = 'set'
|
||||||
useCookie('set-to-null').value = null
|
useCookie('set-to-null').value = null
|
||||||
useCookie('set-to-null-with-default', () => 'default').value = null
|
useCookie<string | null>('set-to-null-with-default', { default: () => 'default' }).value = null
|
||||||
|
|
||||||
// the next set are all sent by browser
|
// the next set are all sent by browser
|
||||||
useCookie('browser-accessed-but-not-used')
|
useCookie('browser-accessed-but-not-used')
|
||||||
useCookie('browser-accessed-with-default-value', () => 'default')
|
useCookie('browser-accessed-with-default-value', { default: () => 'default' })
|
||||||
|
useCookie('browser-set').value = 'set'
|
||||||
|
// confirm that it only sets one `set-cookie` header
|
||||||
useCookie('browser-set').value = 'set'
|
useCookie('browser-set').value = 'set'
|
||||||
useCookie('browser-set-to-null').value = null
|
useCookie('browser-set-to-null').value = null
|
||||||
useCookie('browser-set-to-null-with-default', () => 'default').value = null
|
useCookie<string | null>('browser-set-to-null-with-default', { default: () => 'default' }).value = null
|
||||||
|
|
||||||
const objectCookie = useCookie('browser-object-default')
|
const objectCookie = useCookie<{ foo: string } | undefined>('browser-object-default')
|
||||||
const objectCookieSecond = useCookie('browser-object-default', {
|
const objectCookieSecond = useCookie('browser-object-default', {
|
||||||
default: () => ({ foo: 'bar' }),
|
default: () => ({ foo: 'bar' }),
|
||||||
})
|
})
|
||||||
|
function changeCookie () {
|
||||||
|
if (objectCookie.value!.foo === 'baz') {
|
||||||
|
objectCookie.value!.foo = 'bar'
|
||||||
|
} else {
|
||||||
|
objectCookie.value!.foo = 'baz'
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div>cookies testing page</div>
|
<div>cookies testing page</div>
|
||||||
|
<pre>{{ objectCookie?.foo }}</pre>
|
||||||
<pre>{{ objectCookieSecond.foo }}</pre>
|
<pre>{{ objectCookieSecond.foo }}</pre>
|
||||||
<button @click="objectCookie.foo === 'baz' ? objectCookie.foo = 'bar' : objectCookie.foo = 'baz'">
|
<button @click="changeCookie">
|
||||||
Change cookie
|
Change cookie
|
||||||
</button>
|
</button>
|
||||||
<button @click="refreshCookie('browser-object-default')">
|
<button @click="refreshCookie('browser-object-default')">
|
||||||
|
Loading…
Reference in New Issue
Block a user