refactor(schema): introduce future and features namespace (#24880)

This commit is contained in:
Daniel Roe 2023-12-25 14:03:29 +00:00 committed by GitHub
parent e780bdb757
commit 32d2c99c5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 124 additions and 77 deletions

View File

@ -124,31 +124,6 @@ Read more in `defineRouteRules` utility.
:read-more{to="/docs/guide/concepts/rendering#hybrid-rendering" icon="i-ph-medal-duotone"} :read-more{to="/docs/guide/concepts/rendering#hybrid-rendering" icon="i-ph-medal-duotone"}
## inlineSSRStyles
Inlines styles when rendering HTML. This is currently available only when using Vite.
You can also pass a function that receives the path of a Vue component and returns a boolean indicating whether to inline the styles for that component.
```ts [nuxt.config.ts]
export defineNuxtConfig({
experimental: {
inlineSSRStyles: true // or a function to determine inlining
}
})
```
## noScripts
Disables rendering of Nuxt scripts and JS resource hints. Can also be configured granularly within `routeRules`.
```ts [nuxt.config.ts]
export defineNuxtConfig({
experimental: {
noScripts: true
}
})
```
## renderJsonPayloads ## renderJsonPayloads
Allows rendering of JSON payloads with support for revivifying complex types. Allows rendering of JSON payloads with support for revivifying complex types.

View File

@ -0,0 +1,55 @@
---
title: "Features"
description: "Enable or disable optional Nuxt features to unlock new possibilities."
---
Some features of Nuxt are available on an opt-in basis, or can be disabled based on your needs.
## `features`
### inlineStyles
Inlines styles when rendering HTML. This is currently available only when using Vite.
You can also pass a function that receives the path of a Vue component and returns a boolean indicating whether to inline the styles for that component.
```ts [nuxt.config.ts]
export defineNuxtConfig({
features: {
inlineStyles: true // or a function to determine inlining
}
})
```
### noScripts
Disables rendering of Nuxt scripts and JS resource hints. Can also be configured granularly within `routeRules`.
```ts [nuxt.config.ts]
export defineNuxtConfig({
features: {
noScripts: true
}
})
```
## `future`
There is also a `future` namespace for behavior that will likely become default in a early opting-in to new features that will become default in a future (possibly major) version of the framework.
### typescriptBundlerResolution
This enables 'Bundler' module resolution mode for TypeScript, which is the recommended setting
for frameworks like Nuxt and [Vite](https://vitejs.dev/guide/performance.html#reduce-resolve-operations).
It improves type support when using modern libraries with `exports`.
See [the original TypeScript pull request](https://github.com/microsoft/TypeScript/pull/51669).
```ts [nuxt.config.ts]
export defineNuxtConfig({
future: {
typescriptBundlerResolution: true
}
})
```

View File

@ -128,7 +128,7 @@ export async function writeTypes (nuxt: Nuxt) {
jsxImportSource: 'vue', jsxImportSource: 'vue',
target: 'ESNext', target: 'ESNext',
module: 'ESNext', module: 'ESNext',
moduleResolution: nuxt.options.experimental?.typescriptBundlerResolution ? 'Bundler' : 'Node', moduleResolution: nuxt.options.future?.typescriptBundlerResolution || (nuxt.options.experimental as any)?.typescriptBundlerResolution ? 'Bundler' : 'Node',
skipLibCheck: true, skipLibCheck: true,
isolatedModules: true, isolatedModules: true,
useDefineForClassFields: true, useDefineForClassFields: true,

View File

@ -51,7 +51,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
buildDir: nuxt.options.buildDir, buildDir: nuxt.options.buildDir,
experimental: { experimental: {
asyncContext: nuxt.options.experimental.asyncContext, asyncContext: nuxt.options.experimental.asyncContext,
typescriptBundlerResolution: nuxt.options.experimental.typescriptBundlerResolution || nuxt.options.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' || _nitroConfig.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' typescriptBundlerResolution: nuxt.options.future.typescriptBundlerResolution || nuxt.options.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' || _nitroConfig.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler'
}, },
framework: { framework: {
name: 'nuxt', name: 'nuxt',
@ -117,7 +117,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
// TODO: address upstream issue with defu types...? // TODO: address upstream issue with defu types...?
...nuxt.options.runtimeConfig.nitro satisfies RuntimeConfig['nitro'] as any ...nuxt.options.runtimeConfig.nitro satisfies RuntimeConfig['nitro'] as any
} }
} , },
appConfig: nuxt.options.appConfig, appConfig: nuxt.options.appConfig,
appConfigFiles: nuxt.options._layers.map( appConfigFiles: nuxt.options._layers.map(
layer => resolve(layer.config.srcDir, 'app.config') layer => resolve(layer.config.srcDir, 'app.config')
@ -207,8 +207,8 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
replace: { replace: {
'process.env.NUXT_NO_SSR': nuxt.options.ssr === false, 'process.env.NUXT_NO_SSR': nuxt.options.ssr === false,
'process.env.NUXT_EARLY_HINTS': nuxt.options.experimental.writeEarlyHints !== false, 'process.env.NUXT_EARLY_HINTS': nuxt.options.experimental.writeEarlyHints !== false,
'process.env.NUXT_NO_SCRIPTS': !!nuxt.options.experimental.noScripts && !nuxt.options.dev, 'process.env.NUXT_NO_SCRIPTS': !!nuxt.options.features.noScripts && !nuxt.options.dev,
'process.env.NUXT_INLINE_STYLES': !!nuxt.options.experimental.inlineSSRStyles, 'process.env.NUXT_INLINE_STYLES': !!nuxt.options.features.inlineStyles,
'process.env.NUXT_JSON_PAYLOADS': !!nuxt.options.experimental.renderJsonPayloads, 'process.env.NUXT_JSON_PAYLOADS': !!nuxt.options.experimental.renderJsonPayloads,
'process.env.NUXT_COMPONENT_ISLANDS': !!nuxt.options.experimental.componentIslands, 'process.env.NUXT_COMPONENT_ISLANDS': !!nuxt.options.experimental.componentIslands,
'process.env.NUXT_ASYNC_CONTEXT': !!nuxt.options.experimental.asyncContext, 'process.env.NUXT_ASYNC_CONTEXT': !!nuxt.options.experimental.asyncContext,

View File

@ -164,7 +164,7 @@ async function initNuxt (nuxt: Nuxt) {
} }
// TODO: [Experimental] Avoid emitting assets when flag is enabled // TODO: [Experimental] Avoid emitting assets when flag is enabled
if (nuxt.options.experimental.noScripts && !nuxt.options.dev) { if (nuxt.options.features.noScripts && !nuxt.options.dev) {
nuxt.hook('build:manifest', async (manifest) => { nuxt.hook('build:manifest', async (manifest) => {
for (const file in manifest) { for (const file in manifest) {
if (manifest[file].resourceType === 'script') { if (manifest[file].resourceType === 'script') {

View File

@ -1,6 +1,63 @@
import { defineUntypedSchema } from 'untyped' import { defineUntypedSchema } from 'untyped'
export default defineUntypedSchema({ export default defineUntypedSchema({
future: {
/**
* This enables 'Bundler' module resolution mode for TypeScript, which is the recommended setting
* for frameworks like Nuxt and Vite.
*
* It improves type support when using modern libraries with `exports`.
*
* See https://github.com/microsoft/TypeScript/pull/51669
*/
typescriptBundlerResolution: {
async $resolve (val, get) {
// TODO: remove in v3.10
val = val ?? await get('experimental').then((e: Record<string, any>) => e?.typescriptBundlerResolution)
if (typeof val === 'boolean') { return val }
const setting = await get('typescript.tsConfig.compilerOptions.moduleResolution')
if (setting) {
return setting.toLowerCase() === 'bundler'
}
return false
}
},
},
/**
* `future` is for early opting-in to new features that will become default in a future
* (possibly major) version of the framework.
*/
features: {
/**
* Inline styles when rendering HTML (currently vite only).
*
* You can also pass a function that receives the path of a Vue component
* and returns a boolean indicating whether to inline the styles for that component.
* @type {boolean | ((id?: string) => boolean)}
*/
inlineStyles: {
async $resolve (val, get) {
// TODO: remove in v3.10
val = val ?? await get('experimental').then((e: Record<string, any>) => e?.inlineSSRStyles)
if (val === false || (await get('dev')) || (await get('ssr')) === false || (await get('builder')) === '@nuxt/webpack-builder') {
return false
}
// Enabled by default for vite prod with ssr
return val ?? true
}
},
/**
* Turn off rendering of Nuxt scripts and JS resource hints.
* You can also disable scripts more granularly within `routeRules`.
*/
noScripts: {
async $resolve (val, get) {
// TODO: remove in v3.10
return val ?? await get('experimental').then((e: Record<string, any>) => e?.noScripts) ?? false
}
},
},
experimental: { experimental: {
/** /**
* Set to true to generate an async entry point for the Vue bundle (for module federation support). * Set to true to generate an async entry point for the Vue bundle (for module federation support).
@ -72,29 +129,6 @@ export default defineUntypedSchema({
*/ */
restoreState: false, restoreState: false,
/**
* Inline styles when rendering HTML (currently vite only).
*
* You can also pass a function that receives the path of a Vue component
* and returns a boolean indicating whether to inline the styles for that component.
* @type {boolean | ((id?: string) => boolean)}
*/
inlineSSRStyles: {
async $resolve (val, get) {
if (val === false || (await get('dev')) || (await get('ssr')) === false || (await get('builder')) === '@nuxt/webpack-builder') {
return false
}
// Enabled by default for vite prod with ssr
return val ?? true
}
},
/**
* Turn off rendering of Nuxt scripts and JS resource hints.
* You can also disable scripts more granularly within `routeRules`.
*/
noScripts: false,
/** Render JSON payloads with support for revivifying complex types. */ /** Render JSON payloads with support for revivifying complex types. */
renderJsonPayloads: true, renderJsonPayloads: true,
@ -152,27 +186,6 @@ export default defineUntypedSchema({
*/ */
configSchema: true, configSchema: true,
/**
* This enables 'Bundler' module resolution mode for TypeScript, which is the recommended setting
* for frameworks like Nuxt and Vite.
*
* It improves type support when using modern libraries with `exports`.
*
* This is only not enabled by default because it could be a breaking change for some projects.
*
* See https://github.com/microsoft/TypeScript/pull/51669
*/
typescriptBundlerResolution: {
async $resolve (val, get) {
if (typeof val === 'boolean') { return val }
const setting = await get('typescript.tsConfig.compilerOptions.moduleResolution')
if (setting) {
return setting.toLowerCase() === 'bundler'
}
return false
}
},
/** /**
* 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.

View File

@ -166,7 +166,7 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
srcDir: ctx.nuxt.options.srcDir, srcDir: ctx.nuxt.options.srcDir,
clientCSSMap, clientCSSMap,
chunksWithInlinedCSS, chunksWithInlinedCSS,
shouldInline: ctx.nuxt.options.experimental.inlineSSRStyles, shouldInline: ctx.nuxt.options.features.inlineStyles,
components: ctx.nuxt.apps.default.components, components: ctx.nuxt.apps.default.components,
globalCSS: ctx.nuxt.options.css, globalCSS: ctx.nuxt.options.css,
mode: isServer ? 'server' : 'client', mode: isServer ? 'server' : 'client',

View File

@ -4,6 +4,8 @@ export default defineNuxtConfig({
experimental: { experimental: {
typedPages: true, typedPages: true,
appManifest: true, appManifest: true,
},
future: {
typescriptBundlerResolution: process.env.MODULE_RESOLUTION === 'bundler' typescriptBundlerResolution: process.env.MODULE_RESOLUTION === 'bundler'
}, },
buildDir: process.env.NITRO_BUILD_DIR, buildDir: process.env.NITRO_BUILD_DIR,

View File

@ -191,13 +191,15 @@ export default defineNuxtConfig({
} }
} }
}, },
features: {
inlineStyles: id => !!id && !id.includes('assets.vue'),
},
experimental: { experimental: {
typedPages: true, typedPages: true,
polyfillVueUseHead: true, polyfillVueUseHead: true,
respectNoSSRHeader: true, respectNoSSRHeader: true,
clientFallback: true, clientFallback: true,
restoreState: true, restoreState: true,
inlineSSRStyles: id => !!id && !id.includes('assets.vue'),
componentIslands: { componentIslands: {
selectiveClient: true selectiveClient: true
}, },