1
1
/* eslint-disable @typescript-eslint/require-await */
2
- import { FastifyInstance } from 'fastify'
2
+ import { FastifyInstance , FastifyReply } from 'fastify'
3
3
import 'fastify-accepts'
4
4
import fp from 'fastify-plugin'
5
5
import fastifyStatic from 'fastify-static'
@@ -16,8 +16,8 @@ import {
16
16
ViteDevServer ,
17
17
} from 'vite'
18
18
import { DefaultDocumentTemplate } from './DocumentTemplate'
19
- import { FastifyRendererOptions , FastifyRendererPlugin } from './Plugin'
20
- import { PartialRenderOptions , Render , RenderableRoute , RenderOptions } from './renderers/Renderer'
19
+ import { FastifyRendererOptions , FastifyRendererPlugin , ImperativeRenderable } from './Plugin'
20
+ import { PartialRenderOptions , Render , RenderableRegistration , RenderOptions } from './renderers/Renderer'
21
21
import { kRendererPlugin , kRendererViteOptions , kRenderOptions } from './symbols'
22
22
import { wrap } from './tracing'
23
23
import './types' // necessary to make sure that the fastify types are augmented
@@ -75,35 +75,63 @@ const FastifyRenderer = fp<FastifyRendererOptions>(
75
75
document : incomingOptions . document || DefaultDocumentTemplate ,
76
76
} )
77
77
78
+ fastify . decorate ( 'registerRenderable' , function ( this : FastifyInstance , renderable : string ) {
79
+ const renderableRoute : RenderableRegistration = { ...this [ kRenderOptions ] , renderable }
80
+ return plugin . register ( renderableRoute )
81
+ } )
82
+
83
+ const render = async ( reply : FastifyReply , renderableRoute : RenderableRegistration , props : any ) => {
84
+ if ( reply . sent ) return
85
+
86
+ void reply . header ( 'Vary' , 'Accept' )
87
+ switch ( reply . request . accepts ( ) . type ( [ 'html' , 'json' ] ) ) {
88
+ case 'json' :
89
+ await reply . type ( 'application/json' ) . send ( { props } )
90
+ break
91
+ case 'html' :
92
+ void reply . type ( 'text/html' )
93
+ const render : Render < typeof props > = { ...renderableRoute , request : reply . request , reply, props }
94
+ await plugin . renderer . render ( render )
95
+ break
96
+ default :
97
+ await reply . type ( 'text/plain' ) . send ( 'Content type not supported' )
98
+ break
99
+ }
100
+ }
101
+
102
+ fastify . decorateReply ( 'render' , async function ( this : FastifyReply , token : ImperativeRenderable , props : any ) {
103
+ if ( ! plugin . registeredComponents [ token ] ) {
104
+ throw new Error ( `No registered renderable was found for the provided token= ${ token . toString ( ) } ` )
105
+ }
106
+ const request = this . request
107
+ const renderableRoute : RenderableRegistration = {
108
+ ...this . server [ kRenderOptions ] ,
109
+ pathPattern : request . url ,
110
+ renderable : plugin . registeredComponents [ token ] . renderable ,
111
+ isImperative : true ,
112
+ }
113
+
114
+ await render ( this , renderableRoute , props )
115
+ } )
116
+
78
117
// Wrap routes that have the `render` option set to invoke the rendererer with the result of the route handler as the props
79
118
fastify . addHook ( 'onRoute' , function ( this : FastifyInstance , routeOptions ) {
80
119
if ( routeOptions . render ) {
81
120
const oldHandler = wrap ( 'fastify-renderer.getProps' , routeOptions . handler as ServerRenderer < any > )
82
121
const renderable = routeOptions . render
83
122
const plugin = this [ kRendererPlugin ]
84
- const renderableRoute : RenderableRoute = { ...this [ kRenderOptions ] , url : routeOptions . url , renderable }
123
+ const renderableRoute : RenderableRegistration = {
124
+ ...this [ kRenderOptions ] ,
125
+ pathPattern : routeOptions . url ,
126
+ renderable,
127
+ }
85
128
86
- plugin . registerRoute ( renderableRoute )
129
+ plugin . register ( renderableRoute )
87
130
88
131
routeOptions . handler = wrap ( 'fastify-renderer.handler' , async function ( this : FastifyInstance , request , reply ) {
89
132
const props = await oldHandler . call ( this , request , reply )
90
133
91
- if ( ! reply . sent ) {
92
- void reply . header ( 'Vary' , 'Accept' )
93
- switch ( request . accepts ( ) . type ( [ 'html' , 'json' ] ) ) {
94
- case 'json' :
95
- await reply . type ( 'application/json' ) . send ( { props } )
96
- break
97
- case 'html' :
98
- void reply . type ( 'text/html' )
99
- const render : Render < typeof props > = { ...renderableRoute , request, reply, props, renderable }
100
- await plugin . renderer . render ( render )
101
- break
102
- default :
103
- await reply . type ( 'text/plain' ) . send ( 'Content type not supported' )
104
- break
105
- }
106
- }
134
+ await render ( reply , renderableRoute , props )
107
135
} )
108
136
}
109
137
} )
@@ -162,7 +190,7 @@ const FastifyRenderer = fp<FastifyRendererOptions>(
162
190
config = await resolveConfig ( fastify [ kRendererViteOptions ] , 'serve' )
163
191
}
164
192
165
- await plugin . renderer . prepare ( plugin . routes , config , devServer )
193
+ await plugin . renderer . prepare ( plugin . renderables , config , devServer )
166
194
} )
167
195
168
196
fastify . addHook ( 'onClose' , async ( ) => {
@@ -178,7 +206,6 @@ const FastifyRenderer = fp<FastifyRendererOptions>(
178
206
179
207
module . exports = exports = FastifyRenderer
180
208
export default FastifyRenderer
181
-
182
209
export const build = async ( fastify : FastifyInstance ) => {
183
210
const plugin = fastify [ kRendererPlugin ]
184
211
if ( ! plugin ) {
@@ -189,7 +216,7 @@ export const build = async (fastify: FastifyInstance) => {
189
216
190
217
const clientEntrypoints : Record < string , string > = { }
191
218
const serverEntrypoints : Record < string , string > = { }
192
- for ( const renderableRoute of plugin . routes ) {
219
+ for ( const renderableRoute of plugin . renderables ) {
193
220
const entrypointName = mapFilepathToEntrypointName ( renderableRoute . renderable , renderableRoute . base )
194
221
clientEntrypoints [ entrypointName ] = plugin . renderer . buildVirtualClientEntrypointModuleID ( renderableRoute )
195
222
serverEntrypoints [ entrypointName ] = plugin . renderer . buildVirtualServerEntrypointModuleID ( renderableRoute )
@@ -239,3 +266,5 @@ export const build = async (fastify: FastifyInstance) => {
239
266
JSON . stringify ( virtualModulesToRenderedEntrypoints , null , 2 )
240
267
)
241
268
}
269
+
270
+ Object . assign ( FastifyRenderer , { build } )
0 commit comments