mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(nuxt): enable islands if server pages/components present (#26223)
This commit is contained in:
parent
f080c426a2
commit
9bfd988ca6
@ -365,10 +365,6 @@ You can define a page as [client only](/docs/guide/directory-structure/component
|
||||
|
||||
You can define a page as [server only](/docs/guide/directory-structure/components#server-components) by giving it a `.server.vue` suffix. While you will be able to navigate to the page using client-side navigation, controlled by `vue-router`, it will be rendered with a server component automatically, meaning the code required to render the page will not be in your client-side bundle.
|
||||
|
||||
::note
|
||||
You will also need to enable `experimental.componentIslands` in order to make this possible.
|
||||
::
|
||||
|
||||
## Custom Routing
|
||||
|
||||
As your app gets bigger and more complex, your routing might require more flexibility. For this reason, Nuxt directly exposes the router, routes and router options for customization in different ways.
|
||||
|
@ -12,10 +12,6 @@ When rendering an island component, the content of the island component is stati
|
||||
|
||||
Changing the island component props triggers a refetch of the island component to re-render it again.
|
||||
|
||||
::read-more{to="/docs/guide/going-further/experimental-features#componentislands" icon="i-ph-star-duotone"}
|
||||
This component is experimental and in order to use it you must enable the `experimental.componentIslands` option in your `nuxt.config`.
|
||||
::
|
||||
|
||||
::note
|
||||
Global styles of your application are sent with the response.
|
||||
::
|
||||
|
@ -176,6 +176,9 @@ export default defineNuxtModule<ComponentsOptions>({
|
||||
chunkName: 'components/' + component.kebabName
|
||||
})
|
||||
}
|
||||
if (component.mode === 'server' && !nuxt.options.ssr) {
|
||||
logger.warn(`Using server components with \`ssr: false\` is not supported with auto-detected component islands. If you need to use server component \`${component.pascalName}\`, set \`experimental.componentIslands\` to \`true\`.`)
|
||||
}
|
||||
}
|
||||
context.components = newComponents
|
||||
app.components = newComponents
|
||||
|
@ -217,7 +217,6 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
'process.env.NUXT_NO_SCRIPTS': !!nuxt.options.features.noScripts && !nuxt.options.dev,
|
||||
'process.env.NUXT_INLINE_STYLES': !!nuxt.options.features.inlineStyles,
|
||||
'process.env.NUXT_JSON_PAYLOADS': !!nuxt.options.experimental.renderJsonPayloads,
|
||||
'process.env.NUXT_COMPONENT_ISLANDS': !!nuxt.options.experimental.componentIslands,
|
||||
'process.env.NUXT_ASYNC_CONTEXT': !!nuxt.options.experimental.asyncContext,
|
||||
'process.env.NUXT_SHARED_DATA': !!nuxt.options.experimental.sharedPrerenderData,
|
||||
'process.dev': nuxt.options.dev,
|
||||
|
@ -314,7 +314,7 @@ async function initNuxt (nuxt: Nuxt) {
|
||||
filePath: resolve(nuxt.options.appDir, 'components/nuxt-island')
|
||||
})
|
||||
|
||||
if (!nuxt.options.ssr) {
|
||||
if (!nuxt.options.ssr && nuxt.options.experimental.componentIslands !== 'auto') {
|
||||
nuxt.options.ssr = true
|
||||
nuxt.options.nitro.routeRules ||= {}
|
||||
nuxt.options.nitro.routeRules['/**'] = defu(nuxt.options.nitro.routeRules['/**'], { ssr: false })
|
||||
|
@ -29,7 +29,7 @@ import unheadPlugins from '#internal/unhead-plugins.mjs'
|
||||
// eslint-disable-next-line import/no-restricted-paths
|
||||
import type { NuxtPayload, NuxtSSRContext } from '#app'
|
||||
// @ts-expect-error virtual file
|
||||
import { appHead, appRootId, appRootTag, appTeleportId, appTeleportTag } from '#internal/nuxt.config.mjs'
|
||||
import { appHead, appRootId, appRootTag, appTeleportId, appTeleportTag, componentIslands } from '#internal/nuxt.config.mjs'
|
||||
// @ts-expect-error virtual file
|
||||
import { buildAssetsURL, publicAssetsURL } from '#paths'
|
||||
|
||||
@ -263,7 +263,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
||||
}
|
||||
|
||||
// Check for island component rendering
|
||||
const isRenderingIsland = (process.env.NUXT_COMPONENT_ISLANDS as unknown as boolean && event.path.startsWith('/__nuxt_island'))
|
||||
const isRenderingIsland = (componentIslands as unknown as boolean && event.path.startsWith('/__nuxt_island'))
|
||||
const islandContext = isRenderingIsland ? await getIslandContext(event) : undefined
|
||||
|
||||
if (import.meta.prerender && islandContext && event.path && await islandCache!.hasItem(event.path)) {
|
||||
@ -468,7 +468,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
||||
bodyAttrs: bodyAttrs ? [bodyAttrs] : [],
|
||||
bodyPrepend: normalizeChunks([bodyTagsOpen, ssrContext.teleports?.body]),
|
||||
body: [
|
||||
process.env.NUXT_COMPONENT_ISLANDS ? replaceIslandTeleports(ssrContext, _rendered.html) : _rendered.html,
|
||||
componentIslands ? replaceIslandTeleports(ssrContext, _rendered.html) : _rendered.html,
|
||||
APP_TELEPORT_OPEN_TAG + (HAS_APP_TELEPORTS ? joinTags([ssrContext.teleports?.[`#${appTeleportId}`]]) : '') + APP_TELEPORT_CLOSE_TAG
|
||||
],
|
||||
bodyAppend: [bodyTags]
|
||||
|
@ -374,10 +374,13 @@ export const nuxtConfigTemplate: NuxtTemplate = {
|
||||
baseURL: undefined,
|
||||
headers: undefined
|
||||
}
|
||||
const shouldEnableComponentIslands = ctx.nuxt.options.experimental.componentIslands && (
|
||||
ctx.nuxt.options.dev || ctx.nuxt.options.experimental.componentIslands !== 'auto' || ctx.app.pages?.some(p => p.mode === 'server') || ctx.app.components?.some(c => c.mode === 'server')
|
||||
)
|
||||
return [
|
||||
...Object.entries(ctx.nuxt.options.app).map(([k, v]) => `export const ${camelCase('app-' + k)} = ${JSON.stringify(v)}`),
|
||||
`export const renderJsonPayloads = ${!!ctx.nuxt.options.experimental.renderJsonPayloads}`,
|
||||
`export const componentIslands = ${!!ctx.nuxt.options.experimental.componentIslands}`,
|
||||
`export const componentIslands = ${shouldEnableComponentIslands}`,
|
||||
`export const payloadExtraction = ${!!ctx.nuxt.options.experimental.payloadExtraction}`,
|
||||
`export const cookieStore = ${!!ctx.nuxt.options.experimental.cookieStore}`,
|
||||
`export const appManifest = ${!!ctx.nuxt.options.experimental.appManifest}`,
|
||||
|
@ -79,6 +79,10 @@ export default defineNuxtModule({
|
||||
nuxt.hook('app:templates', async (app) => {
|
||||
app.pages = await resolvePagesRoutes()
|
||||
await nuxt.callHook('pages:extend', app.pages)
|
||||
|
||||
if (!nuxt.options.ssr && app.pages.some(p => p.mode === 'server')) {
|
||||
logger.warn('Using server pages with `ssr: false` is not supported with auto-detected component islands. Set `experimental.componentIslands` to `true`.')
|
||||
}
|
||||
})
|
||||
|
||||
// Restart Nuxt when pages dir is added or removed
|
||||
|
@ -172,7 +172,10 @@ export default defineUntypedSchema({
|
||||
|
||||
/**
|
||||
* Experimental component islands support with <NuxtIsland> and .island.vue files.
|
||||
* @type {true | 'local' | 'local+remote' | Partial<{ remoteIsland: boolean, selectiveClient: boolean }> | false}
|
||||
*
|
||||
* By default it is set to 'auto', which means it will be enabled only when there are islands,
|
||||
* server components or server pages in your app.
|
||||
* @type {true | 'auto' | 'local' | 'local+remote' | Partial<{ remoteIsland: boolean, selectiveClient: boolean }> | false}
|
||||
*/
|
||||
componentIslands: {
|
||||
$resolve: (val) => {
|
||||
@ -182,7 +185,7 @@ export default defineUntypedSchema({
|
||||
if (val === 'local') {
|
||||
return true
|
||||
}
|
||||
return val ?? false
|
||||
return val ?? 'auto'
|
||||
}
|
||||
},
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user