mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-21 16:09:52 +00:00
Merge branch 'main' into fix/cores_assets_chunks
This commit is contained in:
commit
a68b0a50cc
2
.github/workflows/autofix-docs.yml
vendored
2
.github/workflows/autofix-docs.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
|
2
.github/workflows/autofix.yml
vendored
2
.github/workflows/autofix.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
|
2
.github/workflows/changelog.yml
vendored
2
.github/workflows/changelog.yml
vendored
@ -26,7 +26,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
|
24
.github/workflows/ci.yml
vendored
24
.github/workflows/ci.yml
vendored
@ -39,7 +39,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
@ -78,7 +78,7 @@ jobs:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@ee117c905ab18f32fa0f66c2fe40ecc8013f3e04 # v3.28.4
|
||||
uses: github/codeql-action/init@17a820bf2e43b47be2c72b39cc905417bc1ab6d0 # v3.28.6
|
||||
with:
|
||||
config: |
|
||||
paths:
|
||||
@ -95,7 +95,7 @@ jobs:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@ee117c905ab18f32fa0f66c2fe40ecc8013f3e04 # v3.28.4
|
||||
uses: github/codeql-action/analyze@17a820bf2e43b47be2c72b39cc905417bc1ab6d0 # v3.28.6
|
||||
with:
|
||||
category: "/language:${{ matrix.language }}"
|
||||
|
||||
@ -113,7 +113,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
@ -144,7 +144,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
@ -171,7 +171,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
@ -196,7 +196,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
@ -221,7 +221,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
@ -281,7 +281,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
cache: "pnpm"
|
||||
@ -308,7 +308,7 @@ jobs:
|
||||
TEST_PAYLOAD: ${{ matrix.payload }}
|
||||
SKIP_BUNDLE_SIZE: true
|
||||
|
||||
- uses: codecov/codecov-action@0da7aa657d958d32c117fc47e1f977e7524753c7 # v5.3.0
|
||||
- uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1
|
||||
if: github.event_name != 'push' && matrix.env == 'built' && matrix.builder == 'vite' && matrix.context == 'default' && matrix.os == 'ubuntu-latest' && matrix.manifest == 'manifest-on'
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@ -333,7 +333,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
@ -365,7 +365,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
|
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
|
2
.github/workflows/lint-monorepo.yml
vendored
2
.github/workflows/lint-monorepo.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: "pnpm"
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
|
||||
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
registry-url: "https://registry.npmjs.org/"
|
||||
|
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@ee117c905ab18f32fa0f66c2fe40ecc8013f3e04 # v3.28.4
|
||||
uses: github/codeql-action/upload-sarif@17a820bf2e43b47be2c72b39cc905417bc1ab6d0 # v3.28.6
|
||||
if: github.repository == 'nuxt/nuxt' && success()
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
@ -126,6 +126,26 @@ This will produce three files:
|
||||
|
||||
The `200.html` and `404.html` might be useful for the hosting provider you are using.
|
||||
|
||||
#### Skipping Client Fallback Generation
|
||||
|
||||
When prerendering a client-rendered app, Nuxt will generate `index.html`, `200.html` and `404.html` files by default. However, if you need to prevent any (or all) of these files from being generated in your build, you can use the `'prerender:generate'` hook from [Nitro](/docs/getting-started/prerendering#prerendergenerate-nitro-hook).
|
||||
|
||||
```ts twoslash [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
ssr: false,
|
||||
nitro: {
|
||||
hooks: {
|
||||
'prerender:generate'(route) {
|
||||
const routesToSkip = ['/index.html', '/200.html', '/404.html']
|
||||
if (routesToSkip.includes(route.route)) {
|
||||
route.skip = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Hybrid Rendering
|
||||
|
||||
Hybrid rendering allows different caching rules per route using **Route Rules** and decides how the server should respond to a new request on a given URL.
|
||||
|
26
package.json
26
package.json
@ -37,7 +37,7 @@
|
||||
"typecheck:docs": "DOCS_TYPECHECK=true pnpm nuxi prepare && nuxt-content-twoslash verify --content-dir docs --languages html"
|
||||
},
|
||||
"resolutions": {
|
||||
"@babel/core": "7.26.0",
|
||||
"@babel/core": "7.26.7",
|
||||
"@babel/helper-plugin-utils": "7.26.5",
|
||||
"@nuxt/cli": "3.20.0",
|
||||
"@nuxt/kit": "workspace:*",
|
||||
@ -45,7 +45,7 @@
|
||||
"@nuxt/schema": "workspace:*",
|
||||
"@nuxt/vite-builder": "workspace:*",
|
||||
"@nuxt/webpack-builder": "workspace:*",
|
||||
"@types/node": "22.10.10",
|
||||
"@types/node": "22.12.0",
|
||||
"@unhead/dom": "1.11.18",
|
||||
"@unhead/schema": "1.11.18",
|
||||
"@unhead/shared": "1.11.18",
|
||||
@ -62,7 +62,7 @@
|
||||
"nuxt": "workspace:*",
|
||||
"ohash": "1.1.4",
|
||||
"postcss": "8.5.1",
|
||||
"rollup": "4.31.0",
|
||||
"rollup": "4.32.1",
|
||||
"send": ">=1.1.0",
|
||||
"typescript": "5.7.3",
|
||||
"ufo": "1.5.4",
|
||||
@ -74,7 +74,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@arethetypeswrong/cli": "0.17.3",
|
||||
"@babel/core": "7.26.0",
|
||||
"@babel/core": "7.26.7",
|
||||
"@babel/helper-plugin-utils": "7.26.5",
|
||||
"@codspeed/vitest-plugin": "4.0.0",
|
||||
"@nuxt/cli": "3.20.0",
|
||||
@ -86,11 +86,11 @@
|
||||
"@testing-library/vue": "8.1.0",
|
||||
"@types/babel__core": "7.20.5",
|
||||
"@types/babel__helper-plugin-utils": "7.10.3",
|
||||
"@types/node": "22.10.10",
|
||||
"@types/node": "22.12.0",
|
||||
"@types/semver": "7.5.8",
|
||||
"@unhead/schema": "1.11.18",
|
||||
"@unhead/vue": "1.11.18",
|
||||
"@vitest/coverage-v8": "3.0.3",
|
||||
"@vitest/coverage-v8": "3.0.4",
|
||||
"@vue/test-utils": "2.4.6",
|
||||
"acorn": "8.14.0",
|
||||
"autoprefixer": "10.4.20",
|
||||
@ -100,18 +100,18 @@
|
||||
"cssnano": "7.0.6",
|
||||
"destr": "2.0.3",
|
||||
"devalue": "5.1.1",
|
||||
"eslint": "9.18.0",
|
||||
"eslint": "9.19.0",
|
||||
"eslint-plugin-no-only-tests": "3.3.0",
|
||||
"eslint-plugin-perfectionist": "4.7.0",
|
||||
"eslint-typegen": "1.0.0",
|
||||
"estree-walker": "3.0.3",
|
||||
"h3": "npm:h3-nightly@1.14.0-20250122-114730-3f9e703",
|
||||
"happy-dom": "16.7.2",
|
||||
"happy-dom": "16.7.3",
|
||||
"installed-check": "9.3.0",
|
||||
"jiti": "2.4.2",
|
||||
"knip": "5.43.1",
|
||||
"knip": "5.43.6",
|
||||
"magic-string": "0.30.17",
|
||||
"markdownlint-cli": "0.43.0",
|
||||
"markdownlint-cli": "0.44.0",
|
||||
"memfs": "4.17.0",
|
||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28938837.19ec5395",
|
||||
"nuxt": "workspace:*",
|
||||
@ -120,9 +120,9 @@
|
||||
"pathe": "2.0.2",
|
||||
"pkg-pr-new": "0.0.39",
|
||||
"playwright-core": "1.50.0",
|
||||
"rollup": "4.31.0",
|
||||
"rollup": "4.32.1",
|
||||
"semver": "7.6.3",
|
||||
"sherif": "1.1.1",
|
||||
"sherif": "1.2.0",
|
||||
"std-env": "3.8.0",
|
||||
"tinyexec": "0.3.2",
|
||||
"tinyglobby": "0.2.10",
|
||||
@ -130,7 +130,7 @@
|
||||
"typescript": "5.7.3",
|
||||
"ufo": "1.5.4",
|
||||
"unbuild": "3.3.1",
|
||||
"vitest": "3.0.3",
|
||||
"vitest": "3.0.4",
|
||||
"vitest-environment-nuxt": "1.0.1",
|
||||
"vue": "3.5.13",
|
||||
"vue-tsc": "2.2.0",
|
||||
|
@ -27,7 +27,6 @@
|
||||
"test:attw": "attw --pack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/schema": "workspace:*",
|
||||
"c12": "^2.0.1",
|
||||
"consola": "^3.4.0",
|
||||
"defu": "^6.1.4",
|
||||
@ -50,12 +49,13 @@
|
||||
"untyped": "^1.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/schema": "workspace:*",
|
||||
"@rspack/core": "1.2.2",
|
||||
"@types/semver": "7.5.8",
|
||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28938837.19ec5395",
|
||||
"unbuild": "3.3.1",
|
||||
"vite": "6.0.11",
|
||||
"vitest": "3.0.3",
|
||||
"vitest": "3.0.4",
|
||||
"webpack": "5.97.1"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1,27 +1,21 @@
|
||||
import { existsSync } from 'node:fs'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import type { JSValue } from 'untyped'
|
||||
import { applyDefaults } from 'untyped'
|
||||
import type { ConfigLayer, ConfigLayerMeta, LoadConfigOptions } from 'c12'
|
||||
import { loadConfig } from 'c12'
|
||||
import type { NuxtConfig, NuxtOptions } from '@nuxt/schema'
|
||||
import { NuxtConfigSchema } from '@nuxt/schema'
|
||||
import { globby } from 'globby'
|
||||
import defu from 'defu'
|
||||
import { join } from 'pathe'
|
||||
import { isWindows } from 'std-env'
|
||||
import { tryResolveModule } from '../internal/esm'
|
||||
|
||||
export interface LoadNuxtConfigOptions extends Omit<LoadConfigOptions<NuxtConfig>, 'overrides'> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
overrides?: Exclude<LoadConfigOptions<NuxtConfig>['overrides'], Promise<any> | Function>
|
||||
}
|
||||
|
||||
const layerSchemaKeys = ['future', 'srcDir', 'rootDir', 'serverDir', 'dir']
|
||||
const layerSchema = Object.create(null)
|
||||
for (const key of layerSchemaKeys) {
|
||||
if (key in NuxtConfigSchema) {
|
||||
layerSchema[key] = NuxtConfigSchema[key]
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<NuxtOptions> {
|
||||
// Automatically detect and import layers from `~~/layers/` directory
|
||||
opts.overrides = defu(opts.overrides, {
|
||||
@ -54,6 +48,16 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
|
||||
nuxtConfig.buildDir = join(nuxtConfig.rootDir!, 'node_modules/.cache/nuxt/.nuxt')
|
||||
}
|
||||
|
||||
const NuxtConfigSchema = await loadNuxtSchema(nuxtConfig.rootDir || cwd || process.cwd())
|
||||
|
||||
const layerSchemaKeys = ['future', 'srcDir', 'rootDir', 'serverDir', 'dir']
|
||||
const layerSchema = Object.create(null)
|
||||
for (const key of layerSchemaKeys) {
|
||||
if (key in NuxtConfigSchema) {
|
||||
layerSchema[key] = NuxtConfigSchema[key]
|
||||
}
|
||||
}
|
||||
|
||||
const _layers: ConfigLayer<NuxtConfig, ConfigLayerMeta>[] = []
|
||||
const processedLayers = new Set<string>()
|
||||
for (const layer of layers) {
|
||||
@ -89,3 +93,13 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
|
||||
// Resolve and apply defaults
|
||||
return await applyDefaults(NuxtConfigSchema, nuxtConfig as NuxtConfig & Record<string, JSValue>) as unknown as NuxtOptions
|
||||
}
|
||||
|
||||
async function loadNuxtSchema (cwd: string) {
|
||||
const paths = [cwd]
|
||||
const nuxtPath = await tryResolveModule('nuxt', cwd) ?? await tryResolveModule('nuxt-nightly', cwd)
|
||||
if (nuxtPath) {
|
||||
paths.unshift(nuxtPath)
|
||||
}
|
||||
const schemaPath = await tryResolveModule('@nuxt/schema', paths) ?? '@nuxt/schema'
|
||||
return await import(isWindows ? pathToFileURL(schemaPath).href : schemaPath).then(r => r.NuxtConfigSchema)
|
||||
}
|
||||
|
76
packages/kit/src/runtime-config.test.ts
Normal file
76
packages/kit/src/runtime-config.test.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useRuntimeConfig } from './runtime-config'
|
||||
|
||||
const { useNuxt, klona } = vi.hoisted(() => ({ useNuxt: vi.fn(), klona: vi.fn() }))
|
||||
|
||||
vi.mock('./context', () => ({ useNuxt }))
|
||||
vi.mock('klona', () => ({ klona }))
|
||||
|
||||
const testCases = [
|
||||
{
|
||||
description:
|
||||
'should return runtime config with environment variables applied',
|
||||
runtimeConfig: {
|
||||
apiUrl: 'http://localhost',
|
||||
authUrl: 'http://auth.com',
|
||||
},
|
||||
envExpansion: true,
|
||||
env: {
|
||||
NITRO_API_URL: 'http://example.com',
|
||||
},
|
||||
expected: {
|
||||
apiUrl: 'http://example.com',
|
||||
authUrl: 'http://auth.com',
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'should expand environment variables in strings',
|
||||
runtimeConfig: {
|
||||
apiUrl: '{{BASE_URL}}/api',
|
||||
mail: '{{MAIL_SCHEME}}://{{MAIL_HOST}}:{{MAIL_PORT}}',
|
||||
},
|
||||
envExpansion: true,
|
||||
env: {
|
||||
BASE_URL: 'http://example.com',
|
||||
MAIL_SCHEME: 'http',
|
||||
MAIL_HOST: 'localhost',
|
||||
MAIL_PORT: '3366',
|
||||
},
|
||||
expected: {
|
||||
apiUrl: 'http://example.com/api',
|
||||
mail: 'http://localhost:3366',
|
||||
},
|
||||
},
|
||||
{
|
||||
description:
|
||||
'should not expand environment variables if envExpansion is false',
|
||||
runtimeConfig: {
|
||||
apiUrl: '{{BASE_URL}}/api',
|
||||
someUrl: '',
|
||||
},
|
||||
envExpansion: false,
|
||||
env: {
|
||||
BASE_URL: 'http://example1.com',
|
||||
NITRO_NOT_API_URL: 'http://example2.com',
|
||||
NUXT_SOME_URL: 'http://example3.com',
|
||||
},
|
||||
expected: {
|
||||
apiUrl: '{{BASE_URL}}/api',
|
||||
someUrl: 'http://example3.com',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
describe('useRuntimeConfig', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs()
|
||||
})
|
||||
|
||||
it.each(testCases)('$description', ({ runtimeConfig, envExpansion, env, expected }) => {
|
||||
useNuxt.mockReturnValue({ options: { nitro: { runtimeConfig, experimental: { envExpansion } } } })
|
||||
klona.mockReturnValue(runtimeConfig)
|
||||
Object.entries(env).forEach(([key, value]) => vi.stubEnv(key, value))
|
||||
|
||||
expect(useRuntimeConfig()).toEqual(expected)
|
||||
})
|
||||
})
|
@ -94,7 +94,7 @@ function applyEnv (
|
||||
return obj
|
||||
}
|
||||
|
||||
const envExpandRx = /\{\{(.*?)\}\}/g
|
||||
const envExpandRx = /\{\{([^{}]*)\}\}/g
|
||||
|
||||
function _expandFromEnv (value: string, env: Record<string, any> = process.env) {
|
||||
return value.replace(envExpandRx, (match, key) => {
|
||||
|
@ -101,7 +101,7 @@
|
||||
"mlly": "^1.7.4",
|
||||
"nanotar": "^0.2.0",
|
||||
"nitro": "npm:nitro-nightly@3.0.0-beta-28938837.19ec5395",
|
||||
"nypm": "^0.5.0",
|
||||
"nypm": "^0.5.2",
|
||||
"ofetch": "^1.4.1",
|
||||
"ohash": "^1.1.4",
|
||||
"pathe": "^2.0.2",
|
||||
@ -121,7 +121,7 @@
|
||||
"unhead": "^1.11.18",
|
||||
"unimport": "^4.0.0",
|
||||
"unplugin": "^2.1.2",
|
||||
"unplugin-vue-router": "^0.11.1",
|
||||
"unplugin-vue-router": "^0.11.2",
|
||||
"unstorage": "^1.14.4",
|
||||
"untyped": "^1.5.2",
|
||||
"vue": "^3.5.13",
|
||||
@ -131,13 +131,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/scripts": "0.9.5",
|
||||
"@parcel/watcher": "2.5.0",
|
||||
"@parcel/watcher": "2.5.1",
|
||||
"@types/estree": "1.0.6",
|
||||
"@vitejs/plugin-vue": "5.2.1",
|
||||
"@vue/compiler-sfc": "3.5.13",
|
||||
"unbuild": "3.3.1",
|
||||
"vite": "6.0.11",
|
||||
"vitest": "3.0.3"
|
||||
"vitest": "3.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@parcel/watcher": "^2.1.0",
|
||||
|
@ -132,10 +132,11 @@ export default defineComponent({
|
||||
ssrHTML.value = getFragmentHTML(instance.vnode.el, true)?.join('') || ''
|
||||
const key = `${props.name}_${hashId.value}`
|
||||
nuxtApp.payload.data[key] ||= {}
|
||||
nuxtApp.payload.data[key].html = ssrHTML.value
|
||||
// clear all data-island-uid to avoid conflicts when saving into payloads
|
||||
nuxtApp.payload.data[key].html = ssrHTML.value.replaceAll(new RegExp(`data-island-uid="${ssrHTML.value.match(SSR_UID_RE)?.[1] || ''}"`, 'g'), `data-island-uid=""`)
|
||||
}
|
||||
|
||||
const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] ?? getId())
|
||||
const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] || getId())
|
||||
const availableSlots = computed(() => [...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1]))
|
||||
const html = computed(() => {
|
||||
const currentSlots = Object.keys(slots)
|
||||
|
@ -1,12 +1,12 @@
|
||||
import type { DefineComponent, MaybeRef, VNode } from 'vue'
|
||||
import { Suspense, Transition, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from 'vue'
|
||||
import { Suspense, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from 'vue'
|
||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
|
||||
import type { PageMeta } from '../../pages/runtime/composables'
|
||||
|
||||
import { useRoute, useRouter } from '../composables/router'
|
||||
import { useNuxtApp } from '../nuxt'
|
||||
import { _wrapIf } from './utils'
|
||||
import { _wrapInTransition } from './utils'
|
||||
import { LayoutMetaSymbol, PageRouteSymbol } from './injections'
|
||||
|
||||
// @ts-expect-error virtual file
|
||||
@ -80,7 +80,7 @@ export default defineComponent({
|
||||
const transitionProps = route.meta.layoutTransition ?? defaultLayoutTransition
|
||||
|
||||
// We avoid rendering layout transition if there is no layout to render
|
||||
return _wrapIf(Transition, hasLayout && transitionProps, {
|
||||
return _wrapInTransition(hasLayout && transitionProps, {
|
||||
default: () => h(Suspense, { suspensible: true, onResolve: () => { nextTick(done) } }, {
|
||||
default: () => h(
|
||||
LayoutProvider,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createStaticVNode, h } from 'vue'
|
||||
import type { Component, RendererNode, VNode } from 'vue'
|
||||
import { Transition, createStaticVNode, h } from 'vue'
|
||||
import type { RendererNode, VNode } from 'vue'
|
||||
// eslint-disable-next-line
|
||||
import { isString, isPromise, isArray, isObject } from '@vue/shared'
|
||||
import type { RouteLocationNormalized } from 'vue-router'
|
||||
@ -10,9 +10,8 @@ import { START_LOCATION } from '#build/pages'
|
||||
* Internal utility
|
||||
* @private
|
||||
*/
|
||||
export const _wrapIf = (component: Component, props: any, slots: any) => {
|
||||
props = props === true ? {} : props
|
||||
return { default: () => props ? h(component, props, slots) : slots.default?.() }
|
||||
export const _wrapInTransition = (props: any, children: any) => {
|
||||
return { default: () => import.meta.client && props ? h(Transition, props === true ? {} : props, children) : children.default?.() }
|
||||
}
|
||||
|
||||
const ROUTE_KEY_PARENTHESES_RE = /(:\w+)\([^)]+\)/g
|
||||
|
@ -108,6 +108,18 @@ function createWatcher () {
|
||||
ignored: [isIgnored, /[\\/]node_modules[\\/]/],
|
||||
})
|
||||
|
||||
const restartPaths = new Set<string>()
|
||||
const srcDir = nuxt.options.srcDir.replace(/\/?$/, '/')
|
||||
for (const pattern of nuxt.options.watch) {
|
||||
if (typeof pattern !== 'string') { continue }
|
||||
const path = resolve(nuxt.options.srcDir, pattern)
|
||||
if (!path.startsWith(srcDir)) {
|
||||
restartPaths.add(path)
|
||||
}
|
||||
}
|
||||
|
||||
watcher.add([...restartPaths])
|
||||
|
||||
watcher.on('all', (event, path) => {
|
||||
if (event === 'all' || event === 'ready' || event === 'error' || event === 'raw') {
|
||||
return
|
||||
|
@ -83,7 +83,6 @@ const nightlies = {
|
||||
|
||||
export const keyDependencies = [
|
||||
'@nuxt/kit',
|
||||
'@nuxt/schema',
|
||||
]
|
||||
|
||||
let warnedAboutCompatDate = false
|
||||
@ -414,7 +413,7 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
await nuxt.callHook('modules:before')
|
||||
const modulesToInstall = new Map<string | NuxtModule, Record<string, any>>()
|
||||
|
||||
const watchedPaths = new Set<string>()
|
||||
const modulePaths = new Set<string>()
|
||||
const specifiedModules = new Set<string>()
|
||||
|
||||
for (const _mod of nuxt.options.modules) {
|
||||
@ -432,13 +431,15 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
`${modulesDir}/*/index{${nuxt.options.extensions.join(',')}}`,
|
||||
])
|
||||
for (const mod of layerModules) {
|
||||
watchedPaths.add(mod)
|
||||
modulePaths.add(mod)
|
||||
if (specifiedModules.has(mod)) { continue }
|
||||
specifiedModules.add(mod)
|
||||
modulesToInstall.set(mod, {})
|
||||
}
|
||||
}
|
||||
|
||||
nuxt.options.watch.push(...modulePaths)
|
||||
|
||||
// Register user and then ad-hoc modules
|
||||
for (const key of ['modules', '_modules'] as const) {
|
||||
for (const item of nuxt.options[key as 'modules']) {
|
||||
@ -661,7 +662,7 @@ export default defineNuxtPlugin({
|
||||
nuxt.hooks.hook('builder:watch', (event, relativePath) => {
|
||||
const path = resolve(nuxt.options.srcDir, relativePath)
|
||||
// Local module patterns
|
||||
if (watchedPaths.has(path)) {
|
||||
if (modulePaths.has(path)) {
|
||||
return nuxt.callHook('restart', { hard: true })
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,8 @@ export function walk (ast: Program | Node, callback: Partial<WalkOptions>) {
|
||||
|
||||
export function parseAndWalk (code: string, sourceFilename: string, callback: WalkerCallback): Program
|
||||
export function parseAndWalk (code: string, sourceFilename: string, object: Partial<WalkOptions>): Program
|
||||
export function parseAndWalk (code: string, _sourceFilename: string, callback: Partial<WalkOptions> | WalkerCallback) {
|
||||
const ast = parse (code, { sourceType: 'module', ecmaVersion: 'latest', locations: true })
|
||||
export function parseAndWalk (code: string, sourceFilename: string, callback: Partial<WalkOptions> | WalkerCallback) {
|
||||
const ast = parse (code, { sourceType: 'module', ecmaVersion: 'latest', locations: true, sourceFile: sourceFilename })
|
||||
walk(ast, typeof callback === 'function' ? { enter: callback } : callback)
|
||||
return ast
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Fragment, Suspense, Transition, defineComponent, h, inject, nextTick, ref, watch } from 'vue'
|
||||
import { Fragment, Suspense, defineComponent, h, inject, nextTick, ref, watch } from 'vue'
|
||||
import type { KeepAliveProps, TransitionProps, VNode } from 'vue'
|
||||
import { RouterView } from 'vue-router'
|
||||
import { defu } from 'defu'
|
||||
@ -9,7 +9,7 @@ import type { RouterViewSlotProps } from './utils'
|
||||
import { RouteProvider } from '#app/components/route-provider'
|
||||
import { useNuxtApp } from '#app/nuxt'
|
||||
import { useRouter } from '#app/composables/router'
|
||||
import { _wrapIf } from '#app/components/utils'
|
||||
import { _wrapInTransition } from '#app/components/utils'
|
||||
import { LayoutMetaSymbol, PageRouteSymbol } from '#app/components/injections'
|
||||
// @ts-expect-error virtual file
|
||||
import { appKeepalive as defaultKeepaliveConfig, appPageTransition as defaultPageTransition } from '#build/nuxt.config.mjs'
|
||||
@ -101,8 +101,30 @@ export default defineComponent({
|
||||
nuxtApp.callHook('page:loading:end')
|
||||
pageLoadingEndHookAlreadyCalled = true
|
||||
}
|
||||
|
||||
previousPageKey = key
|
||||
|
||||
if (import.meta.server) {
|
||||
vnode = h(Suspense, {
|
||||
suspensible: true,
|
||||
}, {
|
||||
default: () => {
|
||||
const providerVNode = h(RouteProvider, {
|
||||
key: key || undefined,
|
||||
vnode: slots.default ? h(Fragment, undefined, slots.default(routeProps)) : routeProps.Component,
|
||||
route: routeProps.route,
|
||||
renderKey: key || undefined,
|
||||
vnodeRef: pageRef,
|
||||
})
|
||||
return providerVNode
|
||||
},
|
||||
})
|
||||
|
||||
return vnode
|
||||
}
|
||||
|
||||
// Client side rendering
|
||||
|
||||
const hasTransition = !!(props.transition ?? routeProps.route.meta.pageTransition ?? defaultPageTransition)
|
||||
const transitionProps = hasTransition && _mergeTransitionProps([
|
||||
props.transition,
|
||||
@ -112,7 +134,7 @@ export default defineComponent({
|
||||
].filter(Boolean))
|
||||
|
||||
const keepaliveConfig = props.keepalive ?? routeProps.route.meta.keepalive ?? (defaultKeepaliveConfig as KeepAliveProps)
|
||||
vnode = _wrapIf(Transition, hasTransition && transitionProps,
|
||||
vnode = _wrapInTransition(hasTransition && transitionProps,
|
||||
wrapInKeepAlive(keepaliveConfig, h(Suspense, {
|
||||
suspensible: true,
|
||||
onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
|
||||
@ -134,7 +156,7 @@ export default defineComponent({
|
||||
trackRootNodes: hasTransition,
|
||||
vnodeRef: pageRef,
|
||||
})
|
||||
if (import.meta.client && keepaliveConfig) {
|
||||
if (keepaliveConfig) {
|
||||
(providerVNode.type as any).name = (routeProps.Component.type as any).name || (routeProps.Component.type as any).__name || 'RouteProvider'
|
||||
}
|
||||
return providerVNode
|
||||
|
@ -11,6 +11,7 @@ import { transform } from 'esbuild'
|
||||
import type { Property } from 'estree'
|
||||
import type { NuxtPage } from 'nuxt/schema'
|
||||
|
||||
import { klona } from 'klona'
|
||||
import { parseAndWalk, withLocations } from '../core/utils/parse'
|
||||
import { getLoader, uniqueBy } from '../core/utils'
|
||||
import { logger, toArray } from '../utils'
|
||||
@ -215,7 +216,7 @@ export async function getRouteMeta (contents: string, absolutePath: string, extr
|
||||
}
|
||||
|
||||
if (absolutePath in metaCache && metaCache[absolutePath]) {
|
||||
return metaCache[absolutePath]
|
||||
return klona(metaCache[absolutePath])
|
||||
}
|
||||
|
||||
const loader = getLoader(absolutePath)
|
||||
@ -314,7 +315,7 @@ export async function getRouteMeta (contents: string, absolutePath: string, extr
|
||||
}
|
||||
|
||||
metaCache[absolutePath] = extractedMeta
|
||||
return extractedMeta
|
||||
return klona(extractedMeta)
|
||||
}
|
||||
|
||||
const COLON_RE = /:/g
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { type MockedFunction, describe, expect, it, vi } from 'vitest'
|
||||
import { compileScript, parse } from '@vue/compiler-sfc'
|
||||
import * as Parser from 'acorn'
|
||||
import { klona } from 'klona'
|
||||
import { transform as esbuildTransform } from 'esbuild'
|
||||
import { PageMetaPlugin } from '../src/pages/plugins/page-meta'
|
||||
import { getRouteMeta, normalizeRoutes } from '../src/pages/utils'
|
||||
@ -8,6 +9,8 @@ import type { NuxtPage } from '../schema'
|
||||
|
||||
const filePath = '/app/pages/index.vue'
|
||||
|
||||
vi.mock('klona', { spy: true })
|
||||
|
||||
describe('page metadata', () => {
|
||||
it('should not extract metadata from empty files', async () => {
|
||||
expect(await getRouteMeta('', filePath)).toEqual({})
|
||||
@ -62,11 +65,20 @@ definePageMeta({ name: 'bar' })
|
||||
})
|
||||
|
||||
it('should use and invalidate cache', async () => {
|
||||
const _klona = klona as unknown as MockedFunction<typeof klona>
|
||||
_klona.mockImplementation(obj => obj)
|
||||
const fileContents = `<script setup>definePageMeta({ foo: 'bar' })</script>`
|
||||
const meta = await getRouteMeta(fileContents, filePath)
|
||||
expect(meta === await getRouteMeta(fileContents, filePath)).toBeTruthy()
|
||||
expect(meta === await getRouteMeta(fileContents, '/app/pages/other.vue')).toBeFalsy()
|
||||
expect(meta === await getRouteMeta('<template><div>Hi</div></template>' + fileContents, filePath)).toBeFalsy()
|
||||
_klona.mockReset()
|
||||
})
|
||||
|
||||
it('should not share state between page metadata', async () => {
|
||||
const fileContents = `<script setup>definePageMeta({ foo: 'bar' })</script>`
|
||||
const meta = await getRouteMeta(fileContents, filePath)
|
||||
expect(meta === await getRouteMeta(fileContents, filePath)).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should extract serialisable metadata', async () => {
|
||||
|
@ -834,3 +834,41 @@ describe('pages:pathToNitroGlob', () => {
|
||||
expect(pathToNitroGlob(path)).to.equal(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('page:extends', () => {
|
||||
const DYNAMIC_META_KEY = '__nuxt_dynamic_meta_key' as const
|
||||
it('should preserve distinct metadata for multiple routes referencing the same file', async () => {
|
||||
const files: NuxtPage[] = [
|
||||
{ path: 'home', file: `pages/index.vue` },
|
||||
{ path: 'home1', file: `pages/index.vue`, meta: { test: true } },
|
||||
{ path: 'home2', file: `pages/index.vue`, meta: { snap: true } },
|
||||
]
|
||||
const vfs = Object.fromEntries(
|
||||
files.map(file => [file.file, `
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
hello: 'world'
|
||||
})
|
||||
</script>
|
||||
`]),
|
||||
) as Record<string, string>
|
||||
await augmentPages(files, vfs)
|
||||
expect(files).toEqual([
|
||||
{
|
||||
path: 'home',
|
||||
file: `pages/index.vue`,
|
||||
meta: { [DYNAMIC_META_KEY]: new Set(['meta']) },
|
||||
},
|
||||
{
|
||||
path: 'home1',
|
||||
file: `pages/index.vue`,
|
||||
meta: { [DYNAMIC_META_KEY]: new Set(['meta']), test: true },
|
||||
},
|
||||
{
|
||||
path: 'home2',
|
||||
file: `pages/index.vue`,
|
||||
meta: { [DYNAMIC_META_KEY]: new Set(['meta']), snap: true },
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
@ -75,7 +75,7 @@
|
||||
"@types/pify": "5.0.4",
|
||||
"@types/webpack-bundle-analyzer": "4.7.0",
|
||||
"@types/webpack-hot-middleware": "2.25.9",
|
||||
"rollup": "4.31.0",
|
||||
"rollup": "4.32.1",
|
||||
"unbuild": "3.3.1",
|
||||
"vue": "3.5.13"
|
||||
},
|
||||
|
@ -39,5 +39,13 @@ export default defineUntypedSchema({
|
||||
* @type {(data: { loading?: string }) => string}
|
||||
*/
|
||||
loadingTemplate,
|
||||
|
||||
/**
|
||||
* Set CORS options for the dev server
|
||||
* @type {typeof import('h3').H3CorsOptions}
|
||||
*/
|
||||
cors: {
|
||||
origin: [/^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -26,7 +26,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/schema": "workspace:*",
|
||||
"rollup": "4.31.0",
|
||||
"rollup": "4.32.1",
|
||||
"unbuild": "3.3.1",
|
||||
"vue": "3.5.13"
|
||||
},
|
||||
@ -56,7 +56,7 @@
|
||||
"unenv": "^1.10.0",
|
||||
"unplugin": "^2.1.2",
|
||||
"vite": "^6.0.11",
|
||||
"vite-node": "^3.0.3",
|
||||
"vite-node": "^3.0.4",
|
||||
"vite-plugin-checker": "^0.8.0",
|
||||
"vue-bundle-renderer": "^2.1.1"
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ import { getPort } from 'get-port-please'
|
||||
import { joinURL, withoutLeadingSlash } from 'ufo'
|
||||
import { defu } from 'defu'
|
||||
import { env, nodeless } from 'unenv'
|
||||
import { appendCorsHeaders, appendCorsPreflightHeaders, defineEventHandler } from 'h3'
|
||||
import { defineEventHandler, handleCors, setHeader } from 'h3'
|
||||
import type { ViteConfig } from '@nuxt/schema'
|
||||
import type { ViteBuildContext } from './vite'
|
||||
import { devStyleSSRPlugin } from './plugins/dev-ssr-css'
|
||||
@ -255,11 +255,11 @@ export async function buildClient (ctx: ViteBuildContext) {
|
||||
// @ts-expect-error _skip_transform is a private property
|
||||
event.node.req._skip_transform = true
|
||||
} else if (!useViteCors) {
|
||||
if (event.method === 'OPTIONS') {
|
||||
appendCorsPreflightHeaders(event, {})
|
||||
const isPreflight = handleCors(event, ctx.nuxt.options.devServer.cors)
|
||||
if (isPreflight) {
|
||||
return null
|
||||
}
|
||||
appendCorsHeaders(event, {})
|
||||
setHeader(event, 'Vary', 'Origin')
|
||||
}
|
||||
|
||||
// Workaround: vite devmiddleware modifies req.url
|
||||
|
@ -85,7 +85,7 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
|
||||
// https://github.com/vitejs/vite/tree/main/packages/vite/src/node/build.ts#L464-L478
|
||||
assetFileNames: nuxt.options.dev
|
||||
? undefined
|
||||
: chunk => withoutLeadingSlash(join(nuxt.options.app.buildAssetsDir, `${sanitizeFilePath(filename(chunk.name!))}-[hash].[ext]`)),
|
||||
: chunk => withoutLeadingSlash(join(nuxt.options.app.buildAssetsDir, `${sanitizeFilePath(filename(chunk.names[0]!))}-[hash].[ext]`)),
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
@ -77,7 +77,7 @@
|
||||
"@types/pify": "5.0.4",
|
||||
"@types/webpack-bundle-analyzer": "4.7.0",
|
||||
"@types/webpack-hot-middleware": "2.25.9",
|
||||
"rollup": "4.31.0",
|
||||
"rollup": "4.32.1",
|
||||
"unbuild": "3.3.1",
|
||||
"vue": "3.5.13"
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
import pify from 'pify'
|
||||
import { resolve } from 'pathe'
|
||||
import { defineEventHandler, fromNodeMiddleware } from 'h3'
|
||||
import { defineEventHandler, fromNodeMiddleware, handleCors, setHeader } from 'h3'
|
||||
import type { H3CorsOptions } from 'h3'
|
||||
import type { IncomingMessage, MultiWatching, ServerResponse } from 'webpack-dev-middleware'
|
||||
import webpackDevMiddleware from 'webpack-dev-middleware'
|
||||
import webpackHotMiddleware from 'webpack-hot-middleware'
|
||||
@ -125,7 +126,7 @@ async function createDevMiddleware (compiler: Compiler) {
|
||||
})
|
||||
|
||||
// Register devMiddleware on server
|
||||
const devHandler = wdmToH3Handler(devMiddleware)
|
||||
const devHandler = wdmToH3Handler(devMiddleware, nuxt.options.devServer.cors)
|
||||
const hotHandler = fromNodeMiddleware(hotMiddleware)
|
||||
await nuxt.callHook('server:devHandler', defineEventHandler(async (event) => {
|
||||
const body = await devHandler(event)
|
||||
@ -139,8 +140,14 @@ async function createDevMiddleware (compiler: Compiler) {
|
||||
}
|
||||
|
||||
// TODO: implement upstream in `webpack-dev-middleware`
|
||||
function wdmToH3Handler (devMiddleware: webpackDevMiddleware.API<IncomingMessage, ServerResponse>) {
|
||||
function wdmToH3Handler (devMiddleware: webpackDevMiddleware.API<IncomingMessage, ServerResponse>, corsOptions: H3CorsOptions) {
|
||||
return defineEventHandler(async (event) => {
|
||||
const isPreflight = handleCors(event, corsOptions)
|
||||
if (isPreflight) {
|
||||
return null
|
||||
}
|
||||
setHeader(event, 'Vary', 'Origin')
|
||||
|
||||
event.context.webpack = {
|
||||
...event.context.webpack,
|
||||
devMiddleware: devMiddleware.context,
|
||||
|
1658
pnpm-lock.yaml
1658
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -127,7 +127,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
||||
const serverDir = join(pagesRootDir, '.output/server')
|
||||
|
||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"303k"`)
|
||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"301k"`)
|
||||
|
||||
const modules = await analyzeSizes(['node_modules/**/*'], serverDir)
|
||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1402k"`)
|
||||
|
Loading…
Reference in New Issue
Block a user