mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(schema): remove some experimental options for v4 (#27132)
This commit is contained in:
parent
69860d952a
commit
5c34676159
@ -35,7 +35,7 @@ First, opt in to the nightly release channel [following these steps](/docs/guide
|
|||||||
|
|
||||||
Then you can set your `compatibilityVersion` to match Nuxt 4 behavior:
|
Then you can set your `compatibilityVersion` to match Nuxt 4 behavior:
|
||||||
|
|
||||||
```ts
|
```ts twoslash [nuxt.config.ts]
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
future: {
|
future: {
|
||||||
compatibilityVersion: 4,
|
compatibilityVersion: 4,
|
||||||
@ -46,6 +46,7 @@ export default defineNuxtConfig({
|
|||||||
// app: 'app'
|
// app: 'app'
|
||||||
// },
|
// },
|
||||||
// experimental: {
|
// experimental: {
|
||||||
|
// sharedPrerenderData: false,
|
||||||
// compileTemplate: true,
|
// compileTemplate: true,
|
||||||
// templateUtils: true,
|
// templateUtils: true,
|
||||||
// relativeWatchPaths: true,
|
// relativeWatchPaths: true,
|
||||||
@ -136,7 +137,7 @@ nuxt.config.ts
|
|||||||
|
|
||||||
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.) You can also force a v3 folder structure with the following configuration:
|
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.) You can also force a v3 folder structure with the following configuration:
|
||||||
|
|
||||||
```ts
|
```ts [nuxt.config.ts]
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
// This reverts the new srcDir default from `app` back to your root directory
|
// This reverts the new srcDir default from `app` back to your root directory
|
||||||
srcDir: '.',
|
srcDir: '.',
|
||||||
@ -147,6 +148,47 @@ export default defineNuxtConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Shared Prerender Data
|
||||||
|
|
||||||
|
🚦 **Impact Level**: Medium
|
||||||
|
|
||||||
|
##### What Changed
|
||||||
|
|
||||||
|
We enabled a previously experimental feature to share data from `useAsyncData` and `useFetch` calls, across different pages. See [original PR](https://github.com/nuxt/nuxt/pull/24894).
|
||||||
|
|
||||||
|
##### Reasons for Change
|
||||||
|
|
||||||
|
This feature automatically shares payload _data_ between pages that are prerendered. This can result in a significant performance improvement when prerendering sites that use `useAsyncData` or `useFetch` and fetch the same data in different pages.
|
||||||
|
|
||||||
|
For example, if your site requires a `useFetch` call for every page (for example, to get navigation data for a menu, or site settings from a CMS), this data would only be fetched once when prerendering the first page that uses it, and then cached for use when prerendering other pages.
|
||||||
|
|
||||||
|
##### Migration Steps
|
||||||
|
|
||||||
|
Make sure that any unique key of your data is always resolvable to the same data. For example, if you are using `useAsyncData` to fetch data related to a particular page, you should provide a key that uniquely matches that data. (`useFetch` should do this automatically for you.)
|
||||||
|
|
||||||
|
```ts [app/pages/test/[slug\\].vue]
|
||||||
|
// This would be unsafe in a dynamic page (e.g. `[slug].vue`) because the route slug makes a difference
|
||||||
|
// to the data fetched, but Nuxt can't know that because it's not reflected in the key.
|
||||||
|
const route = useRoute()
|
||||||
|
const { data } = await useAsyncData(async () => {
|
||||||
|
return await $fetch(`/api/my-page/${route.params.slug}`)
|
||||||
|
})
|
||||||
|
// Instead, you should use a key that uniquely identifies the data fetched.
|
||||||
|
const { data } = await useAsyncData(route.params.slug, async () => {
|
||||||
|
return await $fetch(`/api/my-page/${route.params.slug}`)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can disable this feature with:
|
||||||
|
|
||||||
|
```ts twoslash [nuxt.config.ts]
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
experimental: {
|
||||||
|
sharedPrerenderData: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
#### Shallow Data Reactivity in `useAsyncData` and `useFetch`
|
#### Shallow Data Reactivity in `useAsyncData` and `useFetch`
|
||||||
|
|
||||||
🚦 **Impact Level**: Minimal
|
🚦 **Impact Level**: Minimal
|
||||||
@ -171,7 +213,7 @@ In most cases, no migration steps are required, but if you rely on the reactivit
|
|||||||
+ const { data } = useFetch('/api/test', { deep: true })
|
+ const { data } = useFetch('/api/test', { deep: true })
|
||||||
```
|
```
|
||||||
1. You can change the default behavior on a project-wide basis (not recommended):
|
1. You can change the default behavior on a project-wide basis (not recommended):
|
||||||
```ts
|
```ts twoslash [nuxt.config.ts]
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
experimental: {
|
experimental: {
|
||||||
defaults: {
|
defaults: {
|
||||||
@ -270,6 +312,29 @@ const importSources = (sources: string | string[], { lazy = false } = {}) => {
|
|||||||
const importName = genSafeVariableName
|
const importName = genSafeVariableName
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Removal of Experimental Features
|
||||||
|
|
||||||
|
🚦 **Impact Level**: Minimal
|
||||||
|
|
||||||
|
##### What Changed
|
||||||
|
|
||||||
|
Four experimental features are no longer configurable in Nuxt 4:
|
||||||
|
|
||||||
|
* `treeshakeClientOnly` will be `true` (default since v3.0)
|
||||||
|
* `configSchema` will be `true` (default since v3.3)
|
||||||
|
* `polyfillVueUseHead` will be `false` (default since v3.4)
|
||||||
|
* `respectNoSSRHeader` will be `false` (default since v3.4)
|
||||||
|
|
||||||
|
##### Reasons for Change
|
||||||
|
|
||||||
|
These options have been set to their current values for some time and we do not have a reason to believe that they need to remain configurable.
|
||||||
|
|
||||||
|
##### Migration Steps
|
||||||
|
|
||||||
|
* `polyfillVueUseHead` is implementable in user-land with [this plugin](https://github.com/nuxt/nuxt/blob/f209158352b09d1986aa320e29ff36353b91c358/packages/nuxt/src/head/runtime/plugins/vueuse-head-polyfill.ts#L10-L11)
|
||||||
|
|
||||||
|
* `respectNoSSRHeader`is implementable in user-land with [server middleware](https://github.com/nuxt/nuxt/blob/c660b39447f0d5b8790c0826092638d321cd6821/packages/nuxt/src/core/runtime/nitro/no-ssr.ts#L8-L9)
|
||||||
|
|
||||||
## Nuxt 2 vs Nuxt 3
|
## Nuxt 2 vs Nuxt 3
|
||||||
|
|
||||||
In the table below, there is a quick comparison between 3 versions of Nuxt:
|
In the table below, there is a quick comparison between 3 versions of Nuxt:
|
||||||
|
@ -386,6 +386,16 @@ This option allows exposing some route metadata defined in `definePageMeta` at b
|
|||||||
|
|
||||||
This only works with static or strings/arrays rather than variables or conditional assignment. See [original issue](https://github.com/nuxt/nuxt/issues/24770) for more information and context.
|
This only works with static or strings/arrays rather than variables or conditional assignment. See [original issue](https://github.com/nuxt/nuxt/issues/24770) for more information and context.
|
||||||
|
|
||||||
|
<!-- You can disable this feature if it causes issues in your project.
|
||||||
|
|
||||||
|
```ts twoslash [nuxt.config.ts]
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
experimental: {
|
||||||
|
scanPageMeta: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
``` -->
|
||||||
|
|
||||||
## cookieStore
|
## cookieStore
|
||||||
|
|
||||||
Enables CookieStore support to listen for cookie updates (if supported by the browser) and refresh `useCookie` ref values.
|
Enables CookieStore support to listen for cookie updates (if supported by the browser) and refresh `useCookie` ref values.
|
||||||
|
@ -136,8 +136,18 @@ export default defineUntypedSchema({
|
|||||||
/**
|
/**
|
||||||
* Tree shakes contents of client-only components from server bundle.
|
* Tree shakes contents of client-only components from server bundle.
|
||||||
* @see [Nuxt PR #5750](https://github.com/nuxt/framework/pull/5750)
|
* @see [Nuxt PR #5750](https://github.com/nuxt/framework/pull/5750)
|
||||||
|
* @deprecated This option will no longer be configurable in Nuxt v4
|
||||||
*/
|
*/
|
||||||
treeshakeClientOnly: true,
|
treeshakeClientOnly: {
|
||||||
|
async $resolve (val, get) {
|
||||||
|
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
||||||
|
if (isV4 && val === false) {
|
||||||
|
console.warn('Enabling `experimental.treeshakeClientOnly` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return val ?? true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit `app:chunkError` hook when there is an error loading vite/webpack
|
* Emit `app:chunkError` hook when there is an error loading vite/webpack
|
||||||
@ -246,19 +256,51 @@ export default defineUntypedSchema({
|
|||||||
/**
|
/**
|
||||||
* Config schema support
|
* Config schema support
|
||||||
* @see [Nuxt Issue #15592](https://github.com/nuxt/nuxt/issues/15592)
|
* @see [Nuxt Issue #15592](https://github.com/nuxt/nuxt/issues/15592)
|
||||||
|
* @deprecated This option will no longer be configurable in Nuxt v4
|
||||||
*/
|
*/
|
||||||
configSchema: true,
|
configSchema: {
|
||||||
|
async $resolve (val, get) {
|
||||||
|
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
||||||
|
if (isV4 && val === false) {
|
||||||
|
console.warn('Enabling `experimental.configSchema` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return val ?? true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not to add a compatibility layer for modules, plugins or user code relying on the old
|
* Whether or not to add a compatibility layer for modules, plugins or user code relying on the old
|
||||||
* `@vueuse/head` API.
|
* `@vueuse/head` API.
|
||||||
*
|
*
|
||||||
* This can be disabled for most Nuxt sites to reduce the client-side bundle by ~0.5kb.
|
* This is disabled to reduce the client-side bundle by ~0.5kb.
|
||||||
|
* @deprecated This feature will be removed in Nuxt v4.
|
||||||
*/
|
*/
|
||||||
polyfillVueUseHead: false,
|
polyfillVueUseHead: {
|
||||||
|
async $resolve (val, get) {
|
||||||
|
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
||||||
|
if (isV4 && val === true) {
|
||||||
|
console.warn('Disabling `experimental.polyfillVueUseHead` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return val ?? false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/** Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header. */
|
/**
|
||||||
respectNoSSRHeader: false,
|
* Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header.
|
||||||
|
* @deprecated This feature will be removed in Nuxt v4.
|
||||||
|
*/
|
||||||
|
respectNoSSRHeader: {
|
||||||
|
async $resolve (val, get) {
|
||||||
|
const isV4 = ((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
||||||
|
if (isV4 && val === true) {
|
||||||
|
console.warn('Disabling `experimental.respectNoSSRHeader` in v4 compatibility mode as it will no longer be configurable in Nuxt v4.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return val ?? false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
/** Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. */
|
/** Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. */
|
||||||
localLayerAliases: true,
|
localLayerAliases: true,
|
||||||
|
@ -13,6 +13,7 @@ import type { NuxtIslandResponse } from '#app'
|
|||||||
|
|
||||||
const isWebpack = process.env.TEST_BUILDER === 'webpack'
|
const isWebpack = process.env.TEST_BUILDER === 'webpack'
|
||||||
const isTestingAppManifest = process.env.TEST_MANIFEST !== 'manifest-off'
|
const isTestingAppManifest = process.env.TEST_MANIFEST !== 'manifest-off'
|
||||||
|
const isV4 = process.env.TEST_V4 === 'true'
|
||||||
|
|
||||||
await setup({
|
await setup({
|
||||||
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
|
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
|
||||||
@ -57,7 +58,14 @@ describe('server api', () => {
|
|||||||
|
|
||||||
describe('route rules', () => {
|
describe('route rules', () => {
|
||||||
it('should enable spa mode', async () => {
|
it('should enable spa mode', async () => {
|
||||||
const { script, attrs } = parseData(await $fetch('/route-rules/spa'))
|
const headHtml = await $fetch('/route-rules/spa')
|
||||||
|
|
||||||
|
// SPA should render appHead tags
|
||||||
|
expect(headHtml).toContain('<meta name="description" content="Nuxt Fixture">')
|
||||||
|
expect(headHtml).toContain('<meta charset="utf-8">')
|
||||||
|
expect(headHtml).toContain('<meta name="viewport" content="width=1024, initial-scale=1">')
|
||||||
|
|
||||||
|
const { script, attrs } = parseData(headHtml)
|
||||||
expect(script.serverRendered).toEqual(false)
|
expect(script.serverRendered).toEqual(false)
|
||||||
if (isRenderingJson) {
|
if (isRenderingJson) {
|
||||||
expect(attrs['data-ssr']).toEqual('false')
|
expect(attrs['data-ssr']).toEqual('false')
|
||||||
@ -876,7 +884,7 @@ describe('head tags', () => {
|
|||||||
expect(headHtml).toContain('<meta content="0;javascript:alert(1)">')
|
expect(headHtml).toContain('<meta content="0;javascript:alert(1)">')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('SPA should render appHead tags', async () => {
|
it.skipIf(isV4)('SPA should render appHead tags', async () => {
|
||||||
const headHtml = await $fetch('/head', { headers: { 'x-nuxt-no-ssr': '1' } })
|
const headHtml = await $fetch('/head', { headers: { 'x-nuxt-no-ssr': '1' } })
|
||||||
|
|
||||||
expect(headHtml).toContain('<meta name="description" content="Nuxt Fixture">')
|
expect(headHtml).toContain('<meta name="description" content="Nuxt Fixture">')
|
||||||
@ -884,7 +892,7 @@ describe('head tags', () => {
|
|||||||
expect(headHtml).toContain('<meta name="viewport" content="width=1024, initial-scale=1">')
|
expect(headHtml).toContain('<meta name="viewport" content="width=1024, initial-scale=1">')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('legacy vueuse/head works', async () => {
|
it.skipIf(isV4)('legacy vueuse/head works', async () => {
|
||||||
const headHtml = await $fetch('/vueuse-head')
|
const headHtml = await $fetch('/vueuse-head')
|
||||||
expect(headHtml).toContain('<title>using provides usehead and updateDOM - VueUse head polyfill test</title>')
|
expect(headHtml).toContain('<title>using provides usehead and updateDOM - VueUse head polyfill test</title>')
|
||||||
})
|
})
|
||||||
@ -2187,7 +2195,6 @@ describe('component islands', () => {
|
|||||||
result.html = result.html.replace(/ data-island-uid="([^"]*)"/g, '')
|
result.html = result.html.replace(/ data-island-uid="([^"]*)"/g, '')
|
||||||
|
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
result.head.link = result.head.link.filter(l => !l.href.includes('@nuxt+ui-templates'))
|
|
||||||
const fixtureDir = normalize(fileURLToPath(new URL('./fixtures/basic', import.meta.url)))
|
const fixtureDir = normalize(fileURLToPath(new URL('./fixtures/basic', import.meta.url)))
|
||||||
for (const link of result.head.link) {
|
for (const link of result.head.link) {
|
||||||
link.href = link.href.replace(fixtureDir, '/<rootDir>').replaceAll('//', '/')
|
link.href = link.href.replace(fixtureDir, '/<rootDir>').replaceAll('//', '/')
|
||||||
@ -2210,14 +2217,12 @@ describe('component islands', () => {
|
|||||||
}
|
}
|
||||||
`)
|
`)
|
||||||
} else if (isDev() && !isWebpack) {
|
} else if (isDev() && !isWebpack) {
|
||||||
|
// TODO: resolve dev bug triggered by earlier fetch of /vueuse-head page
|
||||||
|
// https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/runtime/nitro/renderer.ts#L139
|
||||||
|
result.head.link = result.head.link.filter(h => !h.href.includes('SharedComponent'))
|
||||||
expect(result.head).toMatchInlineSnapshot(`
|
expect(result.head).toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"link": [
|
"link": [
|
||||||
{
|
|
||||||
"href": "/_nuxt/components/SharedComponent.vue?vue&type=style&index=0&scoped=3ee84738&lang.css",
|
|
||||||
"key": "island-link",
|
|
||||||
"rel": "stylesheet",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"href": "/_nuxt/components/islands/PureComponent.vue?vue&type=style&index=0&scoped=c0c0cf89&lang.css",
|
"href": "/_nuxt/components/islands/PureComponent.vue?vue&type=style&index=0&scoped=c0c0cf89&lang.css",
|
||||||
"key": "island-link",
|
"key": "island-link",
|
||||||
|
Loading…
Reference in New Issue
Block a user