feat(schema): remove some experimental options for v4 (#27132)

This commit is contained in:
Daniel Roe 2024-05-13 18:45:21 +01:00 committed by GitHub
parent 69860d952a
commit 5c34676159
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 140 additions and 18 deletions

View File

@ -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:
```ts
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
future: {
compatibilityVersion: 4,
@ -46,6 +46,7 @@ export default defineNuxtConfig({
// app: 'app'
// },
// experimental: {
// sharedPrerenderData: false,
// compileTemplate: true,
// templateUtils: 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:
```ts
```ts [nuxt.config.ts]
export default defineNuxtConfig({
// This reverts the new srcDir default from `app` back to your root directory
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`
🚦 **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 })
```
1. You can change the default behavior on a project-wide basis (not recommended):
```ts
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
defaults: {
@ -270,6 +312,29 @@ const importSources = (sources: string | string[], { lazy = false } = {}) => {
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
In the table below, there is a quick comparison between 3 versions of Nuxt:

View File

@ -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.
<!-- You can disable this feature if it causes issues in your project.
```ts twoslash [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
scanPageMeta: false
}
})
``` -->
## cookieStore
Enables CookieStore support to listen for cookie updates (if supported by the browser) and refresh `useCookie` ref values.

View File

@ -136,8 +136,18 @@ export default defineUntypedSchema({
/**
* Tree shakes contents of client-only components from server bundle.
* @see [Nuxt PR #5750](https://github.com/nuxt/framework/pull/5750)
* @deprecated This option will no longer be configurable in Nuxt v4
*/
treeshakeClientOnly: 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
@ -246,19 +256,51 @@ export default defineUntypedSchema({
/**
* Config schema support
* @see [Nuxt Issue #15592](https://github.com/nuxt/nuxt/issues/15592)
* @deprecated This option will no longer be configurable in Nuxt v4
*/
configSchema: 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
* `@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. */
localLayerAliases: true,

View File

@ -13,6 +13,7 @@ import type { NuxtIslandResponse } from '#app'
const isWebpack = process.env.TEST_BUILDER === 'webpack'
const isTestingAppManifest = process.env.TEST_MANIFEST !== 'manifest-off'
const isV4 = process.env.TEST_V4 === 'true'
await setup({
rootDir: fileURLToPath(new URL('./fixtures/basic', import.meta.url)),
@ -57,7 +58,14 @@ describe('server api', () => {
describe('route rules', () => {
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)
if (isRenderingJson) {
expect(attrs['data-ssr']).toEqual('false')
@ -876,7 +884,7 @@ describe('head tags', () => {
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' } })
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">')
})
it('legacy vueuse/head works', async () => {
it.skipIf(isV4)('legacy vueuse/head works', async () => {
const headHtml = await $fetch('/vueuse-head')
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, '')
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)))
for (const link of result.head.link) {
link.href = link.href.replace(fixtureDir, '/<rootDir>').replaceAll('//', '/')
@ -2210,14 +2217,12 @@ describe('component islands', () => {
}
`)
} 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(`
{
"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",
"key": "island-link",