feat(nuxt): add prerenderRoutes ssr composable (#22863)

This commit is contained in:
Daniel Roe 2023-09-28 11:54:22 +01:00 committed by GitHub
parent 4b5e6ff195
commit a06d5247ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 37 additions and 9 deletions

View File

@ -0,0 +1,20 @@
---
description: prerenderRoutes hints to Nitro to prerender an additional route.
---
# `prerenderRoutes`
When prerendering, you can hint to Nitro to prerender additional paths, even if their URLs do not show up in the HTML of the generated page.
`prerenderRoutes` can only be called within component setup functions, plugins, and route middleware.
```js
const route = useRoute()
prerenderRoutes('/')
prerenderRoutes(['/', '/about'])
```
::alert{icon=👉}
In the browser, or if called outside prerendering, `prerenderRoutes` will have no effect.
::

View File

@ -88,7 +88,7 @@ description: Nuxt Kit provides composable utilities to help interacting with Nux
- `addDevServerHandler (handler)` - `addDevServerHandler (handler)`
- `useNitro()` (only usable after `ready` hook) - `useNitro()` (only usable after `ready` hook)
- `addServerPlugin` - `addServerPlugin`
- `addPrerenderRoutes` - `prerenderRoutes`
### Resolving ### Resolving

View File

@ -45,7 +45,7 @@ export function addServerPlugin (plugin: string) {
/** /**
* Adds routes to be prerendered * Adds routes to be prerendered
*/ */
export function addPrerenderRoutes (routes: string | string[]) { export function prerenderRoutes (routes: string | string[]) {
const nuxt = useNuxt() const nuxt = useNuxt()
if (!Array.isArray(routes)) { if (!Array.isArray(routes)) {
routes = [routes] routes = [routes]

View File

@ -11,7 +11,7 @@ import type { FetchResponse } from 'ofetch'
import type { NuxtIslandResponse } from '../../core/runtime/nitro/renderer' import type { NuxtIslandResponse } from '../../core/runtime/nitro/renderer'
import { getFragmentHTML, getSlotProps } from './utils' import { getFragmentHTML, getSlotProps } from './utils'
import { useNuxtApp, useRuntimeConfig } from '#app/nuxt' import { useNuxtApp, useRuntimeConfig } from '#app/nuxt'
import { useRequestEvent } from '#app/composables/ssr' import { prerenderRoutes, useRequestEvent } from '#app/composables/ssr'
// @ts-expect-error virtual file // @ts-expect-error virtual file
import { remoteComponentIslands } from '#build/nuxt.config.mjs' import { remoteComponentIslands } from '#build/nuxt.config.mjs'
@ -127,7 +127,7 @@ export default defineComponent({
if (import.meta.server && import.meta.prerender) { if (import.meta.server && import.meta.prerender) {
const hints = r.headers.get('x-nitro-prerender') const hints = r.headers.get('x-nitro-prerender')
if (hints) { if (hints) {
appendResponseHeader(event, 'x-nitro-prerender', hints) prerenderRoutes(hints)
} }
} }
setPayload(key, result) setPayload(key, result)

View File

@ -23,7 +23,7 @@ export { useFetch, useLazyFetch } from './fetch'
export type { FetchResult, UseFetchOptions } from './fetch' export type { FetchResult, UseFetchOptions } from './fetch'
export { useCookie } from './cookie' export { useCookie } from './cookie'
export type { CookieOptions, CookieRef } from './cookie' export type { CookieOptions, CookieRef } from './cookie'
export { useRequestHeaders, useRequestEvent, useRequestFetch, setResponseStatus } from './ssr' export { prerenderRoutes, useRequestHeaders, useRequestEvent, useRequestFetch, setResponseStatus } from './ssr'
export { onNuxtReady } from './ready' export { onNuxtReady } from './ready'
export { abortNavigation, addRouteMiddleware, defineNuxtRouteMiddleware, onBeforeRouteLeave, onBeforeRouteUpdate, setPageLayout, navigateTo, useRoute, useRouter } from './router' export { abortNavigation, addRouteMiddleware, defineNuxtRouteMiddleware, onBeforeRouteLeave, onBeforeRouteUpdate, setPageLayout, navigateTo, useRoute, useRouter } from './router'
export type { AddRouteMiddlewareOptions, RouteMiddleware } from './router' export type { AddRouteMiddlewareOptions, RouteMiddleware } from './router'

View File

@ -1,5 +1,5 @@
import type { H3Event } from 'h3' import type { H3Event } from 'h3'
import { setResponseStatus as _setResponseStatus, getRequestHeaders } from 'h3' import { setResponseStatus as _setResponseStatus, appendHeader, getRequestHeaders } from 'h3'
import type { NuxtApp } from '../nuxt' import type { NuxtApp } from '../nuxt'
import { useNuxtApp } from '../nuxt' import { useNuxtApp } from '../nuxt'
@ -35,3 +35,10 @@ export function setResponseStatus (arg1: H3Event | number | undefined, arg2?: nu
} }
return _setResponseStatus(useRequestEvent(), arg1, arg2 as string | undefined) return _setResponseStatus(useRequestEvent(), arg1, arg2 as string | undefined)
} }
export function prerenderRoutes (path: string | string[]) {
if (!process.server || !process.env.prerender) { return }
const paths = Array.isArray(path) ? path : [path]
appendHeader(useRequestEvent(), 'x-nitro-prerender', paths.map(p => encodeURIComponent(p)).join(', '))
}

View File

@ -37,6 +37,7 @@ const appPreset = defineUnimportPreset({
'useRequestURL', 'useRequestURL',
'setResponseStatus', 'setResponseStatus',
'setPageLayout', 'setPageLayout',
'prerenderRoutes',
'onNuxtReady', 'onNuxtReady',
'useRouter', 'useRouter',
'useRoute', 'useRoute',

View File

@ -1,7 +1,5 @@
<script setup> <script setup>
import { appendResponseHeader } from 'h3' prerenderRoutes(['/some/url/from/server-only/component'])
appendResponseHeader(useRequestEvent(), 'x-nitro-prerender', '/some/url/from/server-only/component')
</script> </script>
<template> <template>

View File

@ -47,6 +47,7 @@ describe('composables', () => {
'getRouteRules', 'getRouteRules',
'onNuxtReady', 'onNuxtReady',
'setResponseStatus', 'setResponseStatus',
'prerenderRoutes',
'useRequestEvent', 'useRequestEvent',
'useRequestFetch', 'useRequestFetch',
'isPrerendered', 'isPrerendered',
@ -200,6 +201,7 @@ describe('ssr composables', () => {
expect(useRequestEvent()).toBeUndefined() expect(useRequestEvent()).toBeUndefined()
expect(useRequestFetch()).toEqual($fetch) expect(useRequestFetch()).toEqual($fetch)
expect(useRequestHeaders()).toEqual({}) expect(useRequestHeaders()).toEqual({})
expect(prerenderRoutes('/')).toBeUndefined()
}) })
}) })